Developing Ensemble Productions Version 2009.1 30 June 2009 InterSystems Corporation 1 Memorial Drive Cambridge MA 02142 www.intersystems.com
Developing Ensemble Productions Ensemble Version 2009.1 30 June 2009 Copyright 2009 InterSystems Corporation All rights reserved. This book was assembled and formatted in Adobe Page Description Format (PDF) using tools and information from the following sources: Sun Microsystems, RenderX, Inc., Adobe Systems, and the World Wide Web Consortium at www.w3c.org. The primary document development tools were special-purpose XML-processing applications built by InterSystems using Caché and Java. and Caché WEBLINK, Distributed Cache Protocol, M/SQL, M/NET, and M/PACT are registered trademarks of InterSystems Corporation.,, and InterSystems Jalapeño Technology, Enterprise Cache Protocol, ECP, and InterSystems Zen are trademarks of InterSystems Corporation. All other brand or product names used herein are trademarks or registered trademarks of their respective companies or organizations. This document contains trade secret and confidential information which is the property of InterSystems Corporation, One Memorial Drive, Cambridge, MA 02142, or its affiliates, and is furnished for the sole purpose of the operation and maintenance of the products of InterSystems Corporation. No part of this publication is to be used for any other purpose, and this publication is not to be reproduced, copied, disclosed, transmitted, stored in a retrieval system or translated into any human or computer language, in any form, by any means, in whole or in part, without the express prior written consent of InterSystems Corporation. The copying, use and disposition of this document and the software programs described herein is prohibited except to the limited extent set forth in the standard software license agreement(s) of InterSystems Corporation covering such programs and related documentation. InterSystems Corporation makes no representations and warranties concerning such software programs other than those set forth in such standard software license agreement(s). In addition, the liability of InterSystems Corporation for any losses or damages relating to or arising out of the use of such software programs is limited in the manner set forth in such standard software license agreement(s). THE FOREGOING IS A GENERAL SUMMARY OF THE RESTRICTIONS AND LIMITATIONS IMPOSED BY INTERSYSTEMS CORPORATION ON THE USE OF, AND LIABILITY ARISING FROM, ITS COMPUTER SOFTWARE. FOR COMPLETE INFORMATION REFERENCE SHOULD BE MADE TO THE STANDARD SOFTWARE LICENSE AGREEMENT(S) OF INTERSYSTEMS CORPORATION, COPIES OF WHICH WILL BE MADE AVAILABLE UPON REQUEST. InterSystems Corporation disclaims responsibility for errors which may appear in this document, and it reserves the right, in its sole discretion and without notice, to make substitutions and modifications in the products and practices described in this document. For Support questions about any InterSystems products, contact: InterSystems Worldwide Customer Support Tel: +1 617 621-0700 Fax: +1 617 374-9391 Email: support@intersystems.com
Table of Contents About This Book... 1 1 Production Concepts... 3 1.1 Requests and Responses... 6 1.2 External Interfaces... 6 1.3 Namespaces... 7 1.4 Host Classes... 7 1.5 Configuration Settings... 8 1.6 Startup... 9 1.7 Shutdown... 10 1.8 Production States... 10 1.9 Production Life Cycle... 11 1.9.1 Ensemble Auto-start Settings... 12 1.9.2 Using the Portal to Start and Stop a Production... 12 1.9.3 OnStart and OnProductionStart... 13 1.9.4 Ens.Director... 14 1.10 Jobs... 15 1.11 Pool Size... 15 1.11.1 Private Pool Size for Business Hosts... 16 1.11.2 Actor Pool Size for Productions... 16 1.11.3 First-In First-Out (FIFO) for Health Care... 16 1.11.4 Considerations and Trade-offs... 17 1.12 Events... 17 1.13 Scheduler... 18 1.14 Business Logic... 18 2 Creating a New Production... 21 2.1 Using the Production Model... 21 2.2 Using the New Production Wizard... 25 2.3 Configuration Settings... 27 2.3.1 How Class Code Determines the Available Settings... 28 2.3.2 How a User Configures Production Settings... 29 2.3.3 How a Production Stores the Values of its Settings... 31 2.3.4 Accessing Production Settings Programmatically... 32 2.4 Username and Password Credentials... 34 2.4.1 Credentials on the Configuration Page... 35 2.4.2 Credentials in a Class Definition... 35 2.4.3 Overriding the Configured Credentials... 36 Developing Ensemble Productions iii
2.5 Log, Alert, and Trace... 36 2.5.1 Logging... 37 2.5.2 Trace Messages... 38 2.5.3 Alerts... 41 2.5.4 Alarms... 43 2.6 Utility Functions... 43 2.6.1 Built-in Functions... 43 2.6.2 Function Syntax... 47 2.6.3 User-defined Functions... 48 2.6.4 Lookup Tables... 50 2.7 Time Stamps in Filenames... 52 2.8 Testing and Debugging... 57 2.8.1 Testing from the Ensemble Management Portal... 58 2.8.2 Debugging Production Code... 58 2.8.3 Automatic Error Trapping... 59 2.8.4 Handling Error Codes... 60 2.8.5 Stopping a Suspended Production... 61 2.9 Documentation and Comments... 62 2.9.1 Online Documentation... 62 2.9.2 Class Reference Information... 63 2.9.3 Hover Text For Production Settings... 64 2.9.4 ObjectScript Code Comments... 65 2.9.5 Caché Basic Code Comments... 65 2.9.6 Annotations in BPL and DTL... 66 2.9.7 Extended Code Comments in BPL and DTL... 67 2.10 Ensemble Studio... 68 2.10.1 Starting Studio... 68 2.10.2 The New Class Window... 69 2.10.3 The Workspace Window... 69 2.10.4 Starting the Management Portal from Studio... 71 3 Ensemble Messages... 73 3.1 Message Body... 75 3.2 Synchronous and Asynchronous Messages... 75 3.3 Deferred Response... 76 3.4 Primary Requests and Responses... 78 3.5 Sessions... 79 3.6 Queues... 79 3.7 Message Header... 80 3.8 Creating a Standard Message Body Class... 82 4 Inbound Adapters... 85 iv Developing Ensemble Productions
4.1 Inbound Adapter Life Cycle... 87 4.2 Inbound Adapter Methods... 88 4.2.1 The OnInit Method... 88 4.2.2 The OnTearDown Method... 88 4.2.3 The OnTask Method... 89 4.3 Creating a New Inbound Adapter Class... 90 5 Business Services... 93 5.1 Business Service Life Cycle... 96 5.2 Business Service Methods... 98 5.2.1 The OnInit Method... 98 5.2.2 The OnTearDown Method... 99 5.2.3 The OnProductionStart Method... 99 5.2.4 The OnProductionStop Method... 99 5.2.5 The OnProcessInput Method... 99 5.2.6 The SendRequestSync Method... 100 5.2.7 The SendRequestAsync Method... 100 5.2.8 The SendDeferredResponse Method... 101 5.2.9 The OnGetConnections Method... 102 5.3 Business Service Properties... 102 5.4 Creating a New Business Service Class... 103 5.5 Adding a Business Service to a Production... 104 5.6 Invoking a Business Service Directly... 105 6 Business Processes... 107 6.1 Business Process Life Cycle... 109 6.2 Business Process Methods... 110 6.2.1 The OnRequest Method... 110 6.2.2 The OnResponse Method... 111 6.2.3 The SendRequestSync Method... 112 6.2.4 The SendRequestAsync Method... 112 6.2.5 The SendDeferredResponse Method... 113 6.2.6 The SetTimer Method... 113 6.2.7 The IsComponent Method... 114 6.3 Creating a New Business Process Class... 114 6.3.1 Creating a New BPL Business Process Class... 114 6.3.2 Creating a New Custom Business Process Class... 116 6.3.3 Providing Settings in a Business Process Class... 117 6.3.4 Business Process Components... 117 6.4 Adding a Business Process to a Production... 118 6.5 Business Process Execution Context... 120 6.5.1 The context Object... 121 Developing Ensemble Productions v
6.5.2 The request Object... 122 6.5.3 The response Object... 122 6.5.4 The callrequest Object... 122 6.5.5 The callresponse Object... 123 6.5.6 The syncresponses Collection... 123 6.5.7 The synctimedout Value... 124 6.5.8 The status Value... 124 6.5.9 The process Object... 125 6.6 Using the BPL Visual Editor... 125 6.6.1 BPL Diagram Shapes... 127 6.6.2 BPL Diagram Connections... 131 6.6.3 BPL Diagram Layout... 133 6.6.4 BPL Diagram Context Menu... 134 6.6.5 Using the Call Wizard... 136 6.6.6 Drilling Down in a BPL Diagram... 137 6.6.7 BPL Visual Editor Toolbar... 139 6.6.8 The Inspector Window... 142 6.6.9 Import and Export of BPL Diagrams... 142 6.7 BPL Business Process Example... 142 7 Business Operations... 145 7.1 Business Operation Life Cycle... 147 7.2 Business Operation Methods... 149 7.2.1 The OnInit Method... 150 7.2.2 The OnTearDown Method... 150 7.2.3 The OnProductionStart Method... 150 7.2.4 The OnProductionStop Method... 150 7.2.5 The SendRequestSync Method... 151 7.2.6 The SendRequestAsync Method... 151 7.2.7 Deferred Response Methods... 152 7.3 Business Operation Properties... 152 7.4 Suspending Messages... 153 7.5 Message Maps... 154 7.6 Creating a New Business Operation Class... 155 7.7 Adding a Business Operation to a Production... 157 8 Outbound Adapters... 159 8.1 Outbound Adapter Life Cycle... 160 8.2 Outbound Adapter Methods... 161 8.2.1 The OnInit Method... 161 8.2.2 The OnTearDown Method... 161 8.3 Creating a New Outbound Adapter Class... 162 vi Developing Ensemble Productions
9 Production Data... 165 9.1 Data Transformations... 166 9.1.1 Data Transformation Classes... 168 9.1.2 Creating a New Data Transformation... 168 9.1.3 DTL Data Transformation Examples... 169 9.2 Using the DTL Visual Editor... 170 9.2.1 Synchronizing Graphics and Code... 171 9.2.2 DTL Diagram Column Headers... 172 9.2.3 Using the Inspector Window... 172 9.2.4 DTL Diagram Context Menu... 173 9.2.5 Alternate Views of DTL Code... 174 9.2.6 Assigning Values from Source to Target... 175 9.2.7 Assigning a Literal Value to a Target... 176 9.2.8 Editing Expressions for Assign Statements... 177 9.2.9 Working with Nested Properties... 179 9.2.10 Assigning All Nested Properties... 179 9.2.11 Building an If Statement... 181 9.2.12 Building a Foreach Statement... 182 9.2.13 Editing the DTL Code... 183 9.2.14 Testing the DTL Data Transformation... 184 9.2.15 Import and Export of DTL Diagrams... 185 9.3 Federated Databases... 185 9.4 Data Persistence and Data Recovery... 186 10 Business Logic... 189 10.1 Business Rules... 189 10.2 Business Activity Monitoring... 190 10.3 Workflow... 191 11 Message Routing... 193 11.1 Message Routing Engine... 194 11.2 Publish and Subscribe... 195 11.2.1 Publish and Subscribe Model... 195 11.2.2 Publish and Subscribe Implementation... 197 11.2.3 Publish and Subscribe at Runtime... 198 11.2.4 Configuring Publish and Subscribe... 198 Index... 201 Developing Ensemble Productions vii
List of Figures Overview of an Ensemble Production... 4 Example of Settings on the Configuration Page... 30 BPL <call> Element Showing <annotation> Text... 66 Ensemble Message Object with a Standard Message Body... 74 Typical Request and Response... 77 Request and Deferred Response... 78 How a Production Accepts Incoming Requests... 86 How a Production Relays Incoming Requests... 94 How a Production Orchestrates Incoming Requests... 108 Example of a BPL Diagram... 126 BPL Diagram with Join Selected, Related <if> Highlighted... 131 A New Shape Added to a BPL Diagram... 132 Connection Labels in a Switch Element... 133 Auto-Arranged Shapes in a BPL Diagram... 134 Example of a BPL Loop... 137 Example of a BPL Loop, Drilled Down... 138 Example of a BPL Sequence... 139 Example of a BPL Sequence, Drilled Down... 139 BPL Toolbar... 140 How a Production Fulfills Incoming Requests... 146 How a Production Relays Outgoing Requests... 159 The Data Transformation Utility Object... 167 DTL Visual Editor, Diagram and Code View... 171 DTL Visual Editor with Inspector Window... 173 DTL Visual Editor, Class Code View... 174 DTL Visual Editor, Generated Code View... 175 Connector from Source to Target... 176 Connector from Literal Value to Property in Target... 177 DTL Visual Editor <assign> Wizard... 177 Connector from Source to Parent Property in Target... 179 Connector from Source to Nested Property in Target... 179 Connector Between Two Identical Parent Properties... 180 DTL Visual Editor <if> Wizard... 181 Connector from Source Property to If Statement... 181 DTL Visual Editor <foreach> Wizard... 182 Connector from Source Property to Foreach Statement... 183 DTL Transformation Test Window... 184 viii Developing Ensemble Productions
How a Production Relays Requests via a Federated Database... 186 Developing Ensemble Productions ix
List of Tables Production States... 11 Utility Functions for Business Rules and DTL Data Transformations... 44 Examples of Valid Expressions using Functions... 47 Time Stamp Symbols for Input and Output Filenames... 53 Time Stamp Symbols Different from POSIX, IEEE, and ISO Standards... 57 BPL Diagram Shapes... 128 BPL Diagram Icons... 129 Icons that Add Activities to a BPL Diagram... 140 Icons that Add Loops to a BPL Diagram... 141 Icons that Add Logic to a BPL Diagram... 141 Business Operation Properties... 153 Classes for Publish and Subscribe Messaging... 197 CSP Pages for Publish and Subscribe Messaging... 199 x Developing Ensemble Productions
About This Book This book explains how to plan, develop, and test enterprise integration solutions using Ensemble. InterSystems Ensemble shares many underlying core technologies with InterSystems Caché. This book refers you to books in both documentation sets. This book contains the following chapters: Production Concepts outlines the architecture and life cycle of an Ensemble production. Creating a New Production introduces Ensemble development tools and procedures. Ensemble Messages explains the essential unit of exchange within an Ensemble production. Inbound Adapters shows how a production receives and validates requests from external systems. Business Services shows how a production directs incoming requests for fulfillment. Business Processes explains the essential core of activity within an Ensemble production. Business Operations shows how a production represents an external system as a resource. Outbound Adapters shows how a production constructs and sends requests to external systems. Production Data explains data transformation, abstraction, and persistence. Business Logic includes rule-based decisions, dashboards, and human-computer workflow. Message Routing shows how to develop a production as a fast, reliable message routing engine. There is also a detailed Table of Contents. The following books provide related information: Introducing Ensemble provides an overview of the Ensemble product, its purpose and features. Ensemble Release Notes describes the contents of this release of Ensemble. Ensemble Best Practices describes best practices for organizing and developing Ensemble productions. For general information, see Using InterSystems Documentation. Developing Ensemble Productions 1
1 Production Concepts An Ensemble production is a specialized package of software and documentation that solves a specific integration problem for an enterprise customer. The goal of any Ensemble development project is to deliver a production. This book explains how to generate the class code, XML, and custom software elements that comprise an Ensemble production. The following figure illustrates some of the software elements that an Ensemble production can contain. Within an Ensemble development project, the developers job is to create some of these elements, configure all of them to work together, and leave documentation and tools to ensure that the production can be managed by the enterprise system administration team. In addition to the elements that developers create, the Ensemble production infrastructure includes elements that support messaging, monitoring, persistence, management, tracking, recovery, caching, and storage. The diagram does not show these elements. It acknowledges them with arrows that connect the elements Inside Ensemble. The only requirement to take full advantage of these features is to use the Ensemble classes, tools, and wizards. The Ensemble development and management environments take care of these infrastructure details automatically. Developing Ensemble Productions 3
Production Concepts Overview of an Ensemble Production An Ensemble production typically processes incoming events in the following order, using the following elements. Alternative processing is possible, and some of these alternatives are indicated in the diagram, but this is the classic sequence: 1. An inbound adapter receives an incoming event, transforms it into an Ensemble message object, and passes it to its associated business service. 2. The business service formulates a follow-on request message, and passes this new message to a business process or business operation within Ensemble. 4 Developing Ensemble Productions
3. A business process that receives a request message executes a predefined set of activities, in sequence or in parallel. These activities may include sending follow-on requests to other business processes, to business rules, to data transformations, or to business operations. For example: Business rules change the behavior of business processes at decision points. Routing rules direct messages to their destinations based on message type, message contents, or where the message came from. Schema categories provide a means to validate and access message contents. Data transformations calculate and apply changes to message contents. Business operations map a request to functionality offered by an entity outside Ensemble. Business services, business processes, and business operations are all called business hosts. 4. A business operation encapsulates the capabilities of a resource outside Ensemble, usually an external software application. The business operation transforms properties of the Ensemble request message object into a format usable by the external application API. If the request requires human intervention, a workflow operation manages the interaction between person and computer. 5. An outbound adapter manages the details of communicating with a specific external system or application from within Ensemble. It transmits the API call to the external entity. 6. The response from the external system or application can trigger a cascade of response messages back to the external entity that instigated the flow of events. Details depend on the design choices made by the production developers, as later chapters in this book explain. The following sections further explain additional production concepts: Requests and Responses External Interfaces Namespaces Host Classes Configuration Settings Startup Shutdown Production States Production Life Cycle Jobs Pool Size Events Developing Ensemble Productions 5
Production Concepts Scheduler Business Logic 1.1 Requests and Responses The Ensemble Messages chapter explores message objects in detail. In the current chapter, it is important only to understand that: Every message is a request or a response. Requests and responses are defined in pairs. A request may have one associated response, or no associated response. Any request may be sent synchronously (the caller waits for the response before continuing) or asynchronously (the caller does not wait). The business host that sends the request must indicate this choice and handle the result. Any request that is sent synchronously must, in fact, have a designated response type. The flow of control described at the beginning of this chapter could vary considerably each time a request is sent, depending on a variety of factors including: - The type of request being sent. - Whether or not each request involves waiting (or not waiting) for a response. - Whether or not expected responses are actually received. - The values returned with any responses. 1.2 External Interfaces A traditional way to begin work on an Ensemble solution is to list all of the externally and internally callable interfaces within the planned solution. For example, in the diagram at the beginning of this chapter, all the solid arrows in the gray-shaded area are considered to be Outside Ensemble. Some of these arrows indicate a call into the Ensemble production, and some indicate a call out from the production. These arrows comprise a list of interfaces that is called the processing model for this production. Within the processing model for an Ensemble production, external applications that call into the production are known as client applications; these are shown at left in the diagram. External applications 6 Developing Ensemble Productions
Namespaces whose operations are called by elements inside the production are known as external applications; these are shown at right. Within the same production, the same application can serve as both client and external application. In this case, the distinction between the two roles depends on whether the application is initiating a request (client) or fulfilling a request (external). As with applications, calls from Ensemble out to external databases are possible as well. 1.3 Namespaces In InterSystems products, a namespace is a collection of data and programs in a virtual work space. InterSystems documentation provides a great deal of information about namespaces. Important: The Ensemble installation procedure creates several namespaces for internal use by the Ensemble engine: %SYS, DOCBOOK, USER, SAMPLES, ENSLIB, ENSEMBLE, and ENSDEMO. All system-provided namespaces except ENSEMBLE and USER are overwritten upon reinstallation or upgrade. For this reason, InterSystems recommends that you always create new namespaces in which to work, rather than placing custom code in any of these system-provided namespaces, where it could be overwritten and lost. This book frequently refers to something called an Ensemble namespace or an Ensemble-enabled namespace. This is a namespace that has the Ensemble classes loaded into it. Of the system-provided namespaces, only ENSLIB, ENSEMBLE, and ENSDEMO are Ensemble-enabled. Only ENSEMBLE is intended for your use; the other system-provided namespaces are reserved. Once you have successfully installed Ensemble, any new namespace that you create is automatically Ensemble-enabled. You can create a new namespace by using the System Management Portal [Home] > [Configuration] > [Namespaces] > [New Namespace] page. For instructions, see the Configuring Data section in the Configuring Caché chapter of the Caché System Administration Guide. 1.4 Host Classes An Ensemble host class consists of executable source code. Class developers use the Studio tool, the BPL Editor, or a text editor to create, view, edit, and compile host classes. Every host class extends Ens.Host, an Ensemble class that determines general characteristics for classes that operate as members of a production. Every host class is one of three types, all of which inherit from Ens.Host: Business service class Instances of the Ens.BusinessService class accept requests from entities outside Ensemble and relay them to host classes inside Ensemble for processing and fulfillment. Developing Ensemble Productions 7
Production Concepts A business service class corresponds to a single, well-defined action that an external entity needs to perform. This action enters an Ensemble production in the form of a request to the business service. The business service generates whatever activity is needed to satisfy this request. It invokes various lower-level host classes business processes and business operations and it controls the logic of these invocations. When all of its internal processing is complete, a business service formulates and returns a response to the outside entity s original request. Some requests do not require a response; if this is the case, none is returned. For details, see the Business Services chapter. Business process class Instances of the Ens.BusinessProcess class accept requests from host classes inside Ensemble business services or business processes and either process the requests or relay them to other host classes inside Ensemble for processing. A business process class corresponds to a single, well-defined business task that needs to be performed. The business process generates whatever activity is needed to complete this task. It invokes various lower-level host classes business processes or business operations and it controls the logic of these invocations. When all of its internal processing is complete, a business process formulates and returns a response to the original request, if a response is needed. Some requests do not require a response; if this is the case, none is returned. For details, see the Business Processes chapter. Business operation class Instances of the Ens.BusinessOperation class accept requests from host classes inside Ensemble business services or business processes and either process the requests or relay them to entities outside Ensemble for processing. A business operation class consists of one or more methods, each of which corresponds to a single, well-defined external or internal operation that needs to be performed, such as retrieving a specific piece of data or making a specific type of calculation. When its internal processing is complete, a business process formulates and returns a response to the original request, if a response is needed. Some requests do not require a response; if this is the case, none is returned. By convention, a business operation is an extremely specific operation that contains very little logic and does what is requested of it without calling further operations or branching in any way. When the design of the production demands logic, this is contained in a higher-level business process. For details, see the Business Operations chapter. 1.5 Configuration Settings You must compile and load a host class before you can add the corresponding business host business service, business process, or business operation to the production. Once you add the business host to the production, you can adjust its configurable settings using the configuration display on the [Ensemble] > [Productions] page. 8 Developing Ensemble Productions
For a description of the configurable settings that are built into the base classes for productions, business services, business processes, and business operations, see the lists and descriptions in the following sections of the Configuration chapter of Managing Ensemble Productions: Business Service Settings includes settings for inbound adapters Business Process Settings Business Operation Settings includes settings for outbound adapters Production Settings A host class determines how a configuration item can be configured, by publishing its configurable properties in a class parameter called SETTINGS. Any property listed in the SETTINGS parameter for a host class automatically appears in the configuration display on the [Ensemble] > [Productions] page, whenever you select an item of that host class for configuration. You can edit and save values on the [Ensemble] > [Productions] page without editing or recompiling the host class itself. Any changes you make are applied immediately, without requiring you to stop and restart a running production. The same is true of production-wide properties, which are defined in the production class and exposed for configuration by using the SETTINGS class parameter in the production class. For programming instructions regarding the SETTINGS parameter, see the Configuration Settings section in the Creating a New Production chapter. Startup 1.6 Startup This topic describes what happens when an Ensemble production starts up. The sequence is the same regardless of the mechanism used to start it. The Production Life Cycle section describes options for invoking this sequence. When a production starts, the sequence of actions is as follows: 1. The production class is instantiated; its optional OnStart method executes. 2. The production instantiates each business operation and executes its optional OnProductionStart method. 3. The production instantiates each business process and executes its optional OnProductionStart method. 4. The production clears the business metric cache of any metric values left over from a previous run. 5. The production instantiates each business service and executes its optional OnProductionStart method. Developing Ensemble Productions 9
Production Concepts 6. The production processes any items already placed in queues. This includes messages with Normal priority (asynchronous messages) that were queued when the production stopped. 7. The production now accepts input from outside Ensemble. 1.7 Shutdown This topic describes what happens when an Ensemble production shuts down. The sequence is the same regardless of the mechanism used to stop it. The Production Life Cycle section describes options for invoking this sequence. When a production stops, the sequence of actions is as follows: 1. The production takes each business service offline and executes its optional OnProductionStop method. This action stops all requests from outside Ensemble. 2. All business hosts receive a signal to become Quiescent. 3. All queues go into a Quiescent state. This means that from this point forward, business hosts can only process queued messages with High priority (synchronous messages). Messages with Normal priority (asynchronous messages) remain on their respective queues. 4. The production finishes processing all synchronous messages to the best of its ability. 5. The production takes each business process offline and executes its optional OnProductionStop method. 6. The production takes each business operation offline and executes its optional OnProductionStop method. 7. The production goes offline. Ensemble executes the optional OnStop method in the production class. 1.8 Production States During its life cycle, a production may enter any of the states listed in the following table. The corresponding status values are visible using the [Ensemble] home page or on the [Ensemble] > [Productions] page. 10 Developing Ensemble Productions
Production Life Cycle Production States State Running Stopped Suspended Troubled Meaning When a production has been started and is operating normally, it has a status of Running. This is an acceptable state. A production acquires a status of Stopped when, at the end of the shutdown sequence, all of its queues are free of synchronous messages. This is an acceptable state. A production acquires the Suspended status if, at the end of the shutdown sequence, some queues still contain synchronous messages, waiting for a response. Depending on how the production has been designed, this may or may not indicate a problem. You may start a Suspended production. Starting the production again may permit the waiting messages to be processed. However, if you start the Suspended production, and more messages arrive while those in front of them in the queue cannot be resolved, queues may simply continue to fill. In that case you must investigate to discover why the incoming messages never complete. You may stop a Suspended production. InterSystems advises you do so only during initial development and not on a deployed, live installation. For instructions, see the Stopping a Suspended Production section in the Creating a New Production chapter. A production acquires a status of Troubled if Ensemble is stopped but the production did not shut down properly. This can happen if you restarted Ensemble or rebooted the machine without first stopping the production. In this case you need to issue a command to recover the production. For instructions, see the next section, Production Life Cycle. 1.9 Production Life Cycle This topic introduces several ways to start or stop an Ensemble production. It also explains how these techniques fit within the larger context of starting or stopping the Ensemble server instance where the production runs. At server startup, the major pieces start up in the following order: 1. The Ensemble server instance starts up. The user startup routine runs automatically at this time, but InterSystems recommends you do not use the ^%ZSTART routine to control Ensemble production startup. The mechanisms that Developing Ensemble Productions 11
Production Concepts Ensemble provides to control startup are much easier to use and more closely tied to the production itself. See Ensemble Auto-start Settings for details. 2. At any subsequent time, you may start an Ensemble production. The Startup section, earlier in this chapter describes the full production startup sequence. Ensemble automatically runs the production class OnStart method and the OnProductionStart methods of the business host classes, if provided. These methods are the recommended locations for any special setup instructions that you want to provide for the production, or for individual business hosts, when Ensemble starts up. See OnStart and OnProductionStart for details. 1.9.1 Ensemble Auto-start Settings You can use the Ensemble Management Portal page to configure Ensemble so that a specific production starts automatically at system startup, and stops automatically at system shutdown. The setting for this is called Auto-Start Production. InterSystems recommends that you use this setting to configure live, deployed productions to start when the server starts up: 1. From the [Ensemble] home page click Maintenance on the Ensemble menu to display the [Ensemble] > [Maintenance] page. 2. In the Auto-Start Production list, choose the production name you want to automatically start when Ensemble starts. 3. To disable automatic production start, click the blank entry; this is the default. For debugging situations in a development environment, you can override the automatic start by disabling the EnsembleAutoStart configuration setting: 1. From the InterSystems Systems Management Portal [Home] page, click Configuration under the System Administration column. 2. Click Startup Settings under the Additional Settings column. 3. Click Edit next to the EnsembleAutoStart setting. 4. Clear the EnsembleAutoStart check box to disable the feature and click Save. When you restart Ensemble with this setting disabled, the productions you have set to automatically start at system startup do not start. 1.9.2 Using the Portal to Start and Stop a Production You can also use the Ensemble Management Portal to start or stop an Ensemble production manually, by selecting the production on the [Ensemble] > [Productions] page and clicking Start or Stop to the right of it. 12 Developing Ensemble Productions
While you are developing new production code, it sometimes happens that when you start the Ensemble Management Portal, Ensemble detects a discrepancy between the production as defined in the code, and the status of the running production. Examples would be if: A specific business host experienced an error and has died (the most likely cause). You changed a configuration parameter for a business host in a running production, such that the host now needs to be restarted. A production typically opens a Terminal window, but this window was closed by a user action while the production was still running. When discrepancies such as this arise, the Update Production command becomes available on the [Ensemble] home page. Click it, and Ensemble updates the production to resolve the discrepancy. Ensemble displays a confirmation message. Click OK to return to the [Ensemble] home page. For a deployed production, you can set up the production to update itself automatically. When you take this approach, Update Production never displays. To do this, add a production monitor service to the production. This is a business service with a Service Class of Ens.ProductionMonitorService. Configure the Call Interval setting to control how frequently, in seconds, the monitor service checks to see if there is a discrepancy between the production as defined in the code, and the status of the running production. Each time it finds such a discrepancy, the monitor service updates the production to resolve it. If a production has a status of Troubled due to some unexpected program error, a Recover command appears on the Ensemble Management Portal [Ensemble] home page. Click Recover to shut down and clean up the troubled instance of the production so that you can run a new instance when you are ready. 1.9.3 OnStart and OnProductionStart Production Life Cycle If you have code that must execute before a production starts up, but that requires the Ensemble framework to be running before it can execute, you must override the OnStart method in the production class. Place these code statements in OnStart so that they execute in the proper sequence: that is, after Ensemble has started, but before the production begins accepting requests. An OnStop method is also available to perform a set of tasks before the production finishes shutting down. Each business host business service, business process, or business operation is a subclass of Ens.Host. In any of these classes you may override the OnProductionStart method to provide code statements that you want Ensemble to execute on behalf of this host at production startup time. An OnProductionStop method is also available. Neither OnStart nor OnProductionStart are required, but they are available if you need them. Developing Ensemble Productions 13
Production Concepts 1.9.4 Ens.Director It is possible to start or stop a production at the Terminal command line or from an ObjectScript routine. You can do this by invoking the following methods in the Ens.Director class. These methods work only if the current namespace is an Ensemble namespace: StopProduction Stop the currently running production in an Ensemble namespace: StartProduction Do ##class(ens.director).stopproduction() Start the specified production in the Ensemble namespace, as long as no other production is running: Do ##class(ens.director).startproduction("myproduction") RecoverProduction Clean up a Troubled instance of a running production so that you can run a new instance in the Ensemble namespace: Do ##class(ens.director).recoverproduction() There is no need to call GetProductionStatus to see if the production terminated abnormally prior to calling RecoverProduction. If the production is not Troubled, the method simply returns. GetProductionStatus This method returns the production status via two output parameters, both of which are passed by reference. The first parameter returns the production name, but only when the status is Running, Suspended, or Troubled. The second parameter returns the production state, which is a numeric value equivalent to one of the following constants: $$$eproductionstaterunning $$$eproductionstatestopped $$$eproductionstatesuspended $$$eproductionstatetroubled The following is an example of how to use GetProductionStatus. 14 Developing Ensemble Productions
Jobs Set tsc=##class(ens.director).getproductionstatus(.tproductionname,.tstate) Quit:$$$ISERR(tSC) If tstate'=$$$eproductionstaterunning { $$$LOGINFO($$$Text("No Production is running.")) Quit } You can use the production state macros such as $$$eproductionstaterunning in code outside of the Ensemble classes, for example in a general class or routine. To do this, you must add the following statement to the class: #include Ensemble There is no need to do this inside Ensemble classes, such as in business hosts. If you browse the online class reference documentation for Ens.Director, you can see that it offers many class methods, including many intended for use only by the Ensemble internal framework. InterSystems recommends that you use only the Ens.Director methods documented in this book, and only as documented. For other recommended Ens.Director methods, see: Accessing Production Settings Programmatically in the Creating a New Production chapter Invoking a Business Service Directly in the Business Services chapter 1.10 Jobs Jobs are CPU processes that host the work done by an Ensemble production. This terminology is intended to avoid confusion between CPU processes ( jobs ) and business processes ( processes ). From a low-level, system viewpoint, an Ensemble production consists almost entirely of jobs waiting to wake up to perform work. When a request arrives on the queue of a business host, the item claims a job from its pool of available jobs. The job then hosts the work that needs to be done. If no job is available in the pool of jobs for that business host, it must wait for a job to become available, so that it can do the work. The job returns to the pool after the work is done, or whenever the next task is to wait for something to happen. A job always returns to the same pool it came from. 1.11 Pool Size The choice of Actor Pool Size for the production, and Pool Size for each business host, determines how many jobs are available to perform which types of work for the production. These numbers are an essential part of the production design and are unlikely to need adjustment once the production is deployed live. Larger numbers are not necessarily helpful; while the potential pool sizes actually range from 0 100, most pool sizes are best set to either 0 or 1, and there can be serious consequences when sizes are set to a number greater than 1. The following discussion provides details. Developing Ensemble Productions 15
Production Concepts 1.11.1 Private Pool Size for Business Hosts Each business service, business process, or business operation can have its own, private pool of allocated jobs. You can configure the size of this pool using the settings in the configuration display on the [Ensemble] > [Productions] page. The maximum setting for any one pool is 100 jobs. If, in testing your production, you find that you need more than 100 jobs per business host it probably indicates some other kind of problem, such as a bottleneck or deadlock that should be addressed. If it is a purely computational bottleneck then there is no point in having the pool size larger than the number of CPUs. 1.11.2 Actor Pool Size for Productions Unlike other types of business host, with business processes you have the option of sharing jobs from a public pool; this pool is called the actor pool. You can configure the Actor Pool Size for the production as a whole, using the configuration display on the [Ensemble] > [Productions] page. Actors in the production-wide actor pool have no affiliation with or knowledge of a specific business process. Any business process that has a private Pool Size of 0 can use jobs from the public actor pool. The choice as to whether or not a business process should use its own private pool or the public pool depends on the needs of the production. Any non-zero value for a private Pool Size ensures that the business process only uses jobs from its private pool. If you want any business process to use jobs from the actor pool, its private Pool Size must be 0. The default Ensemble configuration allows 1 job in the private pool for each business host, and 2 jobs in the production-wide actor pool. This means that if you want business processes to share the actor pool it does not happen automatically; you must set their individual Pool Size settings to 0. You must use a Pool Size of 0 for an adapterless business service. This is a business service that is invoked directly from outside Ensemble, rather than receiving its requests in the usual way, via an inbound adapter. An adapterless business service may be invoked via Caché Language Bindings, Caché Server Pages, SOAP, or a routine invoked from the operating system level. For details, see Invoking a Business Service Directly in the chapter Business Services. 1.11.3 First-In First-Out (FIFO) for Health Care A private Pool Size of 1 ensures first-in, first-out (FIFO) processing. If all the business hosts in the production have only one job available, only one message can be processed at a time by each host. This gives each message from a given source only one possible path through the production, so each message is guaranteed to arrive at its configured destination in the same order in which it was sent. Without guaranteed FIFO, a message from a particular source could skip over other messages from the same source by using a faster, parallel job to arrive at its destination sooner. FIFO is essential for health care applications. Suppose a patient enters a hospital and requires care. System A sends out an admit event, followed by a treatment order, but System B receives the order first. System B cannot process the order without an admit, so upon receiving the order, it produces an 16 Developing Ensemble Productions
error. This may delay patient care or require the information system to execute complex logic to associate admit with the order after the admit finally arrives at System B. For this reason, InterSystems recommends that every business service, business process, and business operation in a message routing production for health care has its Pool Size setting configured to 1, with the Actor Pool Size for the production at 0. 1.11.4 Considerations and Trade-offs Events In situations other than health care, private pools of a size 1 or greater can be useful for fast-running business processes in a production that also includes slow-running business processes. A fast-running business process can have a private pool to ensure that its requests never get stuck in the public actor queue behind accumulated requests for the slow-running business processes. If every business process in your production has a private pool, then the Actor Pool Size for the production can be 0. On the other hand, if your production includes many business processes that use the public actor pool, you can raise the Actor Pool Size for the production from the default of 2 to prevent bottlenecks when many business processes are running. InterSystems recommends that, as a maximum, you set the Actor Pool Size equal to the number of CPUs in your Ensemble server machine. You could set the number higher, but at any one time there are only as many jobs available as there are CPUs. 1.12 Events System events occur naturally throughout the life cycle of a production. They are generated and handled internally by Ensemble. Among the ways that system events are used is putting background processes (jobs) to sleep and waking them up. System events are also involved in notification of the arrival of messages on a queue; an event tells the queue owner that a message has arrived, so that the owner knows to take the message from the queue. You do not need a detailed knowledge of system events to develop an Ensemble production. System events are handled automatically by the Ensemble infrastructure. The truly important thing to remember is that system events are not the same as alerts, alarms, event log entries, or Ensemble messages. The Ensemble event log does not provide any information about system events. The event log collects certain types of text message generated by host classes. A developer or system administrator can view these event log entries from the Ensemble Management Portal [Ensemble] > [Event Log] page. Viewing the event log is a way to take the pulse of a production by scanning the informational text messages that it produces while it runs. Event log entries are stored persistently in the Ensemble database and may be purged according to age, as they accumulate. There are some automatic event log entries, such as the entries that acknowledge production startup or shutdown. These reflect normal occurrences in the life cycle of the production. Developing Ensemble Productions 17
Production Concepts However, most event log entries are present in the log because the developer of an Ensemble class decided that certain information would be of interest to a system administrator in case of a problem while the production is running. Important: For instructions, see the Log, Alert, and Trace section in the chapter Creating a New Production. 1.13 Scheduler The default scheduling for business hosts is for them to run whenever the production is running. However, a finer control is possible. Not only can you enable and disable business hosts, but the configuration display on the [Ensemble] > [Productions] page also offers a Schedule field for configuring each business host. This is an optional command string that schedules the host to be stopped and started at specific times and on specific days of the week, month, or year. When it is time to start, if the host is enabled it will be started; when it is time to stop, if the host is running it will be stopped. There are some limitations to scheduling abilities. For example, if a business host is started by the scheduler but cannot be stopped by the scheduler, this is because the host is in the middle of a synchronous call. The host must wait for a response to the call before it can be stopped. For details, see the Scheduling Configuration Items section in the What to Manage chapter of Managing Ensemble Productions. 1.14 Business Logic Ensemble offers several features that enable non-technical users to assess and direct the flow of application logic in order to meet business goals. The chapter Business Logic describes them: Business rules allow non-technical users to change the behavior of Ensemble business processes at specific decision points. The logic of the rule can be changed instantly, using a simple formsbased interface in the Ensemble Management Portal. There is no need for programming or diagramming skills to change the rule, and there is no need to modify or compile production code for changes to take effect. See Business Rules. Ensemble supports business activity monitoring (BAM) by enabling you to develop browserbased corporate dashboards that display graphical, real-time information about the production. Each dashboard is associated with a specific production, displays values from that production, and can be viewed live from the Ensemble Management Portal whenever that production is running. See Business Activity Monitoring. 18 Developing Ensemble Productions
Business Logic Workflow makes it possible to incorporate human interaction into automated business processes. Typical uses of workflow within the enterprise might include order entry, order fulfillment, contract approval, and help desk activities. A workflow management system automates the distribution of tasks among users. Distributing tasks automatically according to a predefined strategy makes task assignment more efficient and task execution more accountable. Ensemble has a built-in Workflow Engine that supports a variety of default and custom distribution strategies for tasks and users. See Workflow. Developing Ensemble Productions 19
2 Creating a New Production There are two ways to create a new Ensemble production. From the Ensemble Management Portal, using the Production Model From Ensemble Studio, using the New Production Wizard Ensemble provides many resources and tools to help you complete the new production: Configuration Settings Username and Password Credentials Log, Alert, and Trace Utility Functions Time Stamps in Filenames Testing and Debugging Documentation and Comments Ensemble Studio 2.1 Using the Production Model You can construct a new production from the Ensemble Management Portal as follows: 1. Choose your working namespace from the selection box at the top right of the [Ensemble] home page. 2. From the main menu choose Productions. The [Ensemble] > [Productions] page displays. Developing Ensemble Productions 21
Creating a New Production 3. Click Create New Production. The [Ensemble] > [Productions] > [Production Wizard] page displays. 4. Enter a Package Name, Production Name, and Description. 5. Choose one of the following: HL7 Messaging If you are using HL7 with Ensemble, choose this option. You can add any generic Ensemble elements that you need as you build the HL7 production, but choosing this option provides a useful set of starter elements for HL7. Generic Choose this option for all other types of production. 6. Click OK. The [Ensemble] > [Productions] > [Production Model] page displays. The Production Model page offers the following menu options: Add Business Service Click this link to start the Business Service Wizard. Choose: - HL7 Input Choose TCP, File, or FTP to determine the host class. Each class already exists and requires no programming. Simply choose one. Give the item a configuration Name. Do not use the characters ;:, Use the Target Name field to identify the business process or business operation to which this business service will send the HL7 messages that it receives. - Business Metric Choose a host class from the MetricClass drop-down list. If the class you need does not appear on this list, create the class in Studio as described in the chapter Business Services, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. Give the item a configuration Name. Do not use the characters ;:, Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). Comment is an optional text description. Call Interval determines how often the business metric will recalculate the values of its properties. The Call Interval is in seconds, starting from a minimum of 0.1 seconds. The default is 5 seconds. - Other 22 Developing Ensemble Productions
Choose a host class from the ServiceClass drop-down list. If the class you need does not appear on this list, create the class in Studio as described in the chapter Business Services, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. Give the item a configuration Name. Do not use the characters ;:, Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). Comment is an optional text description. Using the Production Model Click OK to save your changes, Cancel to ignore them. Most business services have a Call Interval and other operational settings whose values you must set from the configuration display on the [Ensemble] > [Productions] page. To navigate to the configuration display from the [Ensemble] > [Productions] > [Production Model] page, click Configure Production. Add Business Process Click this link to start the Business Process Wizard. Choose: - Business Process Component Adds a business process that you have set up to work as a reusable component as described in the chapter Business Processes. Choose a host class from the Component drop-down list. If the class you need does not appear on this list, create the class in Studio, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. Give the item a configuration Name. Do not use the characters ;:, Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). Comment is an optional text description. - HL7 Message Router Adds a business process that routes HL7 message data. For details, see the Ensemble HL7 Version 2 Development Guide. Accept the default Router Class of EnsLib.HL7.MsgRouter.RoutingEngine. Give the item a configuration Name. Do not use the characters ;:, Use the Routing Rule Name field to identify the routing rule set to which this business process will send the messages that it receives. Developing Ensemble Productions 23
Creating a New Production - Other Adds a normal business process. Choose a host class from the ProcessClass drop-down list. If the class you need does not appear on this list, create the class in Studio as described in the chapter Business Processes, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. Give the item a configuration Name. Do not use the characters ;:, Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). Comment is an optional text description. Click OK to save your changes, Cancel to ignore them. Most business processes have an Inactivity Timeout, Alert On Error, and other settings that you must set from the configuration display on the [Ensemble] > [Productions] page. To navigate to the configuration display from the [Ensemble] > [Productions] > [Production Model] page, click Configure Production. Add Business Operation Click this link to start the Business Operation Wizard. Choose: - HL7 Output Choose TCP, File, or FTP to determine the host class. Each class already exists and requires no programming. Simply choose one. Give the item a configuration Name. Do not use the characters ;:, - Other Choose a host class from the OperationClass drop-down list. If the class you need does not appear on this list, create the class in Studio as described in the chapter Business Operations, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. Give the item a configuration Name. Do not use the characters ;:, Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). Comment is an optional text description. Click OK to save your changes, Cancel to ignore them. 24 Developing Ensemble Productions
Most business operations have a Retry Interval, Failure Timeout, and other operational settings whose values you must set from the configuration display on the [Ensemble] > [Productions] page. To navigate to the configuration display from the [Ensemble] > [Productions] > [Production Model] page, click Configure Production. Remove Item Delete the business service, business process, or business operation that is currently selected in the production model. Save Production Save any changes made in the current editing session. Configure Production Display the [Ensemble] > [Productions] page so that you can provide configuration details for items that you have added. Cancel Revert to the previously saved version of the production model. Using the New Production Wizard Delete Production Delete the production that is currently displayed on the [Ensemble] > [Productions] > [Production Model] page. A confirmation dialog displays. To permanently delete the production with no chance of recovery, click OK. The production and all of its configured settings are removed. The underlying classes for business hosts and data transformations remain. Important: For details regarding the Ensemble Management Portal, including options for adding, configuring, and removing productions and their elements, see Managing Ensemble Productions. 2.2 Using the New Production Wizard The Studio tool supports the development of Ensemble production software in a number of ways. This section and the Ensemble Studio section later in this chapter describe the Studio features that are unique to Ensemble. The book Using Caché Studio documents the Studio features that Ensemble and Caché products share. You can create a new Ensemble production from inside the Studio tool as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Production icon and click OK. Developing Ensemble Productions 25
Creating a New Production 5. Enter a package and class name for the production. Click Next. Important: InterSystems recommends that you do not use the package names Demo, Ens, EnsLib, EnsPortal, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 6. To enable testing for the production, select the Enable Testing check box. 7. Enter and edit business hosts using the table. To add, reorder or delete business hosts, click the icons to the right of the table. Each time you click the Add icon, a dialog prompts you as follows: Choose the Class Name from a drop-down list of valid host classes defined in your Ensemble namespace. Enter a Name that will identify this business host in the Ensemble Management Portal. Do not use the characters ;:, Determine a Pool Size for jobs associated with this business host. This value can be changed in the Ensemble Management Portal. Click OK to save the item definition or Cancel to ignore it. 8. Click Finish to save your new production definition or Cancel to discard it. The result looks something like the following example. Class User.NewProduction1 Extends Ens.Production [ ProcedureBlock ] { XData ProductionDefinition { <Production Name="User.NewProduction1" TestingEnabled="true"> <ActorPoolSize>2</ActorPoolSize> <Item Name="ReasonableBank" ClassName="Demo.Loan.BankUS" PoolSize="1" /> <Item Name="SlowBank" ClassName="Demo.Loan.BankManana" PoolSize="1" /> <Item Name="EfficientBank" ClassName="Demo.Loan.BankSoprano" PoolSize="2" /> <Item Name="FindLoanRate" ClassName="Demo.Loan.FindRateDecisionProcessBPL" PoolSize="3" /> <Item Name="TerminalSession" ClassName="Demo.Loan.FindRateTerminalService" PoolSize="1" /> <Item Name="EMailSession" ClassName="Demo.Loan.FindRateEMailService" PoolSize="1" /> <Item Name="TestingService" ClassName="EnsLib.Testing.Service" PoolSize="1" /> <Item Name="TestingProcess" ClassName="EnsLib.Testing.Process" PoolSize="1" /> <Item Name="BusinessProcessMonitor" 26 Developing Ensemble Productions
Configuration Settings ClassName="Ens.MonitorService" PoolSize="1" /> <Item Name="DashboardMetrics" ClassName="Demo.Loan.BankMetric" PoolSize="1" /> </Production> } } Using Studio, you can add methods to a production class definition, just before the start of the XData ProductionDefinition block. You can use Studio to examine the Demo.Loan.FindRateProduction class in the ENSDEMO namespace. This class provides examples of using methods in a production. The XData ProductionDefinition block holds the configuration information for the production. This consists of values for all the configurable settings that the host classes for the production provide. When you edit production settings using the Ensemble Management Portal [Ensemble] > [Productions] page, you can apply your configuration changes immediately, even if the production is currently running. Any configuration changes that you apply while using the portal are visible in the production class XData ProductionDefinition block, the next time you open the production class definition in Studio. Although you can edit the XData ProductionDefinition block in Studio or a text editor, it is best to edit it from the Ensemble Management Portal. By doing so, you can avoid introducing syntax errors and take advantage of type validation by the portal. However, there is one circumstance that requires you to edit the XData ProductionDefinition block; that is when you want to control the top-to-bottom order of the shapes displayed in each column of the configuration diagram on the [Ensemble] > [Productions] page: Business Services, Business Processes, and Business Operations. Configuration items appear in production class in the order in which they were added to the production. The configuration diagram faithfully captures this order in each column, positioning shapes from top to bottom as you add them to the production. The only way to change this order within a column is to open the production class in Studio and edit the XData ProductionDefinition block, reorder <Item> elements, then recompile the production class. Any changes that you make in this way become visible in the configuration diagram the next time you refresh the display. 2.3 Configuration Settings Production classes and business host classes can have configurable properties defined using a SETTINGS parameter in their respective class definitions. For an overview of configurable settings and why they are useful, see the Configuration Settings section in the previous chapter, Production Concepts. To provide new configurable settings for a production or for a business host, modify its class definition as follows: Developing Ensemble Productions 27
Creating a New Production 1. Add a property for each configuration setting you wish to define. 2. Add a class parameter called SETTINGS to the class. 3. Set the value of SETTINGS to be a comma-delimited list of the names of the properties you have just defined. For example: Property foo As %String; Property bar As %String; Parameter SETTINGS = "foo,bar"; The foo and bar settings now automatically appear in the configuration display on the [Ensemble] > [Productions] page whenever an item of that class is selected for configuration. 2.3.1 How Class Code Determines the Available Settings The syntax for a SETTINGS parameter appears in this excerpt from the class Ens.InboundAdapter: Class Ens.InboundAdapter Extends Ens.Adapter [ ClassType = "", ProcedureBlock, System = 3 ] { /// The minimum interval between invocations of the adapter by the Ensemble /// framework. For adapters that poll for external events, this is the polling /// interval. However, most polling adapters will process all inputs /// immediately if several are detected at one time. This is also the interval /// at which each Business Service will check for shutdown requests. Property CallInterval As %Numeric(MINVAL = 1) [ InitialExpression = 5 ]; Parameter SETTINGS = "CallInterval"; /// (...Additional lines removed from this example...) } Any extension of a class with a SETTINGS parameter inherits the list of configurable properties from its parent class or classes. You can extend the list of configurable properties in the new class by providing a SETTINGS parameter in the new class. The following example is similar to the built-in class EnsLib.File.InboundAdapter. It extends Ens.InboundAdapter by adding several configurable properties and a SETTINGS parameter: Class EnsLib.File.InboundAdapter Extends (Ens.InboundAdapter, Ens.Util.File) [ ClassType = "", ProcedureBlock, System = 3 ] { /// Path to directory to look for files in Property FilePath As %String(MAXLEN = 1000) [ Required ]; /// Wildcard filename to look for; may be a semicolon-separated list of /// wildcards. Property FileSpec As %String(MAXLEN = 400) [ InitialExpression = "*" ]; /// Path to move a file to after processing is completed. If not given, the /// file will be deleted after processing is completed Property ArchivePath As %String(MAXLEN = 1000); 28 Developing Ensemble Productions
/// Path to move a file to while it is being processed. If not given, the file /// will not move while in process. This setting is useful when the same /// filename is used for repeated file submissions. Property WorkPath As %String(MAXLEN = 1000); /// Use this Character Set to translate input from the file. For binary input, /// use "Binary". Property Charset As %String [ InitialExpression = "Default" ]; /// Amount of time to wait to be able to take posession (open,move) a file /// we've found (in case it's still being written in place) Property FileAccessTimeout As %Integer [ InitialExpression = 10 ]; /// Append a timestamp to Archive and Working filenames in order to prevent /// possible name collisions Property AppendTimestamp As %Boolean; Parameter SETTINGS = "FilePath,FileSpec,ArchivePath,WorkPath,Charset, FileAccessTimeout,AppendTimestamp"; /// (...Additional lines removed from this example...) } Configuration Settings 2.3.2 How a User Configures Production Settings When an adapter of the class EnsLib.File.InboundAdapter is selected in the configuration diagram on the [Ensemble] > [Productions] page, a combined list of the configurable properties from Ens.InboundAdapter and EnsLib.File.InboundAdapter displays in the bottom half of the configuration display. Each property appears in the display because it is listed by the SETTINGS parameter in the EnsLib.File.InboundAdapter class or its parent class Ens.InboundAdapter. Note: The previous topic displays the class code from Ens.InboundAdapter and EnsLib.File.InboundAdapter that causes these settings to appear in the configuration display on the [Ensemble] > [Productions] page. Developing Ensemble Productions 29
Creating a New Production Example of Settings on the Configuration Page Because the class code for EnsLib.File.InboundAdapter provides Documatic (///) comment lines immediately above each property definition, context-sensitive help is available for these properties in the configuration display on the [Ensemble] > [Productions] page. Whenever the user hovers the cursor over a property name on the configuration display, the comment text for that property definition displays as a tooltip. Note: Ordinary ObjectScript comment lines begin with a space and two slash characters ( //) or a space and semicolon ( ;). For details about InterSystems Documatic comment conventions (///) see the section Documentation and Comments. The help text shown in the previous figure (for the ArchivePath property) results from the following code in the class EnsLib.File.InboundAdapter: /// Path to move a file to after processing is completed. If not given, the /// file will be deleted after processing is completed Property ArchivePath As %String(MAXLEN = 1000); If there is no comment text in the class where a property is defined, no tooltip is available for that property. 30 Developing Ensemble Productions
2.3.3 How a Production Stores the Values of its Settings After the first time you configure production settings using the Ensemble Management Portal, the production configuration data remains stored in an XML document that is embedded in an XData ProductionDefinition block in the host class for the production. If you want to view this class code, you can find it in Studio. Connect to your Ensemble namespace, and in the Workspace window, select the Production tab. Look for the class under the Productions category. When you edit production settings using the portal, you can apply your configuration changes immediately, even if the production is currently running. Any configuration changes that you apply while using the portal are visible in the production class XData ProductionDefinition block, the next time you open the production class definition in Studio. You can view or edit the XData ProductionDefinition block in Studio. However, when you want to change a production configuration, it is safest to rely on the Ensemble Management Portal to make and apply changes. By doing so, you can avoid introducing syntax errors and take advantage of type validation by the portal. The following excerpt from a production class shows what an XData ProductionDefinition block can look like once the production is configured: XData ProductionDefinition { <Production Name="Demo.Loan.FindRateProduction" TestingEnabled="true" LogGeneralTraceEvents="false"> <Description></Description> <ActorPoolSize>2</ActorPoolSize> <Setting Target="Production" Name="ShutdownTimeout">120</Setting> <Setting Target="Production" Name="UpdateTimeout">10</Setting> <Item Name="Ens.ManagerService" Category="" ClassName="Ens.ManagerService" PoolSize="1" Enabled="true" Foreground="false" InactivityTimeout="0" Comment="" LogTraceEvents="false" Schedule=""> </Item> <Item Name="Demo.Loan.BankMetrics" Category="" ClassName="Demo.Loan.BankMetrics" PoolSize="1" Enabled="true" Foreground="false" InactivityTimeout="0" Comment="" LogTraceEvents="false" Schedule=""> <Setting Target="Adapter" Name="CallInterval">5</Setting> </Item> <!-- Many similar Item entries here --> Configuration Settings <Item Name="Demo.Loan.FindRateMSMQOperation" Category="" ClassName="Demo.Loan.FindRateMSMQOperation" PoolSize="1" Enabled="false" Foreground="false" InactivityTimeout="0" Comment="" LogTraceEvents="false" Schedule=""> <Setting Target="Adapter" Name="QueueLabel"> Find Rate MSMQ Service Response </Setting> <Setting Target="Adapter" Name="QueuePathName">.\private$\FindRate_Response </Setting> <Setting Target="Host" Name="RetryInterval">5</Setting> <Setting Target="Host" Name="FailureTimeout">15</Setting> </Item> Developing Ensemble Productions 31
Creating a New Production <Item Name="Demo.Loan.FindRateMQSeriesOperation" Category="" ClassName="Demo.Loan.FindRateMQSeriesOperation" PoolSize="1" Enabled="false" Foreground="false" InactivityTimeout="0" Comment="" LogTraceEvents="false" Schedule=""> <Setting Target="Host" Name="RetryInterval">5</Setting> <Setting Target="Host" Name="FailureTimeout">15</Setting> <Setting Target="Adapter" Name="QueueManager">QM_davem</Setting> <Setting Target="Adapter" Name="Channel"> S_davem/TCP/127.0.0.1(1414) </Setting> <Setting Target="Adapter" Name="QueueName">postcard</Setting> <Setting Target="Adapter" Name="QueueOptions">MQOO_OUTPUT</Setting> </Item> <Item Name="Demo.Loan.BankEven" Category="" ClassName="Demo.Loan.BankEven" PoolSize="0" Enabled="true" Foreground="false" InactivityTimeout="0" Comment="" LogTraceEvents="false" Schedule=""> </Item> </Production> } 2.3.4 Accessing Production Settings Programmatically The macro $$$ConfigProdSetting("mySetting") retrieves the value of the production setting called mysetting. InterSystems suggests you wrap this macro in a $GET call for safety. For details about $GET see the Caché ObjectScript Reference. The following Ens.Director class methods allow retrieval of production settings even when the production is not running: GetAdapterSettings Retrieve an array containing the values of all adapter settings for the identified configuration item: a business service or business operation. The array is subscripted by setting name. The first parameter for this method is a string that contains the production name and configuration item name separated by two vertical bars ( ). The return value is a status value. If the status value is not $$$OK, the specified combination of production name (myprod) and configuration item name (myop) could not be found. Set tsc=##class(ens.director).productionsettings("myprod myop",.tsettings) GetAdapterSettingValue Get the value of a named adapter setting for the identified configuration item: a business service or business operation. The first parameter is a string that contains the production name and configuration item name separated by two vertical bars ( ). The second parameter is the name of a configuration setting. The third output parameter returns a status value from the call. For example: Set val=##class(ens.director).gethostsettingvalue("myprod myop","qsize",.tsc) 32 Developing Ensemble Productions
If the returned status value is not $$$OK, the specified combination of production name (myprod) and configuration item name (myop) could not be found, or a setting of the specified name (QSize) was not found in the configuration for that specified production and configuration item. GetCurrProductionSettings Retrieve an array containing the values of all production settings from the currently running production or the production most recently run. The array is subscripted by setting name. The return value for this method is a status value. If the status value is not $$$OK, no current production could be identified. Set tsc=##class(ens.director).getcurrproductionsettings(.tsettings) GetCurrProductionSettingValue Configuration Settings Returns the string value of a named production setting from the currently running production or the production most recently run. The second output parameter returns a status value from the call. If this status value is not $$$OK, either a setting of the specified name was not found in the configuration for the current production, or no current production could be identified. GetHostSettings Set myvalue=##class(ens.director).getcurrproductionsettingvalue("myset",.tsc) Retrieve an array containing the values of all settings for the identified configuration item: a business service, business process, or business operation. The array is subscripted by setting name. The first parameter for this method is a string that contains the production name and configuration item name separated by two vertical bars ( ). The return value is a status value. If the status value is not $$$OK, the specified combination of production name (myprod) and configuration item name (myop) could not be found. Set tsc=##class(ens.director).productionsettings("myprod myop",.tsettings) GetHostSettingValue Get the value of a named setting for the identified configuration item: a business service, business process, or business operation. The first parameter is a string that contains the production name and configuration item name separated by two vertical bars ( ). The second parameter is the name of a configuration setting. The third output parameter returns a status value from the call. For example: Set val=##class(ens.director).gethostsettingvalue("myprod myop","qsize",.tsc) Developing Ensemble Productions 33
Creating a New Production If the returned status value is not $$$OK, the specified combination of production name (myprod) and configuration item name (myop) could not be found, or a setting of the specified name (QSize) was not found in the configuration for that specified production and configuration item. GetProductionSettings Retrieve an array containing the values of all production settings from the named production. The array is subscripted by setting name. The return value for this method is a status value. If the status value is not $$$OK, the specified production could not be found. Set tsc=##class(ens.director).productionsettings("myprod",.tsettings) GetProductionSettingValue Get the value of a named production setting from the named production. The third output parameter returns a status value from the call. If this status value is not $$$OK, the specified production could not be found, or a setting of the specified name was not found in the configuration for the specified production. Set val=##class(ens.director).getcurrproductionsettingvalue("prod","set",.tsc) If you browse the online class reference documentation for Ens.Director, you can see that it offers many class methods, including many intended for use only by the Ensemble internal framework. InterSystems recommends that you use only the Ens.Director methods documented in this book, and only as documented. For other recommended Ens.Director methods, see: Ens.Director in the Production Life Cycle section of the chapter Production Concepts Invoking a Business Service Directly in the chapter Business Services 2.4 Username and Password Credentials Some remote systems require a username and password to log into that system. A username-andpassword pair is a login credential. Ensemble permits you to store login credentials in a centralized table that can be viewed and edited only by users with access to the Ensemble Management Portal. This table, called the Credentials table, provides ease of management and protects login data from unauthorized access. Users can edit the Credentials table only by logging into the Ensemble Management Portal and navigating to the [Ensemble] > [Maintenance] > [Credentials] page. 34 Developing Ensemble Productions
Each username-and-password pair in the Credentials table has an ID. When configuring an inbound or outbound adapter on the [Ensemble] > [Productions] page of the Ensemble Management Portal, you can enter this ID in place of the username or password that is required to log into the remote system. An adapter that uses credentials logs itself into a remote system as follows: Using the ID as a key into the Credentials table, it gets the username and password from the table and sends them to the remote system with a request to log in. This means that a system administrator can use the [Ensemble] > [Maintenance] > [Credentials] page to change the username and password values for an ID, without disturbing any other data in the production configuration. The built-in Email or FTP outbound adapters are examples of classes that use credentials. Try viewing the class code for EnsLib.Email.OutboundAdapter or EnsLib.FTP.OutboundAdapter to see how this works. Search for the string Credentials in the file. Inbound adapters can also use credentials. 2.4.1 Credentials on the Configuration Page When using the Ensemble Management Portal, you can confirm that an adapter uses credentials as follows: Open the configuration display on the [Ensemble] > [Productions] page. Choose a business service or business operation to configure. In the Specific Settings column, look for a Credentials field. If the Credentials field is not present, the adapter does not permit credentials to be configured for it. Generally this is because it does not need a username-and-password pair to accomplish its task. The EnsLib.File.InboundAdapter and EnsLib.File.OutboundAdapter are good examples. If the Credentials field is present in the configuration display, it must contain an ID from the Credentials table. If there is no appropriate entry in the Credentials table, you must create it, and enter its ID into the Credentials field. If no credentials are present, no authentication will take place. This might make the adapter unable to connect to the external application. 2.4.2 Credentials in a Class Definition In Studio, you can confirm that an adapter uses credentials as follows: Open the outbound adapter class and search for the string Credentials in the file. In classes that use credentials: One of the published adapter is a string called Credentials, and The class provides a method called CredentialsSet that uses the value of the Credentials setting as a key to look up the username and password in the Credentials table. It then instantiates a credentials object that contains the username and password. Adapter classes without these conventions do not use credentials. Username and Password Credentials Developing Ensemble Productions 35
Creating a New Production 2.4.3 Overriding the Configured Credentials While the Credentials table serves to centralize management and keep login data out of source code, sometimes you need to write code that gets credentials from a source other than the Credentials table. For example, your code might retrieve a username and password from a Web Form or cookie, and then use them with the HTTP outbound adapter to connect to some other site. The way to handle this is in your business service or business operation code, before calling any adapter methods: Provide code that instantiates a credentials object and assigns username and password values to it, and Do not subsequently set the adapter Credentials property or call the adapter CredentialsSet method, or the values may be reset. For example: If..Adapter.Credentials="" { Set..Adapter.%CredentialsObj=##class(Ens.Config.Credentials).%New() } Set..Adapter.%CredentialsObj.Username = tusername Set..Adapter.%CredentialsObj.Password = tpassword Code such as this provides a credentials object that the EnsLib.HTTP.OutboundAdapter can use, but the values inside the object do not come from the Credentials table. 2.5 Log, Alert, and Trace The developer signalled the intention to log or trace an event by providing a call in the host class that does one of the following: Logs the text Traces the text Sends the text as an Alert When developing classes for an Ensemble production, the programmer must decide when to generate log, trace, or alert notifications in response to various conditions that may arise. Not all types of error or activity should necessarily generate an event log entry, a console trace message, or a user alert message. It is up to the developer to choose which occurrences to note, and how to note them. For example, event log entries should appear in case of an external, physical problem, such as 36 Developing Ensemble Productions
a bad network connection. The event log should not register program errors; these should be resolved before the production is released. It is possible to tailor the behavior of log, trace and alert messages. For example, it might be necessary for a system administrator to use the Ensemble Management Portal to configure pager numbers or email addresses for alert notification. The system administrator can also decide whether to enable or disable viewing and notification of various types of message. The distribution of log, alert, and trace messages works as follows: If an Ensemble job has been configured to Run in Foreground, then all log, alert, and enabled trace notifications are printed to the Ensemble Terminal window for that job. All alerts are automatically logged. Trace messages may be logged, but this is optional. Automatic logging of trace messages is enabled or disabled for each configuration item individually, by using the configuration display on the [Ensemble] > [Productions] page. Each business service, business process, and business operation in the production has its own Log Trace Events option. When Log Trace Events is enabled, all of the trace messages that this configuration item generates are automatically stored in the Ensemble event log. The production itself also has a Log Unassigned Trace Events option. This enables logging for all trace messages issued by production elements that are not configuration items. There is no overlap or interaction between these settings; Log Unassigned Trace Events does not override or provide a default value for Log Trace Events. 2.5.1 Logging A host class can store a text string in the Ensemble event log. This is called logging the string. Log utilities are available for use in Caché Basic and ObjectScript. Event log entries can be created automatically by using the <trace> or <alert> elements in BPL. Log messages are useful during host class development, but even a completed class should retain some calls to log utilities, so that it can provide the diagnostic messages that a system administrator needs to see. 2.5.1.1 Log Messages from ObjectScript Log, Alert, and Trace $$$ASSERT, $$$LOGINFO, $$$LOGWARNING, $$$LOGERROR, and $$$LOGSTATUS are the ObjectScript utility macros that write an entry to the Ensemble event log. You assign an entry type to the event log entry simply by choosing a specific log macro to write the string. The resulting event log entry types are Assert, Info, Warning, Error, and Status, respectively. Developing Ensemble Productions 37
Creating a New Production When viewed on the Ensemble Management Portal [Ensemble] > [Event Log] page, each event log entry type has a different background color, to distinguish it from the other types. A system administrator can filter the event log display by choosing to view only entries of a certain type. The log macros each accept a text string as a parameter, except $$$ASSERT which accepts a boolean expression, and $$$LOGSTATUS which accepts a status code variable. The string may be a literal string or any programmed expression. The string might combine text with the values of class properties, as in this call: $$$LOGERROR("Awaiting connect on port "_..Port_" with timeout "_..CallInterval) Or the string might combine text with the results of various ObjectScript function calls, like this: $$$LOGERROR("Got data chunk, size="_$length(data)_"/"_tchunksize) 2.5.1.2 Log Messages from Basic It is possible to produce the effects of the ObjectScript log macros in Caché Basic code. The Basic routine calls for doing so are as follows. To write an event log entry with a priority of Assert, Error, Warning, Info, or Status, respectively: "Ens.Util.Log".LogAssert(Me.%ClassName(1),CurrentMethod,arg) "Ens.Util.Log".LogError(Me.%ClassName(1),CurrentMethod,arg) "Ens.Util.Log".LogWarning(Me.%ClassName(1),CurrentMethod,arg) "Ens.Util.Log".LogInfo(Me.%ClassName(1),CurrentMethod,arg) "Ens.Util.Log".LogStatus(Me.%ClassName(1),CurrentMethod,arg) In these examples, CurrentMethod is the name of the current method and arg is a string or value that you want written to the log. 2.5.2 Trace Messages Ensemble can display a trace message on an Ensemble Terminal window while a production is running. Trace utilities are available for use in ObjectScript, Caché Basic, and BPL. Trace messages appear only if the configuration item that generates them has been configured to Run in Foreground mode. Trace messages may be written to the Ensemble event log as well as to the console. A system administrator controls this behavior for each configuration item using its Log Trace Events setting. If the Log Trace Events setting is enabled, whenever a trace message is generated, it is also logged, with an event log entry type of Trace. If Log Trace Events is disabled, no trace messages are logged for that configuration item. 38 Developing Ensemble Productions
Log, Alert, and Trace 2.5.2.1 Logging User Trace and System Trace By default, when Log Trace Events is enabled Ensemble displays and logs only User trace messages. You can change this default selectively so that, in addition to User trace messages, some or all types of System trace message also appear. The way to do this is to set values for nodes on the ^Ens.Debug global. The ^Ens.Debug("TraceCat") node acts as the main control for the other types of trace message: If you do not set ^Ens.Debug("TraceCat") to any value, only User trace messages appear. If you set the global as follows, neither User trace nor System trace messages appear. Set ^Ens.Debug("TraceCat")=0 If you set the global as follows, any trace messages that are not explicitly disabled appear. Set ^Ens.Debug("TraceCat")=1 Subnodes in ^Ens.Debug("TraceCat") control the various types of trace message individually. You can set values to 1 (true) to enable and 0 (false) to disable. For example, setting values as follows would enable User trace and all types of System trace except external error handling, message parsing, and general system trace messages: Set ^Ens.Debug("TraceCat")=1 ; applies to any trace type not set below Set ^Ens.Debug("TraceCat","bproc")=1 ; traces from business processes Set ^Ens.Debug("TraceCat","connwait")=1 ; adapters waiting to connect Set ^Ens.Debug("TraceCat","exterr")=0 ; errors from external systems Set ^Ens.Debug("TraceCat","file")=1 ; file read or write operations Set ^Ens.Debug("TraceCat","ontask")=1 ; business host framework events Set ^Ens.Debug("TraceCat","parse")=0 ; HL7 and other virtual document parsers Set ^Ens.Debug("TraceCat","protocol")=1 ; sequence # from HL7 MSH segment Set ^Ens.Debug("TraceCat","queue")=1 ; message queue management Set ^Ens.Debug("TraceCat","system")=0 ; general system trace messages Set ^Ens.Debug("TraceCat","timing")=1 ; messages concerning duration of calls Set ^Ens.Debug("TraceCat","transform")=1 ; normal DTL data transformations Set ^Ens.Debug("TraceCat","user")=1 ; user-defined trace messages Set ^Ens.Debug("TraceCat","xform")=1 ; errors in DTL data transformations Technically, all the categories set to 1 would be redundant because of the top node: Set ^Ens.Debug("TraceCat")=1 but the example is useful because it lists all of the available ^Ens.Debug settings for User trace and System trace. During normal operations you generally want to see User trace messages; for this result leave ^Ens.Debug("TraceCat") undefined. 2.5.2.2 Trace Messages from ObjectScript In ObjectScript, the trace utilities are $$$TRACE and $$$systrace. Use $$$systrace to assign a System category to a trace message, $$$TRACE to assign the User category. Developing Ensemble Productions 39
Creating a New Production You might see calls to $$$systrace in Ensemble system code that you view using Studio, but the appropriate choice for your own business host classes is generally $$$TRACE. For example: $$$TRACE("received application for "_request.customername) 2.5.2.3 Trace Messages from Basic The Caché Basic routine calls for issuing trace messages are as follows: To write a system-level trace message: "Ens.Util.Trace".WriteTrace("system",Me.%ClassName(1),CurrentMethod,arg) To write a user-level trace message: "Ens.Util.Trace".WriteTrace("user",Me.%ClassName(1),CurrentMethod,arg) In these examples, CurrentMethod is the name of the current method and arg is a text string that you want written to the console. 2.5.2.4 Trace Messages from BPL or DTL A BPL business process can write a trace message using the <trace> element. DTL data transformations also support <trace>. For example: <trace value='"the time is: " & Now' /> The value is a literal string or an expression that is evaluated to provide the text of the trace message. If an expression, it may perform string concatenation or other calculations as permitted by the native scripting language of the business process. This language is either Caché Basic or ObjectScript. Note: BPL or DTL <trace> expressions also support virtual property syntax using the {} convention. For details see the Ensemble Business Process Language Reference or the Ensemble Data Transformation Language Reference. The <trace> element generates trace message with User priority; the result is the same as calling the $$$TRACE macro from ObjectScript or the WriteTrace("user") utility from Caché Basic. As with all trace messages, the results of the BPL or DTL <trace> element depend on how the associated business host has been configured using the Ensemble Management Portal. BPL <trace> messages appear in the Terminal window only if the associated BPL business process has been configured to Run in Foreground. DTL <trace> messages appear only if the business host that invokes the DTL data transformation has been configured to Run in Foreground. Either type of <trace> message can appear in the event log in addition to the Terminal window, but only if the associated business host has the Log Trace Events option enabled. 40 Developing Ensemble Productions
Log, Alert, and Trace 2.5.3 Alerts Alerts provide the ability to send notifications to a user while an Ensemble production is running. The intention is to alert a system administrator or service technician to the presence of a problem. Alerts may be delivered via email, text pager, or another mechanism. Alerts may be generated using: The SendAlert method from Caché Basic or ObjectScript code The <alert> element from a BPL business process The Alert On Error setting to enable automatic alerts from business hosts All alert messages are automatically written to the Ensemble event log as entries of type Alert. However, the real purpose of an alert is to contact a user. A production does this by directing all alert messages to a configuration item called Ens.Alert, which you can set up to select the best way to contact each user outside Ensemble. The following topics explain how these conventions work. 2.5.3.1 Alerts from ObjectScript or Basic Business services, business processes, and business operations each provide a method called SendAlert. Any business host can send an alert by constructing a message of type Ens.AlertRequest and sending it via the SendAlert method. The Ens.AlertRequest message has a text string property called AlertText. The alert message is sent asynchronously without waiting for a response. In ObjectScript, the method call looks like the following example, but all on one line: Do..SendAlert(##Class(Ens.AlertRequest).%New($LB(..%ConfigName, "Suspended HL7 Message "_prequest.%id()_ " because ACK.MSA.Acknowledgement Code = '"_tacknowledgmentcode_"'")) The text in each call to SendAlert is necessarily different, depending on which configuration item is sending the alert and why. Ideally, an alert message provides enough information so that the technician has a good idea of how to address the problem. Each time a SendAlert method is called, the alert text appears as an Ensemble event log entry. The user becomes aware of the alert the next time he or she logs into the Ensemble Management Portal and views the appropriate section of the [Ensemble] > [Event Log] page. This mechanism might be too passive for the most urgent messages. If you want the production to actively seek the user, you must set up a configuration item that knows how to contact a user device. A production has only one target for alert messages. This alert target receives Ens.AlertRequest messages from all business hosts within the production, and decides what to do with these messages. The host class for an alert target can be a business process or a business operation. The alert target host class must be configured as a member of the production with the configuration name Ens.Alert. Note: Alert messages are written to the Ensemble event log whether or not you enable a configuration item called Ens.Alert. Developing Ensemble Productions 41
Creating a New Production When creating a host class to use as Ens.Alert, you must make sure the class contains any logic that is necessary to route the alert to various users, via various mechanisms, at various times of day, in accordance with your organization s problem-solving policies and procedures. The host class should forward alert request messages to business operations that will deliver the alerts by sending email, ringing pagers, etc. You might want to add configuration SETTINGS to the class to allow configuration of properties such as telephone numbers and email addresses. SETTINGS permit such values to be configured from the configuration display on the [Ensemble] > [Productions] page. For details, see the Configuration Settings section in the chapter Production Concepts. 2.5.3.2 Alerts from BPL A BPL business process can write an alert message using the <alert> element. For example: <alert value="the system needs service right away."/> The value is a literal string or an expression that is evaluated to provide the text of the trace message. If an expression, it may perform string concatenation or other calculations as permitted by the native scripting language of the business process. This language is either Caché Basic or ObjectScript. Note: BPL <alert> expressions also support virtual property syntax using the {} convention. For details, see the Ensemble Business Process Language Reference. The result of calling <alert> from BPL is identical to calling SendAlert from ObjectScript. Just as with SendAlert, the alert always goes to the event log, but you can also configure and enable an alert target called Ens.Alert that sends a notification message outside Ensemble. 2.5.3.3 Configuring Automatic Alerts Alerts can be sent automatically whenever a business service or business operation encounters an error condition. The Alert On Error setting controls this behavior. Alert On Error is available in the [Ensemble] > [Productions] configuration display for business services and business operations, under the Specific Settings heading. When Alert On Error is True, whenever the business host encounters an error it automatically triggers an alert. A business operation also triggers an alert whenever it Suspends its current message. Business operations can be configured with an Alert Retry Grace Period during which errors relating to external connections do not trigger alerts, even if Alert On Error is True. This grace period accommodates a business operation that attempts an external connection with a configured Retry Interval and Failure Timeout. During its retry sequence, the business operation may encounter connection failures that become unimportant when a subsequent retry attempt succeeds. Thus, if a business operation first encounters an error, but later achieves success within the time allotted by the Alert Retry Grace Period, no alert is triggered even though an error occurred. Business services can be configured with a similar Alert Grace Period during which errors relating to external connections do not trigger alerts, even if Alert On Error is True. The Alert Grace Period is 42 Developing Ensemble Productions
allowed to elapse, giving the business service and the external source time to reestablish their connection. If the error condition still exists after the Alert Grace Period, the business service triggers an alert; otherwise no alert is triggered. Setting a grace period value to 0 disables the feature for that business service or business operation. 2.5.4 Alarms Utility Functions Ensemble includes an alarm facility that can be used to invoke a business process or business operation at a predefined time or repeating time interval. An alarm does not indicate an emergency. It is simply a timeout mechanism that Ensemble uses internally to execute timing functions such as the BPL elements <delay> and <sync>. You do not need to know anything about alarms to make Ensemble timing functions work. If you want your production to relay emergency information to a system administrator, you do not want an alarm; you want an alert. 2.6 Utility Functions The Ensemble programming environment provides utility functions for use in business rules or DTL data transformations. These include mathematical or string processing functions such as you may be accustomed to using in other programming languages. This topic lists the available functions and shows the proper syntax for using them in business rules or data transformations. It also explains how to extend the list of built-in utility functions by adding custom code. 2.6.1 Built-in Functions The following table lists the utility functions built into Ensemble. Note: For boolean values, 1 indicates true and 0 indicates false. Developing Ensemble Productions 43
Creating a New Production Utility Functions for Business Rules and DTL Data Transformations Operator Contains(val,str) ConvertDateTime (val,in,out,file) DoesNotContain(val,str) DoesNotMatch(val,pat) DoesNotStartWith(val,str) Exists(tab,val) If(val,true,false) In(val,items) InFile(val,file) Return Value 1 (true) if val contains the substring str; otherwise 0 (false). Reads the input string val as a time stamp in in format, and returns the same value converted to a time stamp in out format. For a list of valid time stamp formats, see the section Time Stamps in Filenames. The default for in and out is %Q. Any %f elements in the out argument are replaced with the file string. If val does not match the in format, out is ignored and val is returned unchanged. 1 (true) if val does not contain the substring str. 1 (true) if val does not match the pattern specified by pat. pat must be a string that uses syntax suitable for the? pattern matching operator in ObjectScript. For details, see the Pattern Matching section in the Operators and Expressions chapter of Using Caché ObjectScript. 1 (true) if val does not start with the substring str. The Exists function provides a way to predict the results of the Lookup function. Exists returns 1 (true) if val is a key defined within the table identified by tab; otherwise it returns 0 (false). If the argument val evaluates to 1 (true), the If function returns the string value of its true argument; otherwise it returns the string value of its false argument. 1 (true) if val is found in the comma-delimited string items. 1 (true) if val is found in the identified file. 44 Developing Ensemble Productions
Utility Functions Operator InFileColumn(...) Return Value The function InFileColumn can have as many as 8 arguments. The full function signature is: InFileColumn(val, file, columnid, rowseparator, columnseparator, columnwidth, linecomment, strippadchars) InFileColumn returns 1 (true) if val is in the specified column in a table-formatted text file. Arguments are as follows: val (required) is the value. file (required) is the text file. Default columnid is 1. Default rowseparator is ASCII 10. A negative rowseparator value indicates the row length. Default columnseparator is ASCII 9. If columnseparator is 0, the format of the file is said to be positional. In this case columnid means character position and columnwidth means character count. Default columnwidth is 0. Default linecomment is an empty string. Default strippadchars consists of a blank space followed by ASCII 9. Lookup(tab,val,def) The Lookup function returns the value of the following global: ^Ens.LookupTable(tab,val) If the requested value is not found, the Lookup function returns the string value of its def argument. The def argument is optional, so if def is not provided and nothing is found, the Lookup function returns an empty string. The Exists function predicts the results of the Lookup function. For additional details, see the Lookup Tables topic later in this section. Developing Ensemble Productions 45
Creating a New Production Operator Matches(val,pat) Max(...) Min(...) Not(val) NotIn(val,items) NotInFile(val,file) Pad(val,width,char) Piece(val,char,from,to) ReplaceStr(val,find,repl) Return Value 1 (true) if val matches the pattern specified by pat. pat must be a string that uses syntax suitable for the? pattern matching operator in ObjectScript. For details, see the Pattern Matching section in the Operators and Expressions chapter of Using Caché ObjectScript. Returns the largest of a list of up to 8 values. List entries are separated by commas. Returns the smallest of a list of up to 8 values. List entries are separated by commas. 0 (false) if val is 1 (true); 1 (true) if val is 0 (false). 1 (true) if val is not found in the comma-delimited string items. 1 (true) if val is not found in the identified file. Reads the input string val. Adds enough instances of char to widen the string to width characters. If width is a positive value, the padding is appended to the right-hand side of the val string. If width is a negative value, the padding is prepended to the left-hand side of the val string. If the delimiter character char is present in the string val, this separates the string into pieces. If there are multiple pieces in the string, from and to specify which range of these pieces to return, starting at 1. If multiple pieces are returned, the delimiter in the return string is the same as the delimiter in the input string. For example: Piece("A,B,C,D,E,F") returns "A" Piece("A!B!C!D!E!F","!",2,4) returns "B!C!D" The default char is a comma, the default from is 1, and the default to is from (return one piece). For details, see the $PIECE function in the Caché ObjectScript Reference. Reads the input string val. Replaces any occurrences of string find with the string repl, and returns the resulting string. Note: Use ReplaceStr instead of the replace function, which has been deprecated. 46 Developing Ensemble Productions
Utility Functions Operator Round(val,n) StartsWith(val,str) Strip(val,act,rem,keep) SubString(str,n,m) ToLower(str) ToUpper(str) Translate(val,in,out) Return Value Returns val rounded off to n digits after the decimal point. If n is not provided (that is, Round(val)) the function drops the fractional portion of the number and rounds it to the decimal point, producing an integer. 1 (true) if val starts with the substring str. Reads the input string val. Removes any characters matching the categories specified in the act template and the rem string, while retaining any characters found in the keep string. Returns the resulting string. For details and examples, see the $ZSTRIP function in the Caché ObjectScript Reference. Returns a substring of a string str, starting at numeric position n and continuing until numeric position m. The number 1 indicates the first character in the string. If m is not provided (that is, SubString(str,n)) the function returns the substring from position n to the end of the string. Returns the string str converted to lowercase. Returns the string str converted to uppercase. Reads the input string val. Translates each occurrence of a character in string in to the character at the corresponding position in string out, and returns the resulting string. 2.6.2 Function Syntax When you reference an Ensemble function in a business rule or a DTL data transformation, the syntax must include parentheses. It must also include any input parameters, such as the numeric values for the mathematical functions Min, Max, or Round. If there are no input values for the function, then the open and close parentheses must be present, but empty. The following are examples of valid function syntax: Examples of Valid Expressions using Functions Expression Min(Age,80,Limit) Round(1/3,2) Computed Value When Age is a property with the value 30 and Limit (likewise a property) has the value 65, the value of this expression is 30. 0.33 Developing Ensemble Productions 47
Creating a New Production Expression Min(10,Max(X,Y)) Computed Value When X is a property with the numeric value 9.125, and Y (likewise a property) has the numeric value 6.875, the value of this expression is 9.125. If the value input to any function is a string that starts with a number, non-numeric characters in the string are dropped and the numeric portion is used. The string "3a" is treated like the number 3, so the function Min("3a","2OfThem") returns the value 2. A string that begins with a non-numeric character such as "a123" has the numeric value 0. The business rule syntax for utility functions differs from the DTL syntax in the following significant way: Business rules reference the utility functions simply by name: ToUpper(value) DTL uses two leading dots on the function name, as if the function were a method:..toupper(value) The following DTL data transformation uses a utility function called ToUpper to convert a string to all uppercase characters. The <assign> statement references ToUpper using double-dot syntax, as if it were a method in the class: Class User.NewDTL1 Extends Ens.DataTransformDTL [ ProcedureBlock ] { XData DTL { <?xml version="1.0"?> <transform targetclass='demo.loan.msg.approval' sourceclass='demo.loan.msg.approval' create='new' language='objectscript'> <assign property='target.bankname' value='..toupper(source.bankname)' action='set'/> <trace value='changed all lowercase letters to uppercase!' /> </transform> } } 2.6.3 User-defined Functions It is possible to extend the set of available functions to include user-defined functions. The built-in utility functions are implemented as methods of the class Ens.Rule.FunctionSet. Adding functions is a matter of subclassing Ens.Rule.FunctionSet and adding more methods. The business rules engine and Business Rule Editor accommodate such extensions automatically. To add a new, user-defined function to the Ensemble programming environment: 48 Developing Ensemble Productions
1. Create a new class that is a subclass of Ens.Rule.FunctionSet. This class must not extend any other superclasses, only Ens.Rule.FunctionSet. 2. For each function you wish to define, add a class method to your new function set class. There is no support for polymorphism, so to be precise, you must mark these class methods as final. You can view this in the existing Ens.Rule.FunctionSet methods. 3. Compile the new class. The new functions are now available for use in rule expressions. To invoke these functions, use the ClassMethod name from your subclass. Unlike functions defined in Ens.Rule.FunctionSet, user-defined method names must be fully qualified with the class that they belong to. This happens automatically if you add them by selecting names from the wizards in the Ensemble Management Portal. As an example, the following function set class provides date and time functions for use in business rules. Its class methods DayOfWeek and TimeInSeconds invoke the ObjectScript functions $ZDATE and $PIECE to extract the desired date and time values from the ObjectScript special variable $HOROLOG: /// Time functions to use in rule definitions. Class Demo.HL7.MsgRouter.Functions Extends Ens.Rule.FunctionSet [ ProcedureBlock ] { /// Returns the ordinal position of the day in the week, /// where 1 is Sunday, 2 is Monday, and so on. ClassMethod DayOfWeek() As %Integer [ CodeMode = expression, Final ] { $zd($h,10) } /// Returns the time as a number of seconds since midnight. ClassMethod TimeInSeconds() As %Integer [ CodeMode = expression, Final ] { $p($h,",",2) } } The default language inside a method is ObjectScript, as in the previous example, but you can use Caché Basic or Java if you define the method using the Language keyword as described in: Language in the Class Keywords section of the Caché ObjectScript Reference. Java only applies when you are Using Java with Caché as described in the book of the same name. The Methods chapter in Using Caché Objects For a full list of functions and special variables available in Caché Basic or ObjectScript, see: Caché Basic Reference Caché ObjectScript Reference Utility Functions Developing Ensemble Productions 49
Creating a New Production Once you have added a new function as described in this topic, the syntax for referring to it is slightly different than for built-in functions. Suppose you define this function in a class that inherits from Ens.Rule.FunctionSet. ClassMethod normalizasexo(value as %String) as %String After you compile the class, when you use one of the Ensemble visual tools such as the Routing Rule Editor or DTL Visual Editor, you will see your function name normalizasexo included in the function selection box along with built-in functions like Strip, In, Contains, and so on. Suppose you choose a built-in function from the function selection box and look at the generated code. You will see that Ensemble has generated the function call using double-dot method call syntax (in DTL) or has simply referenced the function by name (in a business rule). These syntax rules are explained in the previous topic, Function Syntax. The following example is an <assign> statement from DTL that references the built-in Strip function with double-dot syntax: <assign property='target.cod' value='..strip(source.{patientidexternalid.id},"<>cw")' action='set'/> However, if you create your own, user-defined functions, the syntax for DTL is different. It is not enough simply to identify the function; you must also identify the full class name for the class that contains the class method for your function. Suppose your function normalizasexo was defined in a class named HP.Util.funciones. In that case, after you chose a function from the function selection box and looked at the generated code, you would see something like the following example: <assign property='target.sexo' value='##class(hp.util.funciones).normalizasexo(source.{sex})' action='set'/> You need to be aware of this syntax variation if you wish to type statements like this directly into your DTL code, rather than using the DTL Visual Editor to generate the code. 2.6.4 Lookup Tables Ensemble provides the utility function called Lookup so that you can easily perform a table lookup from a business rule or DTL data transformation. The Lookup function works only after you have created at least one lookup table and have populated it with appropriate data. You can create lookup tables using the [Ensemble] > [Maintenance] > [Lookup Settings] page in the Ensemble Management Portal. For instructions, see The Lookup Settings Page section in The Maintenance Page chapter of Managing Ensemble Productions. Should you require more direct manipulation of lookup tables than is provided by the [Ensemble] > [Maintenance] > [Lookup Settings] page, Ensemble provides a class that exposes lookup tables to access 50 Developing Ensemble Productions
via objects or SQL. Additionally, it provides class methods to clear tables, export data as XML, and import data from XML. The class is Ens.Util.LookupTable. For background information about how Caché classes provide programmatic access via objects or SQL, see: The Object Persistence chapter in Using Caché Objects The Defining Tables chapter in Using Caché SQL The Querying the Database chapter in Using Caché SQL Properties in Ens.Util.LookupTable are as follows. All of the properties are of type %String. Their names are: TableName KeyName DataValue Name of the lookup table, up to 255 characters. This is the value from the Lookup Table field on the [Ensemble] > [Maintenance] > [Lookup Settings] page. Key for the entry within the lookup table, up to 255 characters. This is the value from the Key field on the [Ensemble] > [Maintenance] > [Lookup Settings] page. Value associated with this key in the lookup table, up to 32000 characters. This is the value from the Value field on the [Ensemble] > [Maintenance] > [Lookup Settings] page. A sample SQL query might be: Utility Functions SELECT KeyName,DataValue FROM Ens_Util.LookupTable WHERE TableName = 'mytab' Class methods in Ens.Util.LookupTable allow you to work with Ensemble lookup tables as follows. You can call these methods from an ObjectScript routine or from the Terminal prompt: %ClearTable %Import Delete the contents of the specified lookup table. do ##class(ens.util.lookuptable).%cleartable("mytab") Import lookup table data from the specified XML file. For the import to be successful, the file must use the same XML format as that provided by the %Export method of this class. do ##class(ens.util.lookuptable).%import("myfile.xml") Developing Ensemble Productions 51
Creating a New Production %Export Export lookup table data to the specified XML file. If the file exists, Ensemble overwrites it with new data. If the file does not already exist, Ensemble creates it. The following example exports only the contents of the specified lookup table, mytab: do ##class(ens.util.lookuptable).%export("myfile.xml","mytab") The following example exports the contents of all lookup tables in the namespace: do ##class(ens.util.lookuptable).%export("myfile.xml") The resulting XML file looks like the following example. Note that all entries, in all tables, appear as sibling <entry> elements inside a single <lookuptable> element. <?xml version="1.0"?> <lookuptable> <entry table="myothertab" key="mykeya">aaaaaa</entry> <entry table="myothertab" key="mykeyb">bbbbbbbbb</entry> <entry table="mytab" key="mykey1">1111</entry> <entry table="mytab" key="mykey2">22222</entry> <entry table="mytab" key="mykey3">333333</entry> </lookuptable> For each <entry>, the table attribute identifies the table that contains the entry. The key attribute gives the name of the key. The text contents of the <entry> element provide the entry s value. In addition to the XML format described above, you can use the SQL Import Wizard to import commaseparated value (CSV) files that list tables and keys. 2.7 Time Stamps in Filenames While configuring business operations and business services that transmit data to and from files, you frequently have the opportunity to specify input and output filenames in a string that includes date and time format codes, such as %Y%M%d%h%m%s_%f.txt. At runtime, the format codes within this string resolve dynamically based on the current date and time. Ensemble supports the following rules for composing a time stamp specification string: The string may contain literal characters and any of the format codes listed in the following table. Characters that are not part of a format code appear in the resulting time stamp unchanged. All format codes are optional. Each format code consists of a % character, an optional # character, and a conversion character. Ensemble converts the time to a specific time zone or locale if the %K or %L format codes appear at the beginning of the string. 52 Developing Ensemble Productions
Time Stamp Symbols for Input and Output Filenames Time Stamps in Filenames Symbol %a %A %b %B %c Meaning Within a Filename Specification Locale s abbreviated weekday name (Sun, Mon,..., Sat) Locale s full weekday name (Sunday, Monday,..., Saturday) Locale s abbreviated month name (Jan, Feb,..., Dec) Locale s full month name (January, February,..., December) Caché date and time representation as provided by the local machine, except that in forming the time stamp, Ensemble replaces certain characters in the usual date and time format. It replaces spaces with underbars (_), slashes (/) with hyphens (-), and colons (:) with dots (.). The result is something like: MM-DD-YY_hh.mm.ss The %c specifier can have parameters. %c(dformat,tformat,precision) formats the date and time according to your specifications, where: dformat is a number indicating date format. tformat is a number indicating time format. precision is the number of decimal places used to represent subseconds. The Caché ObjectScript Reference describes the %c parameters dformat, tformat, and precision in detail. See the $ZDATETIME topic for a list of all possible dformat and tformat values. %d %#d %D %#D %f Two digits indicating the day of the month (01-31) Day of the month without leading zeros (1-31) Date; equivalent to %m/%d/%y Date; equivalent to %#m/%#d/%y Name indicating the source of the data. The source is usually the input filename (for File and FTP) or a concatenation of the IP address and port number (for data that arrived via TCP). In substituting a value for the format code %f, Ensemble strips out any of the characters,?,\,/,:,[,],<,>,&,,,;,nul,bel,tab,cr,lf, replacing spaces with underbars (_) and slashes (/) with hyphens (-). On all operating systems except OpenVMS, colons (:) become dots (.). On OpenVMS systems, Ensemble replaces colons with hyphens (-). Developing Ensemble Productions 53
Creating a New Production Symbol %F %h %H %#H %I %#I %j %#j %K(n) Meaning Within a Filename Specification As for %f, but with all alphabetic characters converted to uppercase. Locale s abbreviated month name. Equivalent to %b. Two digits indicating the hour in 24-hour format (00-23) Hour in 24-hour format without leading zeros (0-23) Two digits indicating the hour in 12 hour format (01-12) Hour in 12 hour format without leading zeros (1-12) Three digits indicating the day of the year as a number (001-366) Day of the year as a number without leading zeros (1-366) Use the %K(n) format code only at the beginning of the time stamp specification string. %K(n) produces no output, but specifies a base time zone to convert to before formatting the time stamp. n is the time zone, and can be one of the following (case-insensitive): Server (Default) Time on the server where the executing code resides. UTC Universal Time Coordinated (UTC) [+]n Number of hours after (east of) UTC time. n may have a fractional value expressed as a decimal; for example, 4.5 -n Number of hours before (west of) UTC time (n may be fractional) [+]hhmm Hours and minutes after (east of) UTC time, in the ISO 8601:2000 standard format -hhmm Hours and minutes after (west of) UTC time in ISO format %m %#m %M %#M %N %p %#p %P Two digits indicating the month number (01-12) Month number without leading zeros (1-12) Two digits indicating minutes (00-59) Minutes without leading zeros (0 59) Three digits indicating the number of milliseconds (000-999) Locale s a.m. or p.m. indicator for a 12-hour clock (lowercase, with dots) Locale s am or pm indicator for 12-hour clock (lowercase, without dots) Locale s A.M. or P.M. indicator for a 12-hour clock (uppercase, with dots) 54 Developing Ensemble Productions
Time Stamps in Filenames Symbol %#P %q or %q() %q(0) %q(1) %q(2) %q(3) %q(4) %q(5) %Q %Q(n) %r %#r %R %S %t %T %u %#u %U Meaning Within a Filename Specification Locale s AM or PM indicator for a 12-hour clock (uppercase, without dots) HL7 format date and time; equivalent to %Y%m%d%H%M%S or %q(0) HL7 format date and time; equivalent to %Y%m%d%H%M%S or %q ODBC format date and time; equivalent to %Y-%m-%d %H:%M:%S.%N ISO 8601:2000 standard date format; equivalent to %Y-%m-%d Caché $HOROLOG format Caché $ZTIMESTAMP format Creates a GUID ODBC format date and time; equivalent to %Y-%m-%d %H:%M:%S.%N or %c(3,,3) or %q(1) Equivalent to %q(n) Time with seconds in 12-hour format using a.m. or p.m. notation; equivalent to %I:%M:%S %p Time with seconds in 12-hour format using am or pm notation without whitespace or dots; equivalent to %I:%M:%S%#p Time in 24-hour notation; equivalent to %H:%M Two digits indicating seconds (00-60) (60 for leap seconds) Produces a <tab> character Time with seconds in 24-hour notation; equivalent to %H:%M:%S Day of the week as a number (1-7). Monday=1, Tuesday=2,..., Sunday=7. Equivalent to %u Two digits (00 53) indicating the current week within a week-based year convention that does not conform to the ISO 8601:2000 standard. The rules are as follows: The week numbers are 00-53 Sunday is the first day in each week. The first Sunday of January is the first day of week 1 Days in the new year before the first Sunday are in week 0. Developing Ensemble Productions 55
Creating a New Production Symbol %#U %w %#w %W Meaning Within a Filename Specification Number indicating the current week within a week-based year that follows the rules described for %U, except the output does not include leading zeros (0-53). Day of the week (Sunday=0, Monday=1,..., Saturday=6) Equivalent to %w Two digits (00 53) indicating the current week within a week-based year convention that does not conform to the ISO 8601:2000 standard. The rules are as follows: The week numbers are 00-53 Monday is the first day in each week The first Monday of January is the first day of week 1 Days in the new year before the first Monday are in week 0. %W is equivalent to %U(1). %#W %y %Y %z %#z %% %( Number indicating the current week within a week-based year that follows the rules described for %W, except the output does not include leading zeros (0-53). %#W is equivalent to %#U(1). Two digits indicating the year within a century (00-99). For example, the year 1983 produces the number 83 in the time stamp; 2019 produces 19. Four digits indicating the year (0000-9999) Time zone as an offset from Universal Time Coordinated (UTC) in the ISO 8601:2000 standard format (+hhmm or -hhmm). For example, -0430 means 4 hours 30 minutes behind UTC (west of Greenwich). If Ensemble cannot determine the time zone, it ignores the %z code in the time stamp specification string. Time zone as an offset from Universal Time Coordinated (UTC) in hours with leading +/- and without leading zeros. Trailing decimals may appear. For example, -4.5 means 4 hours 30 minutes behind UTC (that is, west of Greenwich). If Ensemble cannot determine the time zone, it ignores the %#z code in the time stamp. Literal % percent sign Literal ( left parenthesis 56 Developing Ensemble Productions
Testing and Debugging Symbol %_ Meaning Within a Filename Specification Reserved token (do not use). This sequence passes through unchanged. The previous table describes all the format codes that you can use when specifying time stamps for use with an inbound or outbound file adapter. These codes conform to POSIX, IEEE, and ISO standards for time format codes. The following table lists the time stamp format codes that do not conform to these standards, or that conform to other standards. Time Stamp Symbols Different from POSIX, IEEE, and ISO Standards Symbol %# %c %E %F %K(n) %L(n) %O %P %q,%q %( Unique Meaning Within a Filename Specification Ensemble supports (and extends) certain Microsoft extended semantics, such as the %# prefix. This indicates the Caché time stamp provided by the local machine. Ensemble does not support the %E code. Ensemble supports %F as an uppercase replacement string, not an ISO format date. Ensemble supports the ISO format date as %q(2) or %Q(2). The user defines the time zone by providing the %K(n) code at the beginning of the file specification string. The %K(n) code produces no output, but specifies a base time zone to convert to before formatting the time stamp. The user defines the locale by providing the %L(n) code at the beginning of the file specification string. The %L(n) code produces no output, but specifies a base locale to use with locale-dependent format codes. Ensemble does not support the %O code. Ensemble defines this code as uppercase AM or PM. Ensemble defines some of these codes according to standards other than POSIX, IEEE, or ISO, such as HL7 or ODBC. Ensemble defines this code as a literal ( character. 2.8 Testing and Debugging This topic explains the facilities available for testing and debugging Ensemble productions. The information is also useful for troubleshooting and tuning production software that is already in use at the enterprise. Topics include: Testing from the Ensemble Management Portal Developing Ensemble Productions 57
Creating a New Production Debugging Production Code Automatic Error Trapping Handling Error Codes Stopping a Suspended Production 2.8.1 Testing from the Ensemble Management Portal The Ensemble Management Portal is HTML-based and can be viewed using a browser. It includes the following features: Ability to view and modify system configuration. Ability to start and stop a production. Ability to view queues and their contents; messages and their details; adapters and actors and their status; business processes and their status; code and graphical representations of configured items. Ability to view, sort, and selectively purge event log entries. Ability to suspend (and later resend) messages whose connectivity is temporarily blocked. Ability to filter and search the message warehouse for specific messages, by category or message content, using a graphical UI or by entering SQL SELECT commands. Ability to visually trace message activity using a graphical UI. Ability to create and view statistical reports. You can launch the portal from within Ensemble Studio, by selecting it as an option from the Utilities menu. Portal features that are most useful for developers are the Monitor Service, which constantly collects runtime data, the Testing Service, which you can use to issue simulated requests into a production that you are developing, and the Event Log, which logs the status messages issued by business hosts. Use these features together to generate test data and study the results. For details about the portal, see Managing Ensemble Productions. 2.8.2 Debugging Production Code The first step in debugging is to turn on system trace messages with the $$$TRACE or $$$LOG utilities. If this does not reveal the problem, you can step into the code using the debugger, as follows: 1. Using Ensemble Studio, insert the BREAK command where you want to start debugging. 2. Using the configuration display on the [Ensemble] > [Productions] page, select the Run in foreground check box for the business host that uses the class you want to debug. 58 Developing Ensemble Productions
3. Start the production. The job that you marked in Step 2 will run in the foreground in an Ensemble Terminal. 4. As soon as that BREAK command is reached, the Terminal enters debug mode and you can step through the code. For details, see the Command-Line Routine Debugging chapter in Using Caché ObjectScript. 2.8.3 Automatic Error Trapping The macros $$$EnsError and $$$EnsSystemError write messages to the Ensemble event log and system console, respectively. It is unlikely that you will have a reason to use these macros when developing a production, but if you examine the built-in Ensemble classes, you will see them. The following information is provided so that you will understand how these macros are being used. The following code excerpt is from the FTP outbound adapter. The adapter tries to get a valid FTP username and password from the Credentials table for the production. If there are no credentials matching the information provided, the adapter uses $$$EnsError to log the status $$$EnsErrNoCredentials. The first parameter of the $$$EnsError macro is a status code, one of the many status codes defined in the file EnsErrors.inc. $$$EnsErrNoCredentials is the status code in the following example. Ensemble uses the status code to look up the appropriate text to write to the event log. Ensemble combines this text with any additional parameter values required by the entry, and writes the completed entry to the event log. #; Connect to the server If '$IsObject(..%CredentialsObj) Do..CredentialsSet(..Credentials) If '$IsObject(..%CredentialsObj) { Set tsc=$$$enserror($$$enserrnocredentials,..credentials) Quit } The following sample code is part of the Demo.Loan sample production package in the ENSDEMO namespace. Demo.Loan.FindRateCSPService is a business service that accepts user requests for interest rate information via a CSP (browser-based) interface. Demo.Loan.FindRateCSPService uses $$$EnsSystemError with a trap; this is the typical convention. Class Demo.Loan.FindRateCSPService Extends Ens.BusinessService [ ProcedureBlock ] { Method OnProcessInput(pCSPRequest As %CSP.Request, poutput As Ens.StringContainer) As %Status { Set $ZT="Trap",tSC=$$$OK do { Set tapplication = ##class(demo.loan.msg.application).%new() Set tapplication.amount = pcsprequest.get("amount") Set tapplication.name = pcsprequest.get("name") Set tapplication.taxid = pcsprequest.get("taxid") Testing and Debugging Developing Ensemble Productions 59
Creating a New Production Set tapplication.nationality = pcsprequest.get("nationality") Set tapplication.businessoperationtype = "mail" Set tapplication.destination = pcsprequest.get("email") Set tsc =..SendRequestAsync("Demo.Loan.FindRateDecisionProcessBPL", tapplication) Quit:$$$ISERR(tSC) #; Set poutput = ##class(ens.stringcontainer).%new(tapplication.getrecordnumbertext(1)) Quit } while (0) Exit Quit tsc Trap Set $ZT="",tSC=$$$EnsSystemError Goto Exit } } You can list any occurrences of $$$EnsSystemError using the error trapping utility %ERN as described in the Command-Line Routine Debugging chapter in Using Caché ObjectScript. The section Error Trap Utilities describes how to view recent occurrences of $$$EnsSystemError by typing the following command at the Terminal prompt: do ^%ERN 2.8.4 Handling Error Codes As you work with Ensemble, you might need to write a business service or business operation class that handles communication between Ensemble and an external system, or a business process class that directs internal processing within Ensemble. If you are not yet familiar with business host classes and how they function within the Ensemble framework, see the Host Classes section in the chapter Production Concepts. When you write custom code, often you must handle error codes received from Ensemble methods. The Ensemble development framework is designed to allow your custom code to be simple and linear as possible with regard to error codes. For example: The OnProcessInput method of business services and the OnMessage and other user-written MessageMap methods of business operations are wrappered by the Ensemble framework, so that developers need not put any additional error trapping in the code they write. The adapter methods available for use by custom business operation code are guaranteed never to trap out, as are the framework methods available to custom code, such as SendAlert and SendRequestSync. Furthermore, the adapter methods are coded to automatically set suitable values for Retry and Suspend when error conditions do occur. Given these precautions built into the Ensemble framework, InterSystems recommends that for normal circumstances your custom code should simply check the error code of each call, and if it is an error 60 Developing Ensemble Productions
value, quit with that value. The following is an example of this coding style. Note the absence of traps or Do {} While 0 blocks: Class Test.FTP.FileSaveOperation Extends Ens.BusinessOperation [ ClassType = "", ProcedureBlock ] { Parameter ADAPTER = "EnsLib.File.OutboundAdapter"; Testing and Debugging Method OnMessage(pRequest As Test.FTP.TransferRequest, Output presponse As Ens.Response) As %Status { Set presponse=$$$nulloref Set tfilename=..adapter.createtimestamp(prequest.filename,"%f_%q") ; file with timestamp should not already exist $$$ASSERT('..Adapter.Exists(tFilename)) Set tsc=..adapter.putstream(tfilename,prequest.streamin) Quit:$$$ISERR(tSC) tsc Quit $$$OK } } More complicated scenarios are sometimes useful, such as for instance executing a number of SQL statements in a business operation using the SQL adapter and then calling a rollback before returning if any of them fail. However, the coding style in the previous example is the best practice in simple circumstances. 2.8.5 Stopping a Suspended Production A production acquires a status of Stopped when, at the end of the shutdown sequence, all of its queues are free of synchronous messages. A production acquires the Suspended status when, at the end of the shutdown sequence, some queues still contain synchronous messages. If this is the case, you can start the Suspended production again to permit these messages to be processed. However, if the problem that originally caused the Suspended status is not resolved, starting a Suspended production can just as easily add more synchronous messages to a queue, without discharging the previous messages and return the production to a Suspended status. If you find this is the case, you may sometimes need to take more drastic action to fully clean up after a production that goes into the Suspended state. Ensemble provides the CleanProduction method for this case. CAUTION: Never use this procedure on a live, deployed Ensemble production. The CleanProduction method removes all messages from queues and removes all current information about the production. Use this procedure only on a production that is still under development. If a live, deployed Ensemble production goes into a Suspended state, contact the InterSystems Worldwide Response Center (WRC) for assistance. If you have exhausted all means to correct the problem and, therefore, are sure that a Suspended production must stop, discarding even synchronous messages that have not yet been delivered, then use the following procedure: Developing Ensemble Productions 61
Creating a New Production 1. Start the Suspended production from the [Ensemble] > [Productions] page by clicking Start in the appropriate row (highlighted in orange); the production status changes to Running. 2. Click Stop in the production row (highlighted in green), to verify the problem still exists. If the production stops successfully, there is no need to clean the production; if the production status returns to Suspended, continue with the next step. 3. Kill the production from an Ensemble Terminal session as follows: a. Change to the appropriate namespace: ZN "EnsSpace" Where EnsSpace is the name of the Ensemble namespace where the Suspended production runs. b. Enter the following command: Do ##class(ens.director).cleanproduction() 4. Verify the production status from the [Ensemble] > [Productions] page; the Status of the production should now be Stopped. Important: Only run the CleanProduction method on a production in a Suspended state. 2.9 Documentation and Comments This topic describes how to obtain and provide documentation and comments as you build the elements of an Ensemble production. 2.9.1 Online Documentation When the local Ensemble server is online, it serves documentation in HTML format via a Web browser. The online documentation system gives access to information about core InterSystems technologies and the InterSystems products Ensemble and Caché. You can access the online documentation in any of the following ways: Find the Ensemble cube in the Windows system tray. Click on it to display the Ensemble cube menu. If Ensemble is stopped, start it. Then choose Documentation from the menu. Entering the following URL into a browser page on the local Ensemble system, where 57772 is the port number for which your Ensemble server is configured: http://localhost:57772/csp/docbook/docbook.csp 62 Developing Ensemble Productions
Documentation and Comments When running Ensemble Studio, choose the Help menu On-line Documentation option. 2.9.2 Class Reference Information You can supplement the online documentation system with information about the classes you create for an Ensemble production, by placing InterSystems Documatic comments in your class code. These comments automatically appear in the online documentation system under the topic Class Reference Information. You have the opportunity to add Documatic comments each time you create a new class, method, property, or query using an Ensemble Studio wizard. If you enter a block of text in the Description field of the wizard dialog, when you save your changes this text appears in the class in the lines just preceding the Class, Method, Property, or Query label. Studio inserts three slashes (///) at the far left of each line to indicate that it is a Documatic comment, as shown in the following example. /// Sample business metric class for Workflow demo Class Demo.Workflow.WFMetric Extends Ens.BusinessMetric [ ProcedureBlock ] { /// Active Tasks Property ActiveTasks As Ens.DataType.Metric(AUTOHISTORY = 10, RANGELOWER = 0, RANGEUPPER = 50, UNITS = "Tasks") [ MultiDimensional ]; /// Active Load Property Load As Ens.DataType.Metric(AUTOHISTORY = 10, RANGELOWER = 0, RANGEUPPER = 100, THRESHOLDUPPER = 90, UNITS = "%") [ MultiDimensional ]; /// Completed Tasks (since previous day) Property CompletedTasks As Ens.DataType.Metric(AUTOHISTORY = 10, RANGELOWER = 0, RANGEUPPER = 100, UNITS = "Tasks") [ MultiDimensional ]; /// Calculate and update the set of metrics for this class Method OnCalculateMetrics() As %Status { // set the values of our metrics // %Instance is the current instance (RoleName in this case) Set trole =..%Instance Set..ActiveTasks = ##class(enslib.workflow.engine).bamactivetasks(trole) Set..Load = ##class(enslib.workflow.engine).bamactiveload(trole) // Get task since start of previous day Set tstart = $ZDT($H-1,3) Set..CompletedTasks = ##class(enslib.workflow.engine).bamcompletedtasks(trole,tstart) } Quit $$$OK /// Set of instances for this metric class<br> Developing Ensemble Productions 63
Creating a New Production /// There is one instance for every defined role. Query MetricInstances() As %SQLQuery { SELECT Name FROM EnsLib_Workflow.RoleDefinition } } Once you compile a class, you can view its generated class documentation as follows. Either: Start the online documentation system and click the Class Reference Information link, or: Enter the following URL into a browser page on the local Ensemble system, where 1972 is the superserver port number of your Ensemble instance: http://localhost:1972/apps/documatic You can extend Documatic comments from within Ensemble Studio, either by editing the Description field for a class in the Studio Inspector window, or by adding lines preceded by three slashes (///) at appropriate locations within the source file. These lines must appear in a consecutive block immediately before the declaration of the class, method, property, or query that they describe, and the first of the three slashes must appear in the first (left-most) position in the line. Studio handles all of this automatically when you make these changes by editing and saving the Description field in the Inspector window. If you edit Documatic comments directly in the code, Studio alerts you to Documatic errors: for example, if you insert a blank line between the comments and the declaration, or if you use an insufficient number of slashes at the beginning of a line within a Documatic text block. However, Studio does not alert you to any bad HTML or Documatic syntax that you introduce within a line. Documatic comments permit any standard HTML element and a small number of specialized Documatic elements, as shown in the following code sample and output display: With regard to the allowed HTML elements, use as strict an HTML standard as you can, for example XHTML, to ensure that your comments can be interpreted by any browser. For a description of specialized Documatic elements, such as <class>, <method>, <property>, <query>, <parameter>, <example>, and <link>, see the Class Reference Information for %CSP.Documatic. 2.9.3 Hover Text For Production Settings If a property definition in an Ensemble host class provide Documatic comments, and if that property is included in the SETTINGS string for the class, context-sensitive help is automatically available for these properties in the configuration display on the [Ensemble] > [Productions] page. Whenever the user hovers the cursor over a property name in the configuration display, the comment text for that property definition displays as a tooltip. 64 Developing Ensemble Productions
Documentation and Comments 2.9.4 ObjectScript Code Comments Rules for ObjectScript comments apply wherever you use ObjectScript code, including: Ensemble class code Any <code> elements in BPL, when the scripting language for the business process has been identified as objectscript (the default when no language is specified) Any <code> elements in DTL, when the scripting language for the data transformation has been identified as objectscript (the default when no language is specified) The double slash // semicolon ; and pound-semicolon pair #; are all single-line comment indicators in ObjectScript. Everything on the line to the right of the indicator is interpreted as a comment.#; comments are suppressed in the compiled routine. White space can be significant within ObjectScript. In particular, a statement cannot start in the first (left-most) character position on a line. This distinguishes a statement from a label, which does start in first position. Thus, you must make sure whatever comment characters you use are preceded by at least one space on the lines where they appear. For example: Method OnCalculateMetrics() As %Status { // Note: these calculations are not accurate; they // are demonstrative. // set the values of our metrics &sql(select COUNT(*) INTO :count FROM Demo_Loan_Msg.Application) Set..LoansRequested = count // set the values of our metrics &sql(select COUNT(*) INTO :count FROM Demo_Loan_Msg.Approval WHERE IsApproved = 1) Set..LoansApproved = count } Quit $$$OK For further details about white space and comments, see the Syntax Rules chapter in Using Caché ObjectScript. 2.9.5 Caché Basic Code Comments Rules for Caché Basic comments apply wherever you use Caché Basic code, including: Ensemble class code Any <code> elements in BPL, when the scripting language for the business process has been identified as basic Developing Ensemble Productions 65
Creating a New Production Any <code> elements in DTL, when the scripting language for the data transformation has been identified as basic The following example illustrates several uses of the Rem statement and single-quote ' syntax to provide single-line comments in Caché Basic code: Dim MyStr1, MyStr2 MyStr1 = "Hello" : Rem Comment after a statement separated by a colon. MyStr2 = "Goodbye" ' This is also a comment; no colon is needed. Rem Comment on a line with no code; no colon is needed. For further details, see the section Rem in the Caché Basic Commands chapter of the Caché Basic Reference. 2.9.6 Annotations in BPL and DTL BPL and DTL support the <annotation> element for comments that need to be associated with a specific activity within the <process> or <transform> block. The <annotation> element cannot simply appear in any arbitrary location within BPL or DTL. An <annotation> must appear as the child of the element that is annotating. The following example shows a BPL <annotation> element that appears between a beginning <call> tag and an ending </call> tag. This is the correct syntax for annotating a <call> activity. <call name="bankmanana"> <annotation> <![CDATA[Send an asynchronous request to Bank Manana.]]> </annotation> </call> The previous example uses CDATA syntax around the annotation text. This convention is optional, but it lets you use line breaks and special characters such as the apostrophe (') without worrying about XML escape sequences. Note the line break between asynchronous and request in the previous example. This line break is interpreted literally when BPL displays the <call> activity in a BPL diagram. The <annotation> text appears as a commentary on the activity, as follows: BPL <call> Element Showing <annotation> Text Both BPL and DTL support the <annotation> element for their activity elements. For language specific details, see these books: Ensemble Business Process Language Reference 66 Developing Ensemble Productions
Documentation and Comments Ensemble Data Transformation Language Reference 2.9.7 Extended Code Comments in BPL and DTL If the <annotation> element does not offer wide enough scope for the comments you wish to add, it is possible to add extended code comments within BPL and DTL. However, first you need to be aware of the following caution. CAUTION: When adding comments to an XData block, as for BPL or DTL, the Studio code view permits you to enter comments using XML format; that is, <!-- and /--> at the beginning and end of each comment line, but saving or compiling the class in the BPL or DTL diagram view strips out the XML comments. The Ensemble Business Process Language (BPL) offers a <code> element that executes one or more lines of code within a BPL business process. Typically, a developer wraps the contents of a <code> element in a CDATA block to avoid having to worry about escaping special XML characters such as the apostrophe (') or the ampersand (&). The <code> block is also useful to provide extended, permanent comments within BPL and DTL code. Comments within the <code> block must uphold the conventions of the scripting language that the <code> block is using. This language can be Caché Basic or ObjectScript. The language is specified by the containing BPL <process> element. If no language is specified, ObjectScript is assumed. The following are two simple examples: Caché Basic: <code><![cdata[ 'Here are some 'code comments 'in Basic ]]></code> ObjectScript: <code><![cdata[ // Here are some // code comments // in ObjectScript ]]></code> The Ensemble Data Transformation Language (DTL) offers a similar <code> element that executes one or more lines of code within a DTL data transformation. The language within a DTL <code> element can be Caché Basic or ObjectScript. The language is specified by the containing DTL <transform> element. If no language is specified, ObjectScript is assumed. Developing Ensemble Productions 67
Creating a New Production 2.10 Ensemble Studio The book Using Caché Studio documents the Studio features that the Ensemble and Caché products share. This section and the Using the New Production Wizard section earlier in this chapter describe the additional features that are unique to Ensemble. You can: Use Studio to write and compile code. Generate code from within Studio by drawing business processes with the Business Process Language (BPL) Visual Editor. Generate code from within Studio by building data transformations with the Data Transformation Language (DTL) Visual Editor. Open Studio to examine or edit the source code of any element within your Ensemble production. Find an element within your preferred view of the source code as a production, as a software package, or as the contents of a namespace. Use Studio to switch easily between various views of production elements. One of the requirements for graphical features of Studio to work is for the SVG Viewer 3.0 to be installed on the system that is running Ensemble. If you encounter any problems, double-check your installation by looking for SVG Viewer under the Adobe products installation folder. 2.10.1 Starting Studio To start Studio, do one of the following: From the Windows system tray, click on the list of options. Ensemble cube icon and select Studio from the From the Windows Start menu, choose Programs, then Ensemble (identifying the InterSystems product folder), then ENSEMBLE (or another name if you chose it at installation) and finally Studio. The Ensemble features of Studio become active whenever Studio is connected to an Ensemble-enabled namespace. For more information, see the Namespaces section in the chapter Production Concepts. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. To connect Studio with an Ensemble namespace: 68 Developing Ensemble Productions
Ensemble Studio 1. From the File menu, choose Change Namespace. 2. The Connection Manager window displays: Choose a Server Connection and Namespace (choose an Ensemble namespace). If necessary, enter the Username and Password for that namespace and server. Click OK to save your changes, Cancel to cancel them. The Cache Connection Manager window closes. 3. If you clicked OK in step 2, the Workspace window now displays the contents of the namespace you selected. 2.10.2 The New Class Window In Studio, when you want to create a new class, select the File menu New option. The New window displays so that you can select the type of class to create. Several tabs organize the New window. These include the General, CSP, and Custom tabs. When Studio is connected to an Ensemble namespace, the Production and Message tabs also display. To create an new class for an Ensemble namespace, choose File > New, click the Production tab and double-click one of the icons. A class creation wizard leads you through the steps to create the class. The classes available on the Production tab are: Business Service Business Process Business Operation Adapter (includes Inbound or Outbound adapters) Production Data Transformation Business Metric To create an Ensemble message class, choose the Messages tab and double-click the Message icon. 2.10.3 The Workspace Window The Studio Workspace window has four display tabs: Project, Windows, Namespace, or Production. Each tab has a different way of ordering and prioritizing the contents of the currently selected namespace. The following description lists them from bottom to top: Developing Ensemble Productions 69
Creating a New Production Production This tab is available only if the currently selected namespace is an Ensemble namespace. It lists host classes for items that can be members of a production. The labels for entries on the Production tab are as follows. Label Adapters Business Operations Business Processes Business Services Data Transformations Messages Productions Dashboards All classes listed under this label are subclasses of... Ens.Adapter, including inbound and outbound adapters. Ens.BusinessOperation. Ens.BusinessProcess. Ens.BusinessService. Ens.DataTransform. Ens.Request or Ens.Response. Ens.Production. Ens.Dashboard. Project This is a collection of files that the user selects for convenience. When any file in this list is updated, Studio displays a notification message to the user. Windows Lists any class or file that the Studio user has open in the currently selected namespace. If you double-click on a name in this list, the window containing that file pops to the top in the Studio window. Namespace Lists every file in the currently selected namespace. This tab does not update in real time; to update it, select the namespace name at the top of the tab, right-click, and from the context menu choose Refresh. The labels for entries on the Namespace tab are as follows: 70 Developing Ensemble Productions
Ensemble Studio Label Classes Routines CSP Files Other Entries Every class in the namespace, organized by package. Every file relating to routines in the namespace. Every file relating the CSP applications in the namespace. Everything else, including files that contain XML-based definitions for the following production components: - The XData block for business processes (.BPL) - The XData block for data transformation (.DTL) - The rule definition for business rules (.RUL) - Custom schema definitions for message routing (.HL7,.AST, and others) 2.10.4 Starting the Management Portal from Studio You can start the Ensemble Management Portal from Studio as follows: 1. Be sure that Studio is connected with an Ensemble namespace. 2. Choose the Utilities menu Ensemble Management option. A browser window opens and the Ensemble Management Portal login page displays. 3. Under the login page title bar is a display area that contains a dialog box and a prompt to Please login. The dialog box provides Username and Password fields. Enter the username and password for a user account defined in the namespace you chose in Step 1. The default login for any namespace is the username _SYSTEM with a password of SYS. 4. Click Login. The [Ensemble] home page displays. Developing Ensemble Productions 71
3 Ensemble Messages All communication that occurs inside Ensemble is accomplished using messages. The chapter Production Concepts stated the basic rules of behavior for Ensemble messages: Every message is a request or a response. Requests and responses are defined in pairs. A request may have one associated response, or no associated response. Any request may be sent synchronously (the caller waits for the response before continuing) or asynchronously (the caller does not wait). The business host that sends the request must indicate this choice and handle the result. Any request that is sent synchronously must have a designated response type. The flow of control could vary considerably each time a request is sent, depending on a variety of factors including: - The type of request being sent. - Whether or not each request involves waiting (or not waiting) for a response. - Whether or not expected responses are actually received. - The values returned with any responses. This chapter discusses Ensemble message objects in detail. This information applies to all types of Ensemble production, whether the primary purpose of the production is to route messages or to connect applications. If you plan to use Ensemble specifically for message routing that is, to use Ensemble as a dedicated interface engine also see the chapter Message Routing. Developing Ensemble Productions 73
Ensemble Messages Ensemble Message Object with a Standard Message Body Every Ensemble message is a persistent object in two parts: The message header contains the information needed to route the message within Ensemble. The message body contains the message data. The message header and message body are each persistent objects in their own right. Ensemble automatically instantiates and populates a message header object whenever an Ensemble business host invokes a method to send a message. The specific method and the values of its parameters indicate to Ensemble where the message is heading, whether or not it is a request or a response message, when it was sent, where to return a response, and whether or not to handle responses synchronously or asynchronously. Properties on the message header object identify the class and object ID of the message body object. Ensemble records all of this information in the persistent message header object so that it is available to be retrieved by any elements of the Ensemble infrastructure that need it: Message Browser, Monitor, Event Log, Visual Trace, and so on. 74 Developing Ensemble Productions
Message Body An Ensemble developer defines message body classes as needed by an Ensemble production. A standard message body class simply extends one of the built-in message body classes Ens.Request or Ens.Response by defining properties to contain the message data. 3.1 Message Body In theory, a message body may be any persistent or serial object. In practice, most developers simply add properties to extend Ens.Request or Ens.Response. This creates the standard message body shown in the diagram at the beginning of this chapter. Use of Ens.Request or Ens.Response ensures that the new message class supports various built-in features for viewing the contents of messages from the Ensemble Management Portal. These features help developers and administrators detect errors in a running production, especially if the production uses message content to determine where the message should be sent. Most of the examples in this book assume a standard message body, with a relatively small number of message properties. Suppose that you work with electronic documents Electronic Data Interchange (EDI) formats such as HL7 or X12 whose data is arbitrarily long and complex. Hundreds of properties may be required to fully describe only one such document, yet the structure may vary from message to message. To address these issues, Ensemble offers a category of message called a virtual document, which allows you to send an electronic document as a message body, without constructing the entire contents of the message as a formal set of properties, as you would need to do for a standard message object. Virtual documents do not extend Ens.Request or Ens.Response, but they do offer ways to view and change data within the document based on a stored schema definition. Each type of virtual document that Ensemble supports has a message body class, schema, and documentation dedicated to it. For details, see Ensemble Virtual Documents. 3.2 Synchronous and Asynchronous Messages Any request message can be sent as follows: Synchronously The caller stops all processing to wait for the response. Asynchronously The caller does not wait; immediately after sending the request the caller resumes other processing. When sending a request asynchronously, the caller specifies one of two options regarding the response to this request: - Ask to receive the response when it arrives. - Ignore the possibility of a response. Developing Ensemble Productions 75
Ensemble Messages The choice of how to send a message is not recorded in the message itself. The host class that sends a request decides whether to send the request synchronously or asynchronously: For a host class written using custom code, the class makes the call using its SendRequestSync method, or its SendRequestAsync method. This choice sets a flag in the message header to a value of synchronous or asynchronous. You cannot change or reconfigure this value once the production is running. Alternatively, if the host class is a business process that has been written using the Ensemble Business Process Language (BPL), the class makes the call using a BPL <call> statement. The <call> element has a required attribute called async that can be 1 (true) or 0 (false). When programming Ensemble business processes, you can use the Ensemble Business Process Language (BPL) or your own custom code. The Business Processes chapter documents both approaches. When making this choice, be aware of a key advantage of using BPL: It handles every aspect of synchronous and asynchronous messaging in a streamlined and elegant way that prevents common problems with contention and deadlocks. Even when a call is marked synchronous, if any wait time is required, the Ensemble framework quietly frees the job that was executing the call on behalf of the BPL business process so that it can do other work while BPL waits for the synchronous response. Later on, the framework silently coordinates receipt of the synchronous response and wakes up the BPL business process to resume its work. If you use custom code, it is very easy to design a production prone to deadlock. All you need to do is to create a sequence of business processes that send synchronous requests and use a limited actor pool. If the production then receives the same number of messages as actors, and a synchronous send occurs simultaneously for all the messages, the production ends up in a deadlock where all the actor processes are in the state of waiting for another process to release messages from queues. The most dangerous aspect of this issue is that testing does not necessarily produce the conditions that cause the deadlock. It is quite possible that the deadlock will first be encountered after deployment. At this point it will not be clear why Ensemble has seized up, and the costs of this unforeseen problem may be high. To avoid problems in making synchronous calls, InterSystems recommends that you use BPL. 3.3 Deferred Response In addition to the straightforward alternatives of synchronous (wait) and asynchronous (do not wait), it is possible to send messages outside Ensemble using a convention called deferred response. Suppose a business process wishes to invoke an action outside Ensemble. It sends a request to a business operation, which performs the invocation and returns the response. The business process is the intended recipient of any response; the business operation is simply the means by which the request goes out and the response comes in. The business operation will relay a response back if the business process 76 Developing Ensemble Productions
made the request synchronously, or if it made the request asynchronously with asynchronous response requested. The following diagram summarizes this convention. Typical Request and Response Deferred Response Now suppose the business operation that receives a request from a business process has been written to use the deferred response feature. The original sender is unaware of the fact that the response is going to be deferred by the business operation. Deferring the response is a design decision made by the developer of the business operation. If the business operation does in fact defer the response, when the original sender receives the response at the end of the deferral period, it is unaware that the response was ever deferred. A business operation defers a response by calling its DeferResponse method to generate a token that represents the original sender and the original request. The business operation must also find a way to communicate this token to the external entity so that it can include this token in any later responses into Ensemble. For example, if the external destination is email, a business operation can include the token string in the subject line of the outgoing email. The entity receiving this email can extract this token from the request subject line and use it in the response subject line. In the following diagram, the item t represents this token. Between the time when the business operation defers the request, and when the response is finally received by the original sender, the request message has a status of Deferred. The Deferred status is an alternative to other status values such as Created, Queued, Delivered, Completed, Discarded, or Suspended. After the original sender receives the corresponding response, the request message status changes from Deferred to Completed. An incoming event in response to the request can be picked up and returned to the original sender by any business host in the production. Exactly where the event arrives in Ensemble depends on the design of the production; typically, it is the task of a business service to receive incoming events from outside Ensemble. The business host that receives the incoming event must also receive the deferred response token with the event. The business host then calls its SendDeferredResponse method to construct the Developing Ensemble Productions 77
Ensemble Messages appropriate response message from the incoming event data and direct this response to the original sender. The original sender receives the response without any knowledge of how it was returned. Request and Deferred Response 3.4 Primary Requests and Responses The original request that causes a business service, business process, or business operation to instantiate and perform work is known as the primary request for that business service, business process, or business operation. Like all requests, a primary request may be synchronous or asynchronous. A primary request may have one primary response associated with it, or it may have no associated response. The business service, business process, or business operation that receives the primary request may generate subsequent requests to other business hosts to fulfill the primary request, or it may do the work internally. Either way, before it completes execution, the business service, business process, or business operation that receives the primary request must return the associated primary response. 78 Developing Ensemble Productions
Sessions 3.5 Sessions In Ensemble messaging terms, a session marks the beginning and end of all the activities prompted by a primary request message initiated from outside Ensemble. A session exists from the moment the primary request enters Ensemble, usually via a business service. The session continues to exist while the production generates internal requests and responses to process the primary request. When the last internal activity prompted by the primary request is done, the session is over. If the primary request required a response, the final act that the production performs within the session is to formulate and send this response. The session ID is the unique identifier for the session that is (or was) associated with a message. Several additional messages may be instantiated within Ensemble during the session, in order to fulfill the primary request. Each of these messages has a different Message ID value, but all of them share the same session ID. When tracking messages on the Ensemble Management Portal, you can use the Session ID to trace the activities spawned by the primary request message all the way through the production. 3.6 Queues The Ensemble messaging system is designed to satisfy the following goals: Ensure that every message is processed as promptly as needed. Ensure failure resilience for itself, and guarantee failure recovery for the overall system. Allow time-averaging of the system load, by letting messages queue up occasionally. Minimize traffic to the extent necessary to avoid slowing down the overall system. To ensure these goals, Ensemble provides a system of queues to handle message delivery. No queue setup is required. Ensemble manages all queues automatically. In Ensemble terms, a queue is simply a list of message objects waiting to be processed by a business host a business service, a business process, or a business operation within a production. Ensemble manages queues as follows: A production offers one shared queue called Ens.Actor. This single, public queue is the target of any messages sent to any business process within a production that does not have its own, private queue. Each message on the Ens.Actor queue is waiting for one of the jobs in the public actor pool (an actor ) to become free. When an actor becomes free, Ensemble retrieves the next message from the Ens.Actor queue and allocates the actor to host any actions prompted by the message. Each individual business service and business operation has its own private queue, which is the target for all the Ensemble messages sent to that business service or business operation. Each Developing Ensemble Productions 79
Ensemble Messages message on a private queue is waiting for one of the jobs in the item s own pool to become free. When this happens, Ensemble retrieves the next message from the item s private queue and allocates the job to the service or operation to host any actions prompted by the message. Unlike other types of business host, business processes can be configured either to use jobs from the public actor pool or use jobs from a private pool such as services and operations have. Any non-zero value for the business process Pool Size ensures that the business process only uses jobs from its private pool. You may set this pool at sizes from 1 to 100. If you want a business process to use jobs from the public actor pool, you must set its private Pool Size to 0. For further advice, see the Pool Size section in the chapter Production Concepts. 3.7 Message Header The message header contains the same fields for every message. These fields include: ObjectId The object identifier for the message header. Whenever a message header and message body are combined together as a message, the ObjectId value in the header is used to identify the combined message object. As a result, this value is the same as the message ID listed on the [Ensemble] > [Messages] page and other pages in the Ensemble Management Portal. Type The message type, Request or Response. Priority The priority of the message relative to others in the queue: RealTime (1), High (2), Normal (3), or Low (4). The Ensemble messaging engine assigns priority values to messages automatically, in the course of normal processing, for its own use. Message priority cannot be programmed into a message class or configured in any way. Priority values are based in part on whether the message is synchronous (High) or asynchronous (Normal). Also, messages that start or stop a production are assigned greater priority than other types of message. Invocation The style of invocation for message: Queue or Inproc. Inproc means the message will be formulated, sent, and delivered in the same job in which it was created. The job will not be released to the sender s pool until the message is delivered to the target. Queue means the message is created in one job, then placed on a queue, at which time the original job is released. Later, when the message is processed, a different job will be allocated for the task. Description A text description of the message. The Ensemble Business Process Language (BPL) provides text in this field automatically, based on the type of BPL activity that generated the message. TimeCreated A Queue message lists the time the message was placed on the queue. An Inproc message lists the time the Send method was called. 80 Developing Ensemble Productions
TimeProcessed A Queue message lists the time the message was taken off the queue to be processed. An Inproc message lists when processing of the message began; for Inproc messages, TimeProcessed will be very close to TimeCreated. Status Indicates the status of the message within its normal life-cycle: Created, Queued, Delivered, Deferred, Completed, Discarded, or Suspended. If there is a request-response pair, the value does not indicate an overall status for the pair; a request may end up with a different Status from its corresponding response. A message in transit has a Status of Created, until it finds its place on a queue, when it becomes Queued. A message that reaches its destination is at first Delivered, then finally Completed. An asynchronous response is Discarded if it arrives after the timeout period for the corresponding request expired. A message response can been Deferred by a business operation to be sent later on; when a Deferred message is finally sent, it has a Status of Completed. Some business operations are designed to set the status of any failed messages to Suspended; such a message goes on a special queue where Ensemble keeps all Suspended messages. Later, a system administrator can use the Ensemble Management Portal to diagnose the problem, and resend Suspended messages after the problem is fixed. For example, if the problem is on the external side of the communication, the external system can be repaired, and then the message can be resent. IsError An integer value of 1 means that IsError is true; the message encountered an error. A value of 0 means IsError is false; the message did not encounter any errors. ErrorStatus If IsError is 1, then this is the text associated with the error. When IsError is 0, ErrorStatus is the string OK. CorrespondingMessageId If the message Type is a Response, this field contains the ObjectId of the corresponding request. If the message Type is a Request, this field contains the ObjectId of the corresponding response (if any) or it is blank. SessionId The unique identifier for the session that is (or was) associated with this message. A session marks the beginning and end of all the activities prompted by a primary request message from outside Ensemble. The primary request message has an ID value that is identical to the SessionId. Several additional messages may be instantiated within Ensemble during the session, in order to fulfill the primary request. All of these messages share the same SessionId, but each has a different ID value. SourceConfigName The name of the configuration item that sent the message. Message Header TargetConfigName The name of the configuration item that was intended to receive the message. SourceBusinessType BusinessService, BusinessProcess, BusinessOperation, or Unknown. TargetBusinessType BusinessService, BusinessProcess, BusinessOperation, or Unknown. BusinessProcessId Every business process that gets executed has an instance and this is the object ID of that instance. If the message is a request, this field identifies the business process in Developing Ensemble Productions 81
Ensemble Messages whose context the message was created (sender). If the message is a response, this field identifies the business process to which it is being returned (receiver). This field is empty in various circumstances, for example if an error occurred. TargetQueueName The destination address for the message: Where is it going? The TargetQueueName may be a name or a number. A name identifies a public queue, such as Ens.Actor for business processes. A number is the job ID associated with the private queue of a business service, business process, or business operation. ReturnQueueName The return address for the message: Where did it come from? The ReturnQueueName may be a name or a number. A name identifies a public queue, such as Ens.Actor for business processes. A number is the job ID associated with the private queue of a business service, business process, or business operation. The ReturnQueueId value is listed even if there is no response expected or needed for a particular request message type. MessageBodyClassName The class name of the message body. MessageBodyId The object identifier for the message body. This field matches the ObjectId field in the Message Body table. 3.8 Creating a Standard Message Body Class A standard Ensemble message class is simply a class derived from either Ens.Request or Ens.Response. By extending these built-in classes as instructed in this section, you enable the data within the message to be displayed in the Ensemble Management Portal as described in the book Managing Ensemble Productions. The easiest way to create a new message class is to use Ensemble Studio, as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Messages tab. 4. Select the Message icon and click OK. 5. Enter a package and class name for the message. Click Next. 82 Developing Ensemble Productions
Creating a Standard Message Body Class Important: InterSystems recommends that you do not use the package names Demo, Ens, EnsLib, EnsPortal, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 6. For Message Type, choose Request or Response. 7. Enter and edit Properties using the table. To add, reorder or delete properties, click the icons to the right of the table. Each time you click the Add icon, a dialog prompts you as follows: Enter the property Name. Enter a data Type or choose one by clicking the Browse icon to the right of this field. Enter a text Description of the property. Click OK to save the property definition or Cancel to ignore it. 8. Click Finish to save your new message definition or Cancel to discard it. The resulting message class looks something like this: Class Demo.Loan.Msg.CreditRatingResponse Extends Ens.Response [ ClassType = persistent, ProcedureBlock ] { Property TaxID As %String; Property CreditRating As %Integer; } It is also possible to use methods in a message class. For example: Class Demo.Loan.Msg.Application Extends Ens.Request [ ClassType = persistent, ProcedureBlock ] { Property Amount As %Integer; Property Name As %String; Property TaxID As %String; Property Nationality As %String; Property BusinessOperationType As %String; Property Destination As %String; Method RecordNumber() As %String { If..%Id()="" Do..%Save() } Quit..%Id() Method GetRecordNumberText(pFormatAsHTML As %Boolean = 0) As %String { Set tcrlf=$s(pformatashtml:"<br>",1:$c(13,10)) Set ttext="" Set ttext=ttext_"your loan application has been received,"_tcrlf Set ttext=ttext_"and is being processed."_tcrlf Set ttext=ttext_"your record number is "_..RecordNumber()_"."_tCRLF Set ttext=ttext_"you'll receive a reply from FindRate"_tCRLF Set ttext=ttext_"within 2 business days."_tcrlf Developing Ensemble Productions 83
Ensemble Messages } } Set ttext=ttext_"thank you for applying with FindRate."_tCRLF Quit ttext 84 Developing Ensemble Productions
4 Inbound Adapters An inbound adapter is responsible for receiving and validating requests from external systems. Inbound adapter classes work in conjunction with a business service classes. In general, the inbound adapter contains general-purpose, reusable code while the business service will contain productionspecific code (such as special validation logic). Typically you will implement inbound adapter classes using one of Ensemble s built-in adapter classes. Developing Ensemble Productions 85
Inbound Adapters How a Production Accepts Incoming Requests A request can enter an Ensemble production in one of two ways. Both are shown in the previous figure: In general, when an external application makes a request for a certain action to be performed, the request comes into Ensemble via an inbound adapter, as shown in the previous figure. The requesting application is called a client application, because it has asked the production to do something. This application is a client of the production. The featured element at this step is the inbound adapter. This is a piece of code that adapts the client s native request format to a one that is understandable to the production. Each application that makes requests of a production must have its own inbound adapter. No change to the client application code is needed, because the adapter handles calls that are already native to the client application. It is possible for a composite application to bypass an inbound adapter and make a request to a business service directly. A composite application consists of a user interface (outside Ensemble) plus business logic (inside Ensemble). No inbound adapter is needed, because the composite application makes requests into the production in a format that is already understandable to the production. Composite applications can be written to invoke business services or business processes. 86 Developing Ensemble Productions
Inbound Adapter Life Cycle 4.1 Inbound Adapter Life Cycle The life cycle of an inbound adapter object is intertwined with that of its associated business service object. When a production starts up, the following events related to inbound adapters occur: 1. When a production starts, it creates a background process for each of its configured business services (there may be more than one process per business service as specified by its configured PoolSize property). 2. Within each background process, an instance of the business service class is created. 3. After the business service object is created, an instance of its related inbound adapter class is created. 4. The values of any configurable properties of the inbound adapter object are set using the values specified by the production definition. 5. The running instance of the business service calls the inbound adapter s OnInit method. While the production is running: 1. The business service repeatedly calls the inbound adapter s OnTask method, at intervals determined by the inbound adapter s CallInterval setting. 2. OnTask checks outside Ensemble for input events of interest to the business service. 3. If OnTask finds an input event, it packages the information from this event as an object of the type expected by the business service and calls the ProcessInput method of the business service. 4. Multiple input events may exist. For example, if the business service is using File.InboundAdapter there may be several files waiting in the designated directory. If there are multiple input events: Typically, the OnTask method calls ProcessInput as many times as is necessary to process all the available input events until no more are found. Then OnTask goes to sleep waiting for the next CallInterval to elapse. Alternatively, an inbound adapter can restrict OnTask to call ProcessInput only once per CallInterval, even if multiple input events exist. Rather than processing all the input events, OnTask goes to sleep after processing the first event found. For details, see the Business Service Life Cycle section in the chapter Business Services. An Ensemble production continues running until it is stopped, either programmatically or by an administrator using the Ensemble Management Portal. When a production stops, the following events related to inbound adapters occur: Developing Ensemble Productions 87
Inbound Adapters 1. Ensemble disables each business service; no more incoming requests are accepted for this production. 2. The OnTearDown method in each inbound adapter is called. 3. All inbound adapter and business service objects are destroyed and their background processes are killed. 4. Each business service s OnProductionStop class method is called, once for each configured item of that class in the production. When a business service is disabled by a system administrator, or becomes inactive according to its configured schedule, the production continues to run but the associated inbound adapter is shut down, and its OnTearDown method is executed. 4.2 Inbound Adapter Methods At minimum, an inbound adapter class contains the following operation methods: OnInit, OnTearDown, and OnTask. 4.2.1 The OnInit Method An inbound adapter class may override the OnInit method. This method is called after the inbound adapter object has been created and its configurable property values have been set. The OnInit method provides a way for an inbound adapter to perform any special setup actions. For example, the following OnInit method establishes a connection to an input device when the inbound adapter is started assuming that this inbound adapter also implements a ConnectToDevice method: Method OnInit() As %Status { // Establish a connection to the input device Set tsc =..ConnectToDevice() Quit tsc } 4.2.2 The OnTearDown Method An inbound adapter class may override the OnTearDown method. This method is called during shutdown before the inbound adapter object is destroyed. The OnTearDown method provides a way for an inbound adapter to perform any special cleanup actions. For example, the following OnTearDown method closes a connection to an input device when the inbound adapter is stopped (assuming that this inbound adapter also implements a CloseDevice method): 88 Developing Ensemble Productions
Inbound Adapter Methods Method OnTearDown() As %Status { // close the input device Set tsc =..CloseDevice() Quit tsc } 4.2.3 The OnTask Method The OnTask method is where the actual work of the inbound adapter takes place. Once a production starts, each business service periodically calls the OnTask method of its associated inbound adapter class. Most inbound adapters have a configurable settings parameter called CallInterval that controls the time interval between calls to OnTask. You set the value for CallInterval when you configure Specific Settings for the business service using the configuration display on the Ensemble Management Portal [Ensemble] > [Productions] page. The OnTask method is intended to do the following things: 1. Check for an incoming event. The inbound adapter can do this in many different ways: For example, it could wait for an incoming I/O event (such as reading from a TCP socket), or it could periodically poll for the existence of external data (such as a file). 2. Package the information from this event into an object of the type expected by the business service class. 3. Invoke the ProcessInput method of the business service object. 4. If necessary, send an acknowledgement back to external system that the event was received. 5. If there is more input data, OnTask can either: Call ProcessInput repeatedly until all the data is retrieved; or Restrict itself to calling ProcessInput only once per CallInterval, even if multiple input events exist. For details, see the Business Service Life Cycle section in the chapter Business Services. When designing an inbound adapter, it is important to keep in mind that the OnTask method must periodically return control to the business service; that is, the OnTask method must not wait indefinitely for an incoming event. It should, instead, wait for some period of time (say 10 seconds) and return control to the business service. The reason for this is that the business service object must periodically check for events from within Ensemble, such as notification that the production is being shut down. Conversely, it is also important that the OnTask method waits for events efficiently sitting in a tight loop polling for events will waste CPU cycles and slow down an entire production. When an OnTask method needs to wait it should do this in such a way as to let its process go to sleep (such as waiting on an I/O event, or using the Hang command). The following is a very simple example of an OnTask method: Developing Ensemble Productions 89
Inbound Adapters Method OnTask() As %Status { #; First, receive a message (note, timeout is in ms) Set msg =..ReceiveMessage(..CallInterval*1000,.tSC) If ($IsObject(msg)) { Set tsc=..businesshost.processinput(msg) } } Quit tsc If your inbound adapter class is a subclass of one of the built-in adapters provided by the Ensemble adapter library, then it is likely that the library class will implement the OnTask method; therefore, your subclass might need to override a different method as specified by the inbound adapter class. 4.3 Creating a New Inbound Adapter Class An inbound adapter is simply a class derived from the Ens.InboundAdapter class. The easiest way to create a new inbound adapter class is to use Ensemble Studio, as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Adapter icon and click OK. 5. Enter a package and class name for the inbound adapter. Click Next. Important: InterSystems recommends that you do not Demo, Ens, EnsLib, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 6. For Adapter Type, choose Inbound. 7. Enter and edit Properties using the table. To add, reorder or delete properties, click the icons to the right of the table. Each time you click the Add icon, a dialog prompts you as follows: Enter the property Name. If you want this property to be editable from the configuration display on the Ensemble Management Portal [Ensemble] > [Productions] page, select the Configurable check box to the right of the Name field. 90 Developing Ensemble Productions
Enter a data Type or choose one by clicking the Browse icon to the right of this field. Enter a text Description of the property. Click OK to save the property definition or Cancel to ignore it. 8. Click Finish to save your new inbound adapter definition or Cancel to discard it. The resulting inbound adapter class will look something like this: Class MyProduction.InboundAdapter Extends Ens.InboundAdapter [ ProcedureBlock ] { Parameter SETTINGS = "IPAddress,TimeOut"; Property IPAddress As %String(MAXLEN=100); Property TimeOut As %Integer(MINVAL=0, MAXVAL=10); Property Counter As %Integer; } Creating a New Inbound Adapter Class An inbound adapter class can define both configurable properties (like IPAddress and TimeOut in the previous example) and non-configurable properties (like Counter in the previous example). To make a property configurable, simply add its name to the comma-delimited list of properties in the value of the class s SETTINGS parameter. The configuration display on the [Ensemble] > [Productions] page automatically provides the user interface needed to view and edit the configurable properties. For details, see the Configuration Settings section in the chapter Production Concepts. To fully implement an inbound adapter class, you must implement one or more of its callback methods, such as the OnTask method. Developing Ensemble Productions 91
5 Business Services A business service is responsible for accepting requests from external applications into Ensemble. Developing Ensemble Productions 93
Business Services How a Production Relays Incoming Requests A business service is responsible for the following activities: Waiting for a specific external event (such as notification from an application, receipt of a TCP message, etc.). Reading, parsing, and validating the data accompanying such an event, Returning, if required, an acknowledgement to the external application indicating that the event was received, Constructing an instance of an Ensemble request object (a subclass of the Ens.Request class) and forwarding it on to the appropriate business process or business operation for processing. 94 Developing Ensemble Productions
Within a business service, the actual mechanics of receiving an event is typically delegated to an inbound adapter class. Factoring this behavior into two classes makes it easier to separate the productionspecific logic within the business service class from the more generic, technology-specific logic of the inbound adapter class. Typically the simpler business service classes are custom written for a production, while the (typically) more complex inbound adapters are provided as reusable components within the Ensemble library. The purpose of a business service is to receive data input. In most cases, a business service has an inbound adapter associated with it. However, in some cases an adapter is not required, either because an application is capable of sending Ensemble request messages into the service or because the business service has been written to handle external calls of a particular kind, for example from a composite application. A business service of this type is called an adapterless business service. When a business service has an inbound adapter, it is in the data pulling (as opposed to pushing ) mode. In this mode, the business service polls the adapter at regular intervals to see if it has data. Meanwhile, if the adapter encounters input data at any time, it calls upon the business service to process the input. By these two mechanisms, data enters the system. When a business service does not have an adapter, it does not pull data. Client applications call the business service and tell it to process input (this is a data pushing mode). When a business service receives data input, it uses the data to generate a primary request message. The business service supervises fulfillment of the request by invoking various business processes, business operations, and data transformations as needed. The business service can provide methods to accomplish work internal to itself. It can make calls as needed to the Ensemble storage engine or other internal facilities. Like all production entities, the business service writes entries to the event logs and message store for the production. A developer can write the business service to make explicit entries in the event log as well. As the business service generates the primary request, it assigns this request a unique session ID. This session ID marks all subsequent messages that are invoked to fulfill the primary request. The session ID is important in managing a production, because if anything goes wrong with the fulfillment of a primary request, the same session ID is present in the record of all subsequent, internal messages associated with that request. With one click on the Ensemble Management Portal screen, a system administrator can instantly display the full set of associated messages. All that is required is to filter the message display based on the session ID. Ensemble uses a specialized type of business service called a business metric to store the values that it displays using dashboards. For an overview of this type of business service, see the Business Activity Monitoring section in the chapter Business Logic. For full details, see the book Using Dashboards with Ensemble. Developing Ensemble Productions 95
Business Services 5.1 Business Service Life Cycle Ensemble automatically manages the life cycle of each business service. When you start a production (or change the configuration of a specific business service), Ensemble automatically performs the following tasks for each configured business service class (that is, for every business service listed in the production definition): 1. Ensemble invokes the business service s OnProductionStart callback method, if defined. The OnProductionStart method is a class method that is invoked once for each business service class listed in the production configuration. A business service class can use this callback to perform any class-wide initialization it may require. 2. Ensemble creates one or more background processes in which to execute the business service. The number of background processes is determined by the business service s PoolSize property within the production configuration. Each background process is referred to as an instance of the business service and contains an instance of a business service object. Ensemble will only create a background process for a business service if the following conditions are true: The business service class must have an associated inbound adapter class as specified by its ADAPTER class parameter. A business service class with no associated inbound adapter is referred to as an adapterless service. Instead of waiting for external events, such a service is invoked in-process (perhaps by a composite application). The business service s Enabled property within the production configuration must be set to 1 (otherwise the business service is considered to be disabled and will not accept input). The business service s PoolSize property within the production configuration must be set to a value greater than 0. If the business service s Foreground property within the production configuration is set to 1, then Ensemble will create a foreground process (that is, Ensemble will create a Terminal window) for the business service. This feature facilitates testing and debugging. 3. Ensemble initializes the system monitoring information used to monitor the status and operating history of the business service. 4. Within each background process: a. Ensemble creates an instance of the business service class, supplies the most recently configured values of any of the business service s configurable properties (those defined as configurable using the SETTINGS parameter), and invokes the business service OnInit callback 96 Developing Ensemble Productions
Business Service Life Cycle method (if present). The OnInit method is an instance method that provides a convenient place to execute any initialization logic for a business service. b. Ensemble creates an instance of the associated inbound adapter class (if one is defined) and supplies the most recently configured values of any of the inbound adapter s configurable properties (those defined as configurable using the SETTINGS parameter). While the production is running, the business service repeatedly calls the inbound adapter s OnTask method. This OnTask loop is controlled by the business service s CallInterval setting and %WaitForNextCallInterval property as follows: 1. The business service calls the inbound adapter s OnTask method. 2. OnTask checks outside Ensemble for input events of interest to the business service: If it finds input, OnTask calls the ProcessInput method of the associated business service object. If it does not find input, OnTask goes to sleep. Control returns to the business service, which waits for the next CallInterval to elapse before returning to step 1. 3. ProcessInput sets the business service %WaitForNextCallInterval property to 0 (false) and calls OnProcessInput to handle the input event. Upon completion, ProcessInput returns control to OnTask. 4. At this point, OnTask may set %WaitForNextCallInterval to 1 (true). This restricts the business service to processing only one input event per CallInterval, even when multiple input events exist. Usually you want the business service to process all available input events without delay, so usually you do not want to do anything to change %WaitForNextCallInterval at this step. It should retain the 0 (false) value set by ProcessInput. The adapter base class Ens.InboundAdapter has an OnTask method that calls ProcessInput, sets %WaitForNextCallInterval to 1, and exits. If you simply want a business service to wake up and run its ProcessInput method once per CallInterval without concern for events outside Ensemble, assign it to the adapter class Ens.InboundAdapter. 5. OnTask exits. 6. The business service tests the value of its %WaitForNextCallInterval property: If 1 (true) OnTask goes to sleep. The business service waits for the CallInterval to elapse before returning to step 1. If 0 (false) the business service immediately returns to step 1. The CallInterval will not come into play until OnTask discovers there is no more input (see step 2). Developing Ensemble Productions 97
Business Services An Ensemble production continues running until it is stopped, either programmatically or by an administrator using the Ensemble Management Portal. When a production stops, the following events related to business services occur: 1. Ensemble disables each business service; no more incoming requests are accepted for this production. 2. The OnTearDown method in each inbound adapter is called. 3. All inbound adapter and business service objects are destroyed and their background processes are killed. 4. Each business service s OnProductionStop class method is called, once for each configured item of that class in the production. When a business service is disabled by a system administrator, or becomes inactive according to its configured schedule, the production continues to run but the associated inbound adapter is shut down, and its OnTearDown method is executed. 5.2 Business Service Methods At minimum, a business service class contains the following operation methods: OnInit, OnTearDown, OnProductionStart, OnProductionStop, and OnProcessInput. A business service class also provides methods to send messages to business processes or business operations, as follows: SendRequestSync sends a message synchronously (waits for a response), SendRequestAsync sends a message asynchronously (does not wait for a response), and SendDeferredResponse sends a response that was previously deferred by a business operation. Finally, for custom business services that determine their message targets at runtime rather than at configuration time, the OnGetConnections method is available to tell the Ensemble internal framework which configuration items are the targets of this business service. 5.2.1 The OnInit Method A business service class may override the OnInit method. This method is called after the business service object has been created and its configurable property values have been set. The OnInit method provides a way for a business service to perform any special setup actions. Method OnInit() As %Status { Quit $$$OK } 98 Developing Ensemble Productions
Business Service Methods 5.2.2 The OnTearDown Method A business service class may override the OnTearDown method. This method is called during shutdown before the business service object is destroyed. The OnTearDown method provides a way for a business service to perform any special cleanup actions. Method OnTearDown() As %Status { Quit $$$OK } 5.2.3 The OnProductionStart Method A business service class may override the OnProductionStart method. This class method is called once for each configured business service when a production is started. The OnProductionStart method provides a way for a business service to perform any special business service-wide setup actions. ClassMethod OnProductionStart() As %Status { Quit $$$OK } 5.2.4 The OnProductionStop Method A business service class may override the OnProductionStop method. This class method is called once for each configured business service when a production is stopped. The OnProductionStop method provides a way for a business service to perform any special business service-wide cleanup actions. ClassMethod OnProductionStart() As %Status { Quit $$$OK } 5.2.5 The OnProcessInput Method The OnProcessInput method is where the actual work of the business service takes place. When an inbound adapter receives an event, it calls the business service ProcessInput method. This, in turn, calls the OnProcessInput method. The OnProcessInput method is passed, as an input argument, an object representing the incoming event. The business service author defines the type of this event. The OnProcessInput method is intended to do the following things: 1. Validate, if necessary, the incoming event object. Developing Ensemble Productions 99
Business Services 2. Transform the incoming event object into a specific Ensemble request object (a subclass of Ens.Request). 3. Send the request on to a business process or business operation for processing. The following is a simple example of an OnProcessInput method: Method OnProcessInput(pInput As %RegisteredObject, poutput As %RegisteredObject) As %Status { // construct a request object using values from input object Set trequest = ##class(myrequest).%new() Set trequest.value = pinput.value // send request to MyProduction.Operation Set tsc =..SendRequestAsync("MyProduction.Operation", trequest) } Quit tsc The OnProcessInput method can send a request using SendRequestSync or SendRequestAsync. 5.2.6 The SendRequestSync Method A request is synchronous when the business service invokes its SendRequestSync method to make the request. A call to SendRequestSync requires the business service to wait, and do nothing else, until it receives a response from the call. To send a synchronous request from a business service, use the SendRequestSync method as follows: Set tsc =..SendRequestSync(pTargetDispatchName, trequest,.tresponse) This method takes the following arguments: ptargetdispatchname The configuration name of the business process or business operation to which the request is sent. prequest Any persistent object, but typically a subclass of Ens.Request. This object contains the data to send with the request. presponse (By reference) Any persistent object, but typically a subclass of Ens.Response. This object receives the data returned by the response. ptimeout (Optional) The number of seconds to wait for a response. The default is 1 (wait forever). If no response is expected, you can use SendRequestAsync instead of SendRequestSync. 5.2.7 The SendRequestAsync Method A request is asynchronous when the business service invokes its SendRequestAsync method to make the request. A call to SendRequestAsync requires the business service to fire and forget that is, 100 Developing Ensemble Productions
the request is sent and the business service continues its next activity without waiting for a response from the call. To send an asynchronous request from a business service, use the SendRequestAsync method as follows: Set tsc =..SendRequestAsync(pTargetDispatchName, trequest) This method takes the following arguments: Business Service Methods ptargetdispatchname The configuration name of the business process or business operation to which the request is sent. trequest Any persistent object, but typically a subclass of Ens.Request. This object contains the data to send with the request. 5.2.8 The SendDeferredResponse Method All business hosts support the SendDeferredResponse method. This method permits a business host to participate in the Ensemble deferred response convention by identifying a previously deferred request, constructing the actual response message, and directing this response to the business host that originated the request. For an overview, see the Deferred Response section in the Ensemble Messages chapter. This topic describes the role of a business service in this convention. Suppose an incoming event arrives in Ensemble along with a deferred response token, and suppose the arrival point for this event is a business service. This business service then calls SendDeferredResponse to construct a response and direct it to the caller that originated the request. The SendDeferredResponse call looks like this: Set sc =..SendDeferredResponse(token, presponsebody) SendDeferredResponse takes the following arguments: token A string that identifies the deferred response so that the caller can match it to the original request. The business service obtains the token string through some mechanism unique to the production. For example, if the external destination is email, when sending a request for which it is willing to receive a deferred response, a business operation can include the token string in the subject line of the outgoing email. The entity receiving this email can extract this token from the request subject line and use it in the response subject line. This preserves the token so that the business service receiving the response email can use it in a subsequent call to SendDeferredResponse. presponsebody Any persistent object, but typically a subclass of Ens.Response. This object contains the actual response message. Developing Ensemble Productions 101
Business Services 5.2.9 The OnGetConnections Method In ordinary circumstances, it is a simple matter for the Ensemble internal framework to determine which configuration items are the targets of messages from a business service. It simply reads the configuration settings for the business service. It does this when needed to accurately render the configuration diagram of your production, which shows the logical connections between configuration items in the business service, business process, and business operation columns. To view examples of this diagram, see the onfiguration chapter in Managing Ensemble Productions. For custom business services that determine their message targets dynamically, at runtime, rather than at configuration time, the OnGetConnections method is available to tell the Ensemble internal framework which configuration items are the targets of this business service. Normally it is not necessary for you to write an OnGetConnections method for a business service. Most business services simply inherit this method from the base class for business hosts, Ens.Host. However, if your business service does determine its message targets dynamically, you can override OnGetConnections in your business service class. The Ensemble framework will call your version of the method automatically whenever it needs to render the configuration diagram of your production. An OnGetConnections method must have the following signature: ClassMethod OnGetConnections(Output parray As %String, item As Ens.Config.Item) [ CodeMode = generator ] Where the arguments are as follows: parray A string that this method constructs. When the method returns, this string must contain a comma-separated list of the configured names of items to which this business service sends messages. Alternatively, if there are no targets at the present time, this string may be blank (""). item The Ens.Config.Item object that represents this business service. For examples of overridden OnGetConnections methods, use Studio to view the class code for the built-in business services provided for use with electronic data interchange protocols such as HL7 and X12. These are described in detail in books such as the Ensemble HL7 Version 2 Development Guide and the Ensemble X12 Development Guide. 5.3 Business Service Properties The business service property of greatest interest is %WaitForNextCallInterval. Its value controls the OnTask loop of a business service, as described in the section Business Service Life Cycle. 102 Developing Ensemble Productions
Creating a New Business Service Class 5.4 Creating a New Business Service Class A business service host class is simply a class derived from Ens.BusinessService. To create a new business service class, use Ensemble Studio as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Business Service icon and click OK. 5. Enter a package and class name for the business service. Do not use the characters ;:, Click Next. 6. If the business service has an associated inbound adapter class, select it from the drop-down list. 7. Click Finish to save your new business service definition or Cancel to discard it. The resulting business service class will look something like this: Class MyProduction.Service Extends Ens.BusinessService [ ProcedureBlock ] { Parameter ADAPTER = "MyProduction.InboundAdapter"; Method OnProcessInput(pInput As %RegisteredObject, poutput As %RegisteredObject) As %Status { Quit tsc } } The ADAPTER parameter specifies the name of the associated inbound adapter class. A business service class can define both configurable and non-configurable properties. To make a property configurable, simply add its name to the comma-delimited list of properties in the value of the class s SETTINGS parameter. The configuration display on the [Ensemble] > [Productions] page automatically provides the user interface needed to view and edit the configurable properties. For details, see the Configuration Settings section in the chapter Production Concepts. To fully implement the business service, you must implement one or more of its callback methods, such as the OnProcessInput method. Developing Ensemble Productions 103
Business Services 5.5 Adding a Business Service to a Production To add a business service to an Ensemble production, you must first identify (or create) the appropriate business service host class, and then add the business service to the production configuration using the Ensemble Management Portal as follows: 1. Start the Business Service Wizard in one of the following ways: On the [Ensemble] > [Productions] > [Production Model] page, click Add Business Service. While viewing the configuration diagram on the [Ensemble] > [Productions] page, do one of the following: - Left-click on the diagram background. A row of buttons displays below the diagram. Click Add Service. - Right-click on the diagram to reveal the context menu. Choose Add, then Business Service. 2. Choose one of the following types of business service to add. Your initial choice determines the fields that display in the Business Service Wizard form: HL7 Input - Choose TCP, File, or FTP to determine the host class. Each class already exists and requires no programming. Simply choose one. - Give the item a configuration Name. Do not use the characters ;:, - Use the Target Name field to identify the business process or business operation to which this business service will send the HL7 messages that it receives. Business Metric - Choose a host class from the MetricClass drop-down list. If the class you need does not appear on this list, create the class in Studio, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. - Give the item a configuration Name. Do not use the characters ;:, - Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). - Comment is an optional text description. 104 Developing Ensemble Productions
Invoking a Business Service Directly - Call Interval determines how often the business metric will recalculate the values of its properties. The Call Interval is in seconds, starting from a minimum of 0.1 seconds. The default is 5 seconds. Other - Choose a host class from the ServiceClass drop-down list. If the class you need does not appear on this list, create the class in Studio, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. - Give the item a configuration Name. Do not use the characters ;:, - Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). - Comment is an optional text description. 3. Click OK to save your changes, Cancel to ignore them. 4. Business services have operational settings whose values you must set from the configuration display on the [Ensemble] > [Productions] page. If you are already viewing that page, simply begin. To navigate to the configuration display from the [Ensemble] > [Productions] > [Production Model] page, click Configure Production. For full details and instructions about how to configure a business service, see the Business Service Settings section in the Configuration chapter of Managing Ensemble Productions. 5.6 Invoking a Business Service Directly Business services that have inbound adapters typically wait for incoming events and have their associated jobs automatically invoked for them. There are times when you want to invoke a business service class directly, from a job that has been created by some other mechanism, such as a Language Binding, Caché Server Pages, SOAP, or a routine invoked from the operating system level. This type of business service is called an adapterless business service. For a business service to work, an instance of the business service object must exist. You cannot create this instance by calling the %New method. Instead, you must use the Ens.Director factory method CreateBusinessService. For example: Set tsc = ##class(ens.director).createbusinessservice("myservice",.tservice) When you use CreateBusinessService you must ensure that: Developing Ensemble Productions 105
Business Services The business service class is adapterless. Ensure the class has no ADAPTER class parameter value. The configured business service has a Pool Size setting of 0. This means the production does not allocate a job for this business service at production startup. The CreateBusinessService method does the following: 1. It makes sure that a production is running and that the production defines the given business service. 2. It makes sure that the given business service is currently enabled. 3. It resolves the configuration name of the business service and instantiates the correct business service object using the correct configuration values (a production may define many business services using the same business service class but with different names and settings). If the CreateBusinessService method succeeds, it returns, by reference, an instance of the business service class. You can then invoke its ProcessInput method directly. You must provide the ProcessInput method with an instance of the input object it expects. For example: If ($IsObject(tService)) { Set input = ##class(myobject).%new() Set input.value = 22 Set tsc = tservice.processinput(input,.output) } If you browse the online class reference documentation for Ens.Director, you can see that it offers many class methods, including many intended for use only by the Ensemble internal framework. InterSystems recommends that you use only the Ens.Director methods documented in this book, and only as documented. For other recommended Ens.Director methods, see: Ens.Director in the Production Life Cycle section of the chapter Production Concepts Accessing Production Settings Programmatically in the chapter Creating a New Production 106 Developing Ensemble Productions
6 Business Processes Business processes are responsible for the higher level processing within a production. A business process coordinates a series of actions in one or more external applications by calling business operations or other business processes to perform the work. Developing Ensemble Productions 107
Business Processes How a Production Orchestrates Incoming Requests The business process is the workhorse of Ensemble orchestration layer. When a business process receives an incoming request, the business process supervises fulfillment of the request by invoking various business processes, business operations, business methods, and data transformations as needed. The business process can provide methods to accomplish work internal to itself. It can make calls as needed to the Ensemble storage engine or other internal facilities. Like all production entities, the business process writes entries to the event logs and message store for the production. A developer can write the business process to make explicit entries in the event log as well. 108 Developing Ensemble Productions
Business Process Life Cycle 6.1 Business Process Life Cycle Each time the production starts, Ensemble creates the public actor pool for the production. The number of jobs in the pool is determined by the production s ActorPoolSize property, which can be reconfigured while the production is running. Within each job in the actor pool, there is an instance of an Ens.Actor object whose responsibility it is to manage the use of its job by business processes. This Ens.Actor instance is called an actor. The business processes in a production can share the public message queue called Ens.Actor. This public queue is the target of all messages sent to any business process within a production that does not have its own, private queue. Actors listen on the Ens.Actor queue whenever they are free to host a business process. When a request arrive on the Ens.Actor queue, any actor that is free may assign its job to host the business process named in the request. Requests on the Ens.Actor queue are processed in the order in which they are received. Each successive request is claimed by the next available actor, on an ongoing basis. The life cycle of a business process that uses the public queue runs as follows: 1. The initial request is addressed to the business process. The request message arrives on the Ens.Actor queue. 2. As soon as an actor is available to pull the request message off the Ens.Actor queue, it does so. 3. The actor creates a new instance of the appropriate business process class, supplies the most recently configured values of any of the business process s configurable properties (those defined as configurable using the SETTINGS parameter), and invokes that instance s OnRequest method. The business process instance is now ongoing. 4. While the business process instance is ongoing, whenever it is not active (for example, while it is waiting for input or feedback) it generally returns control to the actor that instantiated it. When this happens: a. The actor suspends the business process instance. b. The actor saves the instance s current state to disk. c. The actor returns its job to the actor pool. 5. Whenever an ongoing business process has no assigned actor and a subsequent request or response arrives addressed to the business process (for example, when the anticipated input or feedback arrives) the following sequence occurs: a. As soon as an actor is available to pull the new request or response message from the Ens.Actor queue, it does so. Developing Ensemble Productions 109
Business Processes b. The actor restores the corresponding business process object from disk, complete with all of its state information. c. The actor invokes the instance s OnRequest or OnResponse method, as appropriate. 6. After the business process instance completes execution, its current actor invokes its OnComplete method and marks the instance with the status of IsComplete. The actor also returns its job to the actor pool. No further events are sent to this business process instance. Alternatively, business process can be configured to have private queues, bypassing the public Ens.Actor queue. For details, see the topics Jobs and Pool Size. The life cycle of a business process with a private queue runs exactly as described for a public queue, except that: The business process runs in jobs from the private pool only. The messages addressed to this business process arrive on its own, private queue, and do not arrive on the Ens.Actor queue. 6.2 Business Process Methods At minimum, a business process class contains the operation methods OnRequest and OnResponse. A business process class also provides the SendDeferredResponse method to support a deferred response from a business operation. Additionally, the Ens.BusinessProcess class defines a set of methods that you can use within a customcoded business process. BPL-generated code uses these methods automatically. They include the SendRequestSync, SendRequestAsync, and SetTimer methods documented in this section, as well as assorted others. You can view the complete Ens.BusinessProcess class using Ensemble Studio. 6.2.1 The OnRequest Method The business process s OnRequest method is called whenever an initial request for a specific business process arrives on the appropriate queue and is assigned a job in which to execute. The following is an example of an OnRequest method, from the Demo.Loan.BankUS sample class in the ENSDEMO namespace: Method OnRequest(request As Demo.Loan.Msg.Application, Output response As Demo.Loan.Msg.Approval) As %Status { Set $ZT="Trap",tSC=$$$OK Do { $$$TRACE("received application for "_request.name) #; If $zcrc(request.name,2)#5=0 { Set response = ##class(demo.loan.msg.approval).%new() 110 Developing Ensemble Productions
Set response.bankname = "BankUS" Set response.isapproved = 0 $$$TRACE("application is denied because of bank holiday") Quit } #; Set trequest = ##class(demo.loan.msg.primeraterequest).%new() Set tsc =..SendRequestAsync("Demo.Loan.WebOperations",tRequest,1,"PrimeRate") #; Set trequest = ##class(demo.loan.msg.creditratingrequest).%new() Set trequest.ssn = request.ssn Set tsc =..SendRequestAsync("Demo.Loan.WebOperations",tRequest,1,"CreditRating") #; Set tsc =..SetTimer("PT15S") #; Quit } While (0) Exit Quit tsc Trap Set $ZT="",tSC=$$$EnsSystemError Goto Exit } This method takes the following arguments: prequest The incoming request object. presponse The response returned by this business process. Business Process Methods 6.2.2 The OnResponse Method The business process s OnResponse method is called whenever a response for a specific business process arrives on the appropriate queue and is assigned a job in which to execute. Typically this is a response to an asynchronous request made by the business process. The following is an example of an OnResponse method, from the Demo.Loan.BankUS sample class in the ENSDEMO namespace: /// Handle a 'Response' Method OnResponse(request As Ens.Request, ByRef response As Ens.Response, callrequest As Ens.Request, callresponse As Ens.Response, pcompletionkey As %String) As %Status { Set $ZT="Trap",tSC=$$$OK Do { If pcompletionkey="primerate" { Set..PrimeRate = callresponse.primerate } Elseif pcompletionkey="creditrating" { Set..CreditRating = callresponse.creditrating } Quit } While (0) Exit Quit tsc Trap Set $ZT="",tSC=$$$EnsSystemError Goto Exit } Developing Ensemble Productions 111
Business Processes This method takes the following arguments: prequest The initial request object sent to this business process. presponse The response object that will eventually be returned by this business process. pcallrequest The request object associated with the incoming response. pcallresponse The incoming response object. pcompletionkey The completion key value associated with the incoming response. This is set by the call to the SendRequestAsync method that made the request. 6.2.3 The SendRequestSync Method This method makes a synchronous request to a business operation or business process: this method does not return until a response is received. This method takes the following arguments: ptargetdispatchname The configuration name of the business process or business operation to which the request is sent. prequest Any persistent object, but typically a subclass of Ens.Request. This object contains the data to send with the request. presponse (By reference) Any persistent object, but typically a subclass of Ens.Response. This object receives the data returned by the response. ptimeout (Optional) The number of seconds to wait for a response. The default is 1 (wait forever). If no response is expected, you can use SendRequestAsync instead of SendRequestSync. 6.2.4 The SendRequestAsync Method This method makes an asynchronous request to a business operation or business process: this method does not wait for a response before returning control to the caller. This method takes the following arguments: ptargetdispatchname The configuration name of the business operation or business process that is the target for this request. prequest Any persistent object, but typically a subclass of Ens.Request. This object contains the data to send with the request. presponserequired A Boolean flag indicating whether or not a response is needed for this request. An integer value of 1 (true) indicates that this message requires a response. A value of 0 (false) means the message does not require a response. 112 Developing Ensemble Productions
Business Process Methods pcompletionkey An optional string value that lets you associate a name with this request. This value is passed to the OnResponse method when the response returns and allows you to determine which request a specific response is associated with. 6.2.5 The SendDeferredResponse Method All business hosts support the SendDeferredResponse method. This method permits a business host to participate in the Ensemble deferred response convention by identifying a previously deferred request, constructing the actual response message, and directing this response to the business host that originated the request. For an overview, see the Deferred Response section in the Ensemble Messages chapter. This topic describes the role of a business process in this convention. Suppose an incoming event arrives in Ensemble along with a deferred response token, and suppose the arrival point for this event is a business process. A business service is the more common case, but it is also possible for a business process to send deferred responses. When it receives the data required to complete a deferred response, the business process calls SendDeferredResponse to construct a response message and direct it to the caller that originated the request. The SendDeferredResponse call looks like this: Set sc =..SendDeferredResponse(token, presponsebody) SendDeferredResponse takes the following arguments: token A string that identifies the deferred response so that the caller can match it to the original request. The business process obtains the token string through some mechanism unique to the production. For example, if the external destination is email, when sending a request for which it is willing to receive a deferred response, a business operation can include the token string in the subject line of the outgoing email. The entity receiving this email can extract this token from the request subject line and use it in the response subject line. This preserves the token so that the business process receiving the response email can use it in a subsequent call to SendDeferredResponse. presponsebody Any persistent object, but typically a subclass of Ens.Response. This object contains the actual response message. 6.2.6 The SetTimer Method This method sets up a timer indicating how long to wait for pending asynchronous responses. Any responses received after this time are discarded and not processed. This method takes the following arguments: pduration An XML duration value. This is a string of one or more characters; for example P60S for 60 seconds or P1Y2M3DT10H30M for 1 year, 2 months, 3 days, 10 hours, and 30 minutes. Developing Ensemble Productions 113
Business Processes For the syntax of an XML duration string, see the Primitive Datatypes section of the W3C Recommendation XML Schema Part 2: Datatypes Second Edition, which you can view at http://www.w3.org/tr/xmlschema-2/#duration. 6.2.7 The IsComponent Method Ens.BusinessProcessBPL, the base class for all BPL business processes, offers a class method IsComponent which returns 1 (true) if the BPL business process has been designated a reusable component, 0 (false) if not. 6.3 Creating a New Business Process Class You can implement Ensemble business process classes in two different, but equally valid ways: Using Business Process Language (BPL), a specification based on XML that automatically generates business process code from a BPL document or from its corresponding graphical representation. Ensemble generates this type of business process as a subclass of the Ens.BusinessProcessBPL class. Using custom code, creating a subclass of the Ens.BusinessProcess class and implementing the OnRequest and OnResponse methods In either case you can begin from Ensemble Studio. 6.3.1 Creating a New BPL Business Process Class The host class for a BPL business process is simply a class derived from Ens.BusinessProcessBPL. It is identical in every way to a class derived from Ens.BusinessProcess, except that it supports the Ensemble Business Process Language (BPL). BPL is a language used to describe executable business processes within a standard XML document. BPL syntax is based on several of the proposed XML standards for defining business process logic, including the Business Process Execution Language for Web Services (BPEL4WS or BPEL) and the Business Process Management Language (BPML or BPMI). BPL is a superset of other proposed XML-based standards, in that it provides additional elements whose purpose is to help you build integration solutions. These additional elements include support for: Execution flow control elements such as <branch>, <if>, <switch>, <foreach>, <while>, and <until>. For information about how to use these and other BPL syntax elements, see the Ensemble Business Process Language Reference. 114 Developing Ensemble Productions
Generation of executable code from business process logic. Embedding SQL and custom-written code into the business process logic. The BPL Visual Editor, a full-featured, visual modeling tool for graphically viewing and editing business process logic. This tool includes complete round-trip engineering between the visual and BPL representations of the business process. Changes to one representation are automatically reflected in the other. The next several topics provide information about how to use this tool from within Studio. Debugging capabilities. Specialized elements allow you to leverage built-in Ensemble development features to trace business process activities using a line-by-line debugging tool. Automatic support for both asynchronous and synchronous messaging between business processes and other members of an integration solution. BPL streamlines this difficult and error-prone programming task. Persistent state. BPL permits a long-running business process to automatically suspend execution and efficiently save its execution state to the built-in, persistent cache embedded in Ensemble whenever it is in active; for example, when it is waiting for an asynchronous response. Ensemble automatically manages all state preservation and the ability to smoothly resume processing. Rich and varied data transformation services, including SQL queries embedded within the business process. To create a new BPL business process class, use Ensemble Studio as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Creating a New Business Process Class Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Business Process icon and click OK. 5. Enter a package and class name for the business process. Click Next. Important: InterSystems recommends that you do not use the package names Demo, Ens, EnsLib, EnsPortal, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 6. Select Using the Business Process Editor and click Finish. Developing Ensemble Productions 115
Business Processes The dialog closes, and the BPL Visual Editor opens a new class diagram in the Class Editor window. The new diagram is blank except for the class name and description at the top left corner of the page. For detailed information, see the section Using the BPL Visual Editor. When you save a diagram from the BPL Visual Editor, it generates a class description that is, a text document in correct BPL syntax. The BPL diagram and the BPL document are equally valid descriptions of the same BPL business process class. Studio recognizes each format interchangeably. A change to one automatically generates a change to the other. Therefore, while viewing the class in Studio, you can switch between diagram and text views of the BPL document by clicking Other or pressing Ctrl-Shift-V. View Note: When switching from the text view to the graphical view, sometimes it is necessary to close and reopen the class to see the graphical view again. 6.3.2 Creating a New Custom Business Process Class A custom business process class is a class derived from Ens.BusinessProcess, with class methods implemented directly by the developer (instead of being generated through BPL). Important: A class derived from Ens.BusinessProcess does not support the business process execution context or a graphical display of business process logic. If these are features that you want your business process to support, you must use BPL instead of custom code. The easiest way to start work on a new custom business process class is to create a framework for it using Ensemble Studio, as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Business Process icon and click OK. 5. Enter a package and class name for the business process. Click Next. Important: InterSystems recommends that you do not use the package names Demo, Ens, EnsLib, EnsPortal, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 116 Developing Ensemble Productions
Creating a New Business Process Class 6. Select Using Custom Code and click Finish. The resulting business process class will look something like this: Class MyProduction.MyProcess Extends Ens.BusinessProcess [ ClassType = persistent, ProcedureBlock ] { Method OnRequest(pRequest As Ens.Request, Output presponse As Ens.Response) As %Status { Quit $$$ERROR($$$NotImplemented) } } To fully implement this business process, you must implement one or more of its methods. 6.3.3 Providing Settings in a Business Process Class A business process class can define both configurable and non-configurable properties. To make a property configurable, simply add its name to the comma-delimited list of properties in the value of the class s SETTINGS parameter. The configuration display on the [Ensemble] > [Productions] page automatically provides the user interface needed to view and edit the configurable properties. For details, see the Configuration Settings section in the chapter Production Concepts. The SETTINGS parameter is easy to edit when you are viewing class code in Studio. However, this parameter, even when present in class code, is not visible in the BPL diagram view of a BPL business process. To add SETTINGS to a BPL business process from Ensemble Studio, you must first open the class in the BPL diagram view, then click the View Other button to switch to the class code view. Add properties and SETTINGS parameter in the class code view, then compile the class. The BPL diagram does not display business process settings, but after you compile the class, the settings become visible next time you configure an instance of this business process class in the configuration display on the [Ensemble] > [Productions] page. 6.3.4 Business Process Components A business process component or BPL component is a BPL business process that a programmer wishes to identify as a modular, reusable sequence of steps in the BPL language. A BPL component is analogous to a function, macro, or subroutine in other programming languages. Only another BPL business process can call a BPL component. It does this using the BPL <call> element. The BPL business process component performs tasks, then returns control to the BPL business process that called it. The Ensemble architecture already allows one BPL business process to call another BPL business process. The optional component designation simply provides convenience. It allows you to classify certain BPL business processes as simpler, lower-level components that: Developing Ensemble Productions 117
Business Processes Are not intended to run as stand-alone business processes (although nothing in the architecture prevents this) May be reusable (in the sense of a function, macro, or subroutine in the BPL language) Business processes that are not components are assumed to have more complex, special-purpose designs, and to operate at a higher conceptual level than components. It is expected that BPL noncomponents will call BPL components to accomplish tasks. Important: There is no requirement that you use the component designation for any BPL business process. It is available as a convenience for any BPL programmer who prefers it. The programmer makes a business process into a component simply by setting an attribute of the toplevel <process> container for the BPL business process. The attribute is called component and it can be set to 1 (true) or 0 (false). For syntax details see the Ensemble Business Process Language Reference. To set the value of the component attribute, you can do either of the following: Edit the BPL <process> element within the XData BPL block in the class code. Open the BPL business process diagram in Studio. Click on the title box (at top left in the diagram) to reveal <process> element attributes in the Studio Inspector window. Click on the Component field in the Inspector window. To make the business process a component, change the Component value from False to True. To set up a <call> to a component from a BPL business process, see the section Using the Call Wizard. 6.4 Adding a Business Process to a Production To add a business process to an Ensemble production, you must first identify (or create) the appropriate business process host class, and then add the business process to the production configuration using the Ensemble Management Portal as follows: 1. Start the Business Process Wizard in one of the following ways: On the [Ensemble] > [Productions] > [Production Model] page, click Add Business Process. While viewing the configuration diagram on the [Ensemble] > [Productions] page, do one of the following: - Left-click on the diagram background. A row of buttons displays below the diagram. Click Add Process. 118 Developing Ensemble Productions
Adding a Business Process to a Production - Right-click on the diagram to reveal the context menu. Choose Add, then Business Process. 2. Choose one of the following types of business process to add. Your choice determines the fields that display in the Business Process Wizard form: Business Process Component - Choose a host class from the Component drop-down list. If the class you need does not appear on this list, create the class in Studio, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. - Give the item a configuration Name. Do not use the characters ;:, - Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). - Comment is an optional text description. HL7 Message Router - Accept the default Router Class of EnsLib.HL7.MsgRouter.RoutingEngine. - Give the item a configuration Name. Do not use the characters ;:, - Use the Routing Rule Name field to identify the routing rule set to which this business process will send the messages that it receives. Other - Choose a host class from the ProcessClass drop-down list. If the class you need does not appear on this list, create the class in Studio, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. - Give the item a configuration Name. Do not use the characters ;:, - Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). - Comment is an optional text description. 3. Click OK to save your changes, Cancel to ignore them. 4. Business processes have operational settings whose values you must set from the configuration display on the [Ensemble] > [Productions] page. If you are already viewing that page, simply begin. Developing Ensemble Productions 119
Business Processes To navigate to the configuration display from the [Ensemble] > [Productions] > [Production Model] page, click Configure Production. For full details and instructions about how to configure a business process, see the Business Process Settings section in the Configuration chapter of Managing Ensemble Productions. 6.5 Business Process Execution Context The life cycle of a business process requires it to have certain state information saved to disk and restored from disk, whenever the business process suspends or resumes execution. This feature is especially important for long-running business processes, which may take days or weeks to complete. A BPL business process supports the business process life cycle with a group of variables known as the execution context. The variables in the execution context are automatically saved and restored each time the BPL business process suspends and resumes execution. These variables are available to every BPL business process; that is, to every business process class that inherits from Ens.BusinessProcessBPL. Important: Custom business processes that inherit from Ens.BusinessProcess do not have access to a built-in execution context and must handle similar issues using custom code. Some of the execution context variables are available to every activity within a BPL business process. Others are generally available, but go in and out of scope, depending on the type of activity that the business process is executing at the time. The following topics describe the execution context variables and when they are available to a BPL business process. The variables are: context request response callrequest callresponse syncresponses synctimedout status process Tip: For detailed information about BPL syntax, and about BPL elements such as <process>, <context>, and <call>, see the Ensemble Business Process Language Reference. 120 Developing Ensemble Productions
Business Process Execution Context 6.5.1 The context Object context is an object that is available to a BPL business process anywhere inside the <process> element. context is a general-purpose container for any data that needs to be persisted during the life cycle of the business process. You define each data item as a property on the context object when creating the BPL business process as follows: In the BPL Visual Editor, click on the background of the main drawing. In the Inspector window, find the Context field. Click the 1. More icon at right. A dialog displays. Use it as follows: Click the Add icon to add a new property, or double-click on the name of an existing property name to edit it. 2. Enter a property Name. 3. Enter a data type class name in the Type field or click the More icon to browse for a class you want to use as a data type. Typically you will choose one from the system library of data types described in the Data Types chapter of Using Caché Objects. These include %String, %Integer, %Boolean, etc. 4. If needed, you can choose a Collection type or enter an Initial Expression for the property. 5. Click OK to save your changes, Cancel to discard them. 6. The BPL Visual Editor generates the necessary <context> and <property> elements in the BPL code. In BPL code, insert <property> elements inside the <context> element, one for each property, as described in the Ensemble Business Process Language Reference. System data types have optional parameters. For details, see the Parameters section in the Data Types chapter of Using Caché Objects. These include the MINLEN and MAXLEN parameters that set the minimum and maximum allowed lengths of a %String property. The default maximum %String length is 50 characters; you can reset this by setting the MAXLEN for that %String property to another value. To set property parameters such as MINVAL, MAXVAL, MINLEN, MAXLEN, or others: In the BPL Visual Editor, add data type parameters to a context property when you first add the property, or at any subsequent time, by inserting a comma-separated list of parameters enclosed in parentheses after the data type class name. That is, rather than simply entering %String or %Integer, you can enter data types such as: %String(MAXLEN=256) %Integer(MINVAL=0,MAXVAL=100) %String(VALUELIST=",Buy,Sell,Hold") Developing Ensemble Productions 121
Business Processes The BPL Visual Editor generates the necessary <parameters> element in the BPL code. In BPL code, you must allow the <property> element to specify the data type with its type attribute (class name only!) and include a <parameters> element inside the <property> element to describe any data type parameters that you want to include, as described in the Ensemble Business Process Language Reference. For example: <context> <property name='test' type='%integer' initialexpression='342' > <parameters> <parameter name='maxval' value='1000' /> </parameters> </property> <property name='another' type='%string' initialexpression='yo' > <parameters> <parameter name='maxlen' value='2' /> <parameter name='minlen' value='1' /> </parameters> </property> </context> Once you have defined properties on the context object as described in this topic, you can refer to them anywhere in BPL using ordinary dot syntax and the property name, as in: context.mydata 6.5.2 The request Object The request object contains the properties that were in the original request message object the primary request the incoming message that first caused this business process to be instantiated. The request object is available to a BPL business process anywhere inside the <process> element. You can refer to the properties of the request object using dot syntax and the property name, as in: request.originalthought 6.5.3 The response Object The response object contains the properties that are required to build the final response message object to be returned by this business process instance. The business process returns this final response either when it reaches the end of its life cycle, or when it encounters a <reply> activity. The response object is available to a BPL business process anywhere inside the <process> element. You can refer to the properties of the response object using dot syntax and the parameter name, as in: response.bottomline 6.5.4 The callrequest Object The callrequest object contains any properties that are required to build the request message object to be sent by a <call>. 122 Developing Ensemble Productions
A <call> activity sends a request message and, optionally, receives a response. A BPL <call> element must include a <request> activity to put values into the properties on the request message object. In order to accomplish this, the <request> provides a sequence of <assign> activities that place values into properties on the callrequest object. Typically, some of these values are derived from properties on the original request object, but you are free to assign any value. As soon as the <assign> activities inside the <request> are completed, the message is sent, and the associated callrequest object goes out of scope. callrequest has no meaning outside its associated <request> activity; it is already out of scope when the associated <call> begins processing its next activity, the optional <response>. Within the scope of the relevant <request> element, you can refer to the properties on callrequest using dot syntax, as in: callrequest.userdata 6.5.5 The callresponse Object Upon completion of a <call> activity, the callresponse object contains the properties of the response message object that was returned to the <call>. If the <call> was designed with no response, there is no callresponse. Every <call> that expects a response must provide a <response> activity within the <call>. The purpose of the <response> activity is to retrieve the response values and make them available to the business process as a whole. The callresponse object is available anywhere inside the <response> activity. However, as soon as the <response> activity completes, the associated callresponse object goes out of scope. Therefore, if you want to use the values in callresponse elsewhere in the business process, you must <assign> these values to properties on the context or response objects, and you must do so before the end of the <response> activity in which they were received. You can refer to the properties on callresponse using dot syntax, as in: callresponse.useranswer 6.5.6 The syncresponses Collection syncresponses is a collection, keyed by the names of the <call> activities being synchronized by a <sync>. When a <sync> activity begins, syncresponses is cleared in preparation for new responses. As the <call> activities return, responses go into the collection. When the <sync> activity completes, syncresponses may contain all, some, or none of the desired responses (see synctimedout). syncresponses is available anywhere inside the <sequence> that contains the relevant <call> and <sync> activities, but goes out of scope outside that <sequence>. To refer to the response value from one of the synchronized calls, use the syntax: syncresponses.getat("name") Where the relevant <call> was defined as: <call name="name"> Business Process Execution Context Developing Ensemble Productions 123
Business Processes 6.5.7 The synctimedout Value synctimedout is an integer value that may be 0, 1, or 2. synctimedout indicates the outcome of a <sync> activity after several calls. You can test the value of synctimedout after the <sync> and before the end of the <sequence> that contains the calls and <sync>. synctimedout has one of three values: If 0, no call timed out. All the calls had time to complete. This is also the value if the <sync> activity had no timeout set. If 1, at least one call timed out. This means not all <call> activities completed before the timeout. If 2, at least one call was interrupted before it could complete. synctimedout is available to a BPL business process anywhere inside the <sequence> that contains the relevant <call> and <sync> activities, but goes out of scope outside that <sequence>. Generally you will test synctimedout for status and then retrieve the responses from completed calls out of the syncresponses collection. You can refer to synctimedout with the same syntax as for any integer variable name, that is: synctimedout 6.5.8 The status Value status is a value of type %Status that indicates success or failure. Note: Error handling for a BPL business process happens automatically without your ever needing to test or set the status value in the BPL source code. The status value is documented here in case you need to trigger a BPL business process to exit under certain special conditions. When a BPL business process starts up, status is automatically assigned a value indicating success. To test that status has a success value, you can use the macro $$$ISOK(status) in ObjectScript and the method $SYSTEM.Status.IsOK(status) in Basic. If the test returns a True value, status has a success value. As the BPL business process runs, if at any time status acquires a failure value, Ensemble immediately terminates the business process and writes the corresponding text message to the event log. This happens regardless of how status acquired the failure value. Thus, the best way to cause a BPL business process to exit suddenly, but gracefully is to set status to a failure value. status can acquire a failure value in any of the following ways: status automatically receives the returned %Status value from any <call> that the business process makes to another business host. If the value of this %Status indicates failure, status automatically receives the failure value. This is the most common way in which status is set, and it happens automatically, without any special statements in the BPL code. 124 Developing Ensemble Productions
Using the BPL Visual Editor An <assign> activity can set status to a failure value. The usual convention for doing this is to use an <if> element to test the result of some prior activity, and then within the <true> or <false> element use <assign> to set status to a failure value when failure conditions exist. Statements within a <code> activity can set status to a failure value. The BPL business process does not perceive the change in the value of status until the <code> activity has fully completed. Therefore, if you want a failure status to cause an immediate exit from a <code> activity, you must place a quit command in the <code> activity immediately after setting a failure value for status. To test that status has a failure value, use the macro $$$ISERR(status) in ObjectScript and the method $system.status.iserror(status) in Basic. If the test returns a True value, status has a failure value. You will be able to perform this test only within the body of a <code> activity before it returns to the main BPL business process, since the business process will automatically quit with an error as soon as it detects that status has acquired a failure value following any <call>, <assign>, or <code> activity. status is available to a BPL business process anywhere inside the <process>. You can refer to status with the same syntax as for any variable of the %Status type, that is: status WARNING! Like all other execution context variable names, status is a reserved word in BPL. Do not use it except as described in this topic. 6.5.9 The process Object The process object represents the current instance of the BPL business process object. The process object is provided so that you can invoke any business process method, such as SendRequestSync or SendRequestAsync, from any context within the flow of the BPL business process, for example from within the text block of a <code> activity. The process object is available to a BPL business process anywhere inside the <process> element, but is typically needed only within the <code> activity. You can refer to methods of the process object using dot syntax and the method name, as in: process.sendrequestsync or process.clearallpendingresponses 6.6 Using the BPL Visual Editor The BPL Visual Editor is an Ensemble Studio tool that permits you to construct a BPL business process as a visual diagram. When you save a diagram from the BPL Visual Editor, it generates a class description that is, a text document in correct BPL syntax. The BPL diagram and the BPL document are equally valid descriptions of the same BPL business process class. Developing Ensemble Productions 125
Business Processes A BPL diagram consists of shapes that correspond to activities in a BPL file, with additional shapes and connections that correspond to logic in the BPL file. The following is a sample BPL diagram. Example of a BPL Diagram 126 Developing Ensemble Productions
To view a similar diagram, start Studio, connect to an Ensemble namespace, and open a BPL business process class such as Demo.Loan.FindRateDecisionProcessBPL in the ENSDEMO namespace. The class opens to the BPL diagram view automatically. To switch to the class code view, click the View Other button in the Studio toolbar. When using the BPL Visual Editor to work with a BPL diagram, you can: Add a new element by right-clicking and selecting Add from the context menu. Select a shape by clicking on it. You can select multiple shapes by holding down the Shift key while selecting. Delete, Copy, and otherwise manipulate the current selected items by right-clicking and choosing options from the context menu. Connect one element to another by clicking on its input or output nub and dragging to the desired element. The BPL Visual Editor will not allow you to make an illegal connection. Insert and connect a new shape in one operation: Select the two elements on either side of where the new shape should go, then enter commands to add the shape. The new shape appears between the existing elements with connections automatically in place. Auto-arrange shapes by right-clicking and using the Arrange Layout command in the context menu. Changing the position of shapes does not change the underlying BPL code. Only a change to the connecting lines will change the code. Display or edit the properties of an element by selecting it and using the Studio Inspector window. You can select a connector to see its properties; you can click on the background to see the properties of the process itself. Detect an element with a logical error: it is displayed with a red outline. You can determine the cause of the error by right-clicking and choosing the context menu Validate Activity command. View a popup summary of an element by hovering the mouse over it. Navigate nested diagrams (if any) by right-clicking and choosing Drill Down or Drill Up from the context menu. The following topics provide details. 6.6.1 BPL Diagram Shapes Using the BPL Visual Editor A BPL diagram uses certain shapes to indicate that a BPL element is present in the code. Developing Ensemble Productions 127
Business Processes BPL Diagram Shapes BPL Shape Meaning Activity Example <assign>, <call>, <sync>, and most others. Loop Sequence Scope Decision <foreach>, <while>, or <until>. Reveal the loop details by clicking on the arrow at the bottom of the shape, or by selecting the shape, right-clicking, and choosing Drill Down from the context menu. <catch>, <catchall>, or <sequence>. Reveal the sequence by clicking on the plus sign at the bottom of the shape, or by selecting the shape, right-clicking, and choosing Drill Down from the context menu. The start of a BPL <scope> for error handling purposes. A shaded rectangular background encloses all the BPL elements that fall within this <scope> The start of an <if>, <switch>, or <branch>. Special <alert>, <reply>, or <label>. Split Join The start of a BPL <flow> element, where various logical paths diverge from a single point The end of any branching element <if>, <flow>, <branch>, <scope>, or <switch> where all possible paths come together. The start or end of a BPL diagram. 128 Developing Ensemble Productions
Many activity shapes display an icon, as shown for the <assign> activity in the previous table. The following table lists and describes these icons. BPL Diagram Icons Using the BPL Visual Editor Icon BPL Element <assign> Asynchronous <call> Synchronous <call> <catch> <code> <delay> <milestone> <rule> <sql> <sync> <trace> Developing Ensemble Productions 129
Business Processes In general the interior color of a BPL diagram shape is white, with a blue outline. If the shape is in error, its outline is red. If the shape is disabled, its interior color is gray, with a gray outline. When you click on a shape in a BPL diagram, it becomes selected. Its attributes display in the Studio Inspector window, where you can edit their values. Its interior color changes to yellow. If it is in error, its outline remains red; if not, its outline changes from blue to green. A disabled shape has a dotted outline when selected. You can select multiple shapes by holding down the Ctrl key while clicking on shapes. You can select all of the shapes in a diagram by right-clicking and choosing Select All from the context menu. To unselect any shape, click on it while it is already selected. When a shape represents a complex activity such as <if> or <switch> that has multiple branches, joins, or other types of related shapes elsewhere in the BPL diagram, clicking on one of these shapes highlights the related shapes in green with a purple outline. Clicking on a <sync> element highlights the <call> elements that it synchronizes. Clicking on an <if> shape highlights the Join where the <true> and <false> branches come together. And so on. For example: 130 Developing Ensemble Productions
BPL Diagram with Join Selected, Related <if> Highlighted Using the BPL Visual Editor 6.6.2 BPL Diagram Connections In a BPL diagram, the lines between shapes specify logical relationships and sequencing among the elements. These lines are called connections. The start of each line is a circular nub and the end is Developing Ensemble Productions 131
Business Processes a triangular point. One triangular input nub and one circular output nub are built into each shape that you add to the BPL diagram. A New Shape Added to a BPL Diagram You can connect one shape to another by clicking on its input or output nub and dragging the cursor to the desired shape. When you release the mouse, a connection appears. Another way to connect shapes is to insert and auto-connect a new shape in one step. Select the two elements on either side of where the new shape should go. You can select multiple elements by holding down the Ctrl key while clicking on the shapes. If two elements are selected with no existing connection between them, you can add a new shape and it appears between the existing elements, with connections automatically in place. To add a new shape between two connected elements, click on the connection to highlight it, then add the new element. The new shape appears between the existing elements, with connections automatically in place. Once two shapes are connected, the connection is preserved no matter where you drag the respective shapes. You can drag shapes to any layout position you wish, within the same diagram. Connections reroute automatically, and the underlying BPL document is not changed. On the other hand, if you change the logic of the connections, for example to reorder calls, create loops, or cut and paste, then the underlying BPL document is changed to reflect your actions in the BPL Visual Editor. You can add a text label to any connection by editing its attributes in the Inspector window. Within a <switch> activity, each possible path is automatically labeled with the corresponding <switch> value. All of the possible paths from a <switch> activity converge at a Join shape before a single arrow connects from the Join shape to the next activity in the BPL diagram. 132 Developing Ensemble Productions
Using the BPL Visual Editor Connection Labels in a Switch Element The BPL Visual Editor provides many types of validation of your diagram as you work on it. One useful validation feature is that the editor detects if the output branches of an <if>, <flow>, or <switch> element are connected to the wrong Join shape in the diagram. If so, the connector that is in error displays in red until you correct the diagram. 6.6.3 BPL Diagram Layout After you add shapes or create new connections, you can tidy the diagram by right-clicking and choosing Arrange Layout from the context menu. If you want your diagrams to always use this type of layout, ensure that the Auto Arrange option on the context menu is selected. Developing Ensemble Productions 133
Business Processes Auto-Arranged Shapes in a BPL Diagram By default, when someone opens a BPL diagram in the BPL Visual Editor or BPL Viewer, the tools display the diagram using automatic layout arrangements. These automatic choices may or may not be appropriate for a particular drawing. You can disable automatic layout to ensure that your diagram always displays with exactly the layout you want. To do so: 1. Click on the background of the top-level BPL diagram. 2. The Inspector window displays the attributes of the <process> element. Find the Layout attribute in the list. 3. You can select a value of manual or automatic for the Layout attribute. Select manual to preserve the exact position of each element, each time you save the BPL diagram. This way, when the diagram is displayed in the BPL Visual Editor or BPL Viewer, it does not take on any layout characteristics except what you have specified. 6.6.4 BPL Diagram Context Menu A context-sensitive menu of commands is available for you to use in the BPL Visual Editor. To display the BPL diagram context menu, position the cursor on a BPL diagram and right-click. The following options display: Add Activity Choose a BPL element from a list. All of the elements in the BPL schema are displayed in this list, plus logical shapes like Join. When you choose an item from the list, a new element of this type pops up in the diagram. The new element does not have a name and is not yet connected to the diagram. Connect Elements After selecting two unconnected shapes in the BPL graphical editor, you can right-click and select the Connect Elements option. The two elements become connected sequentially in the order in which you selected them. 134 Developing Ensemble Productions
Using the BPL Visual Editor Call Wizard Displays a dialog whose drop-down choices help you to properly construct a new <call> to one of the available business processes or business operations in the production. The Help button in this dialog displays the online documentation for the BPL <call> element. Zoom Choose a zoom factor for the BPL diagram. Choose a large factor to view details, a small factor to gain an overview. Undo Undo your most recent action, such as adding, moving, or editing an activity. Select All Select all of the shapes in the current diagram. If desired, you can then unselect specific items by holding down the Ctrl key while clicking on shapes. Cut, Copy, Delete, Paste These editing commands apply to the currently selected activity in the diagram. You can select one activity at a time by clicking on it. The selected activity changes color to yellow. Show Annotation Reveal or conceal the text notes that explain each shape. When you reveal annotations, they appear to the upper right of each shape that has an <annotation> element in the BPL document. Smart Connections Enable or disable the smart connections feature. When the feature is enabled, connections automatically appear when you select two shapes, or a connection between two existing shapes, and add a new shape between them. Arrange Layout Align shapes nicely in the diagram without changing the underlying BPL document. Auto Arrange Cause each new shapes in the diagram to automatically conform to a tidy shape without needing to select Arrange Layout after adding each shape. Validate Activity Validate the underlying BPL code for the currently selected activity in the diagram. Group Elements Cause the selected shapes to form a group diagram, into which you can drill down for details. You can select whether to group the selected elements as a <sequence>, or as a specific type of loop: <foreach>, <while>, or <until>. Drill Down, Drill Up If you select an activity, right-click, then choose Drill Down from the context menu, a BPL diagram of activity details displays. To return to the higher level where one shape represents the entire activity, right-click and choose Drill Up. View Target Definition To use this option, select a <call> activity that calls another BPL business process. Right-click, then choose View Target Definitionfrom the context menu. The BPL diagram for the referenced BPL business process displays in a separate Studio window. You can switch back to the diagram of the calling business process by selecting its name in the Studio Window menu. Developing Ensemble Productions 135
Business Processes Note: When you first open a BPL diagram and choose View Target Definition, a message displays asking you to use the Call Wizard to set the production name. Choose the context menu Call Wizard option, click on the production name that contains the BPL diagram, and then click Cancel. Find, Find Again Find and Find Again let you search for a text string in the underlying BPL document. When found, the corresponding string is highlighted in the BPL diagram. View Source Displays the SVG code for the diagram. About SVG Viewer Display version and copyright information about the SVG Viewer used by the BPL Visual Editor. 6.6.5 Using the Call Wizard The BPL Visual Editor context menu option Call Wizard displays a dialog that helps you to construct a valid <call> to one of the available business processes or business operations in the production. Use this dialog as follows: Select a Production from the drop-down list of productions in the currently active Ensemble namespace. Select a Target from within the chosen production. You may choose one of the following: - Business Operation - Business Process - Business Process Component Depending on which you choose, the dialog displays a list of the available items of that type; you may select one of these as the Target of the <call>. Select a Request Type from the drop-down list of message types in the currently active Ensemble namespace. Select or clear the following check boxes as needed: - Create default Request and Response blocks - Add missing properties to the Business Process context - Use an asynchronous call Click the Help button to display documentation for the <call> element. Click OK to save changes, Cancel to exit the dialog without saving. Control returns to the BPL diagram. 136 Developing Ensemble Productions
Using the BPL Visual Editor 6.6.6 Drilling Down in a BPL Diagram A loop activity displays a cyclic arrow to indicate that it provides drill-down details. The following is an example of the <foreach> loop activity. Others include <while> and <until>. Example of a BPL Loop If you select the loop activity, right-click, and choose Drill Down from the context menu, a BPL diagram of the loop displays. This is a full BPL diagram showing all the logic between the Start and End of the loop. To return to the higher logical level, where one shape represents the entire loop, right-click and choose Drill Up from the context menu. Developing Ensemble Productions 137
Business Processes Example of a BPL Loop, Drilled Down A sequence displays a plus sign to indicate that it, too, can provide drill-down details. 138 Developing Ensemble Productions
Using the BPL Visual Editor Example of a BPL Sequence When you drill down into a sequence, the resulting BPL diagram showing all the logic between the Start and End of the sequence. To return to the higher logical level, where one shape represents the entire sequence, right-click and choose Drill Up from the context menu. Example of a BPL Sequence, Drilled Down If there is an error anywhere in a lower-level diagram, the BPL Visual Editor highlights the group shape (<foreach>, <sequence>, <while>, or <until>) in red. To fix the error, you must select the group shape, right-click, and choose Drill Down from the context menu. In the lower-level diagram, the activity that has the error is highlighted in red. 6.6.7 BPL Visual Editor Toolbar The BPL Visual Editor Toolbar is available whenever you have a BPL diagram open in the Studio tool. The toolbar is visible by default. You can show or hide it by selecting the Studio View menu BPL Toolbar option. Developing Ensemble Productions 139
Business Processes BPL Toolbar When you click on an icon in the BPL Visual Editor Toolbar, a new element appears in the BPL Visual Editor window. The type of element depends on which icon you clicked. The following list matches each icon in the BPL Visual Editor Toolbar with the BPL element it adds to the diagram. Icons are listed from top to bottom as they appear in the BPL Toolbar from left to right. The BPL Toolbar provides icons that add BPL diagram elements in three categories: activities, loops, and logic. Icons that Add Activities to a BPL Diagram BPL Icon Adds this Activity <alert> <assign> <call> <code> <delay> <empty> <reply> <rule> <sql> 140 Developing Ensemble Productions
Using the BPL Visual Editor BPL Icon Adds this Activity <sync> <trace> <transform> Icons that Add Loops to a BPL Diagram BPL Icon Adds this Loop <foreach> <while> <until> Icons that Add Logic to a BPL Diagram BPL Icon Adds this Logic <flow> Join (required for the diagram, no corresponding BPL element) <scope> <sequence> <if> Developing Ensemble Productions 141
Business Processes BPL Icon Adds this Logic <switch> 6.6.8 The Inspector Window The Studio Inspector window plays a large role in adding detail to a BPL diagram. When you click on an element in the BPL Visual Editor, its editable attributes display in the Inspector window. If the Inspector window is not visible in Studio, you can display it by selecting the View menu, Inspector option or by pressing Alt+1. For details about the attributes that you can edit for each type of BPL element, see the Ensemble Business Process Language Reference. 6.6.9 Import and Export of BPL Diagrams The user can export a BPL diagram to an XML file which can later be imported back into another Ensemble installation. The rules for doing this are the same as for importing or exporting any other Ensemble class to a file: In Ensemble Studio, use the Tools Export and Tools Import commands. 6.7 BPL Business Process Example The following sample business process is similar to a class in the sample production package Demo.Loan in the ENSDEMO namespace. In this business process, three different banks can be consulted for prime rate and credit approval information. /// Loan Approval Business Process for Bank Soprano. /// Bank Soprano simulates a bank with great service but /// somewhat high interest rates. Class Demo.Loan.BankSoprano Extends Ens.BusinessProcessBPL [ ClassType = persistent, ProcedureBlock ] { XData BPL { <process request="demo.loan.msg.application" response="demo.loan.msg.approval"> <context> <property name="creditrating" type="%integer"/> <property name="primerate" type="%numeric"/> </context> <sequence> 142 Developing Ensemble Productions
<trace value='"received application for "_request.name'/> <assign name='init Response' property="response.bankname" value='"banksoprano"'> <annotation> <![CDATA[Initialize the response object.]]> </annotation> </assign> <call name="primerate" target="demo.loan.weboperations" async="1"> <annotation> <![CDATA[Send an asynchronous request for the Prime Rate.]]> </annotation> <request type="demo.loan.msg.primeraterequest"/> <response type="demo.loan.msg.primerateresponse"> <assign property="context.primerate" value="callresponse.primerate"/> </response> </call> <call name="creditrating" target="demo.loan.weboperations" async="1"> <annotation> <![CDATA[Send an asynchronous request for the Credit Rating.]]> </annotation> <request type="demo.loan.msg.creditratingrequest"> <assign property="callrequest.taxid" value='request.taxid'/> </request> <response type="demo.loan.msg.creditratingresponse"> <assign property="context.creditrating" value="callresponse.creditrating"/> </response> </call> <sync name='wait' calls="primerate,creditrating" type="all" timeout="10"> <annotation> <![CDATA[Wait for the response from the async requests. Wait for up to 10 seconds.]]> </annotation> </sync> <switch name='approved?'> <case name='no PrimeRate' condition='context.primerate=""'> <assign name='not Approved' property="response.isapproved" value="0"/> </case> <case name='no Credit' condition='context.creditrating=""'> <assign name='not Approved' property="response.isapproved" value="0"/> </case> <default name='approved' > <assign name='approved' property="response.isapproved" BPL Business Process Example Developing Ensemble Productions 143
Business Processes value="1"/> <assign name='interestrate' property="response.interestrate" value="context.primerate+10+(99*(1-(context.creditrating/100)))"> <annotation> <![CDATA[Copy InterestRate into response object.]]> </annotation> </assign> </default> </switch> <delay name='delay' duration="2+($zcrc(request.name,4)#5)"> <annotation> <![CDATA[Wait for a random duration.]]> </annotation> </delay> <trace value='"application is " _$s(response.isapproved:"approved for "_response.interestrate_"%", 1:"denied")'/> </sequence> </process> } } 144 Developing Ensemble Productions
7 Business Operations A business operation is responsible for sending requests from Ensemble to an external application or system. Developing Ensemble Productions 145
Business Operations How a Production Fulfills Incoming Requests A business operation is responsible for the following activities: Waiting for requests from business services or business processes. Dispatching, via a message map, the request to a specific method within the business operation. Each method within a business operation class represents a specific action within an external application. Transforming the request object into a form usable by the associated outbound adapter and asking the outbound adapter to send a request to the external application. 146 Developing Ensemble Productions
Business Operation Life Cycle Returning, if requested, a response object to the caller. When a business operation receives an incoming request, it invokes the appropriate operations within external applications or databases, by accessing an appropriately configured outbound adapter for the application or database. Each business operation contains a message map that defines exactly which external operation to perform, depending on the type of Ensemble message that came into the business operation. The message map contains one or more entries, each mapping one request to the specific outbound adapter that is associated with the business operation. While a business operation is primarily responsible for delivering a request to the specific external application that contains a specific operation that needs to be performed, it can also send messages to other business operations or to business processes, as needed. Usually, however, the logic of the individual business operation is kept as simple as possible. Many productions provide a large set of extremely simple business operations and allow business processes to contain the logic that determines when each operation should be called. Within a business operation, the actual mechanics of sending a call outside Ensemble is typically delegated to an outbound adapter class. Factoring this behavior into two classes makes it easier to separate the production-specific logic within the business operation class from the more generic, technologyspecific logic of the outbound adapter class. Typically (the simpler) business operation classes are custom written for a production while (the typically more complex) outbound adapters are provided as reusable components within the Ensemble library. You can define a business operation with no associated outbound adapter class. In this case, the business operation itself must contain the logic needed to communicate with an external application. 7.1 Business Operation Life Cycle Ensemble automatically manages the life cycle of each business operation. When you start a production (or change the configuration of a specific business operation), Ensemble automatically performs the following tasks for each configured business operation class (that is, for every business operation listed in the production definition): 1. It invokes the class OnProductionStart callback method, if defined. The OnProductionStart method is a class method that is invoked once for each business operation class listed in the production configuration. A business operation class can use this callback to perform any class-wide initialization it may require. 2. It creates one or more background processes in which to execute the business operation. The number of background processes is determined by the business operation s PoolSize property within the production configuration. Each background process is referred to as an instance of the business operation and contains an instance of a business operation object. Developing Ensemble Productions 147
Business Operations Ensemble will only create a background process for a business operation if the following conditions are true: The business operation class must set its INVOCATION class parameter to Queue. The business operation s Enabled property within the production configuration must be set to 1 (otherwise the business operation is considered to be disabled). A disabled business operation still has an incoming message queue. Any requests posted to this queue will not be processed until the business operation is enabled. The business operation s PoolSize property within the production configuration must be set to a value greater than 0. If the business operation s Foreground property within the production configuration is set to 1, then Ensemble will create a foreground process (that is, it will create a Terminal window) for the business operation. This feature facilitates testing and debugging. 3. It initializes the system monitoring information used to monitor the status and operating history of the business operation. 4. Within each background process: a. Ensemble creates an instance of the business operation class, supplies the most recently configured values of any of the business operation s configurable properties (those defined as configurable using the SETTINGS parameter), and invokes the business operation OnInit callback method (if present). The OnInit method is an instance method that provides a convenient place to execute any initialization logic for a business operation. b. Ensemble creates an instance of the associated outbound adapter class (if one is defined) and supplies the most recently configured values of any of the outbound adapter s configurable properties (those defined as configurable using the SETTINGS parameter) 5. Once running, the business operation waits for requests to be sent (from business services, business processes, and other business operations) to its associated message queue. 6. After the business operation retrieves a request from its message queue, it searches its message map for the operation method that corresponds to the request type. It then invokes that operation method. 7. The operation method, using the data within the request object, makes a request to an external application. Typically it does this using one or methods provided by its associated outbound adapter object. An Ensemble production continues running until it is stopped, either programmatically or by an administrator using the Ensemble Management Portal. When a production stops, the following events related to business operations occur: 148 Developing Ensemble Productions
1. Ensemble waits for each business operation to reach a quiescent state (that is, Ensemble waits until each business operation has completed all of its synchronous requests). 2. The OnTearDown method in each outbound adapter is called. Business Operation Methods 3. All outbound adapter and business operation objects are destroyed and their background processes are killed. 4. Each business operation s OnProductionStop class method is called, once for each configured item of that class in the production. When a business operation is disabled by a system administrator, or becomes inactive according to its configured schedule, the production continues to run but the associated outbound adapter is shut down, and its OnTearDown method is executed. 7.2 Business Operation Methods A business operation class must provide one or more operation methods, each of which correspond to a specific action to be carried out within an external application. The business operation class determines which method to invoke by means of a message map. Additionally, a business operation class provides the operation methods OnInit, OnTearDown, OnProductionStart, and OnProductionStop, each of which has a common signature, as seen in the following example. The first argument is the incoming request object received by the message queue. The second is used to return an instance of a response object by reference. The operation method returns a %Status value indicating success or failure: Method MyMethod(pRequest As MyProduction.MyRequest, Output presponse As MyProduction.MyResponse) As %Status { // invoke a method of our Adapter object Set tsc =..Adapter.Send(pRequest.Value) // create a response object Set presponse = ##class(myproduction.myresponse).%new() Set presponse.value = 10 } Quit tsc A business operation class also provides methods to send messages to other business processes or to business operations, as follows: SendRequestSync sends a message synchronously (wait for a response), SendRequestAsync sends a message asynchronously (do not wait for a response), and SendDeferredResponse sends a response that was previously deferred by another business operation. Developing Ensemble Productions 149
Business Operations 7.2.1 The OnInit Method A business operation class may override the OnInit method. This method is called after the business operation object has been created and its configurable property values have been set. The OnInit method provides a way for a business operation to perform any special setup actions. Method OnInit() As %Status { Quit $$$OK } 7.2.2 The OnTearDown Method A business operation class may override the OnTearDown method. This method is called during shutdown before the business operation object is destroyed. The OnTearDown method provides a way for a business operation to perform any special cleanup actions. Method OnTearDown() As %Status { Quit $$$OK } 7.2.3 The OnProductionStart Method A business operation class may override the OnProductionStart method. This class method is called once for each configured business operation when a production is started. The OnProductionStart method provides a way for a business operation to perform any special business operation-wide setup actions. ClassMethod OnProductionStart() As %Status { Quit $$$OK } 7.2.4 The OnProductionStop Method A business operation class may override the OnProductionStop method. This class method is called once for each configured business operation when a production is stopped. The OnProductionStop method provides a way for a business operation to perform any special business operation-wide cleanup actions. ClassMethod OnProductionStart() As %Status { Quit $$$OK } 150 Developing Ensemble Productions
Business Operation Methods 7.2.5 The SendRequestSync Method A request is synchronous when the business operation invokes its SendRequestSync method to make the request. A call to SendRequestSync requires the business operation to wait, and do nothing else, until it receives a response from the call. To send a synchronous request from a business operation, use the SendRequestSync method as follows: Set tsc =..SendRequestSync(pTargetDispatchName, trequest,.tresponse) This method takes the following arguments: ptargetdispatchname The configuration name of the business process or business operation to which the request is sent. prequest Any persistent object, but typically a subclass of Ens.Request. This object contains the data to send with the request. presponse (By reference) Any persistent object, but typically a subclass of Ens.Response. This object receives the data returned by the response. ptimeout (Optional) The number of seconds to wait for a response. The default is 1 (wait forever). If no response is expected, you can use SendRequestAsync instead of SendRequestSync. 7.2.6 The SendRequestAsync Method A request is asynchronous when the business operation invokes itssendrequestasync method to make the request. A call to SendRequestAsync requires the business operation to fire and forget that is, the request is sent and the business operation continues its next activity without waiting for a response from the call. To send an asynchronous request from a business operation, use the SendRequestAsync method as follows: Set tsc =..SendRequestAsync(pTargetDispatchName, trequest) This method takes the following arguments: ptargetdispatchname The configuration name of the business process or business operation to which the request is sent. prequest Any persistent object, but typically a subclass of Ens.Request. This object contains the data to send with the request. Developing Ensemble Productions 151
Business Operations 7.2.7 Deferred Response Methods This topic describes the methods that business operations provide to support deferred response: For an overview of the feature that explains the role of a business operation, see the Deferred Response section in the Ensemble Messages chapter. 7.2.7.1 The DeferResponse Method This method returns a %Status value indicating success or failure. It provides one by-reference argument, token, which returns the deferred response delivery token required for a later call to SendDeferredResponse. For example: Set sc=..deferresponse(.token) // Send the token out somewhere... Quit $$$OK 7.2.7.2 The SendDeferredResponse Method A business operation can request information from an external system and then use this information to construct a deferred response. In this case, upon receiving the external data the business operation would call SendDeferredResponse to construct a response message and direct it to the caller that originated the request. The SendDeferredResponse call would look like this: Set sc =..SendDeferredResponse(token, presponsebody) SendDeferredResponse takes the following arguments: token A string that identifies the deferred response so that the caller can match it to the original request. The business operation obtains the token string through some mechanism unique to the production. presponsebody Any persistent object, but typically a subclass of Ens.Response. This object contains the actual response message. 7.3 Business Operation Properties Within an operation method, the following properties of the business operation class are available: 152 Developing Ensemble Productions
Suspending Messages Business Operation Properties Property %ConfigName %SessionId Adapter DeferResponse FailureTimeout Retry RetryInterval SuspendMessage Description The configuration name for this business operation. The session ID of the current message being processed. The associated outbound adapter for this business operation. To defer the response from this business operation for later delivery, set the DeferResponse property to the integer value 1 (true) and obtain a deferred response delivery token before exiting the business operation. The length of time (in seconds) during which to continue retry attempts. After this number of seconds has elapsed, give up and return an error code. See Retry and RetryInterval. Set this property to the integer value 1 (true) if you want to retry the current message. Typically, the retry feature is used when the external application is not responding and you wish to retry without generating an error. See RetryInterval and FailureTimeout. How frequently (in seconds) to retry access to the output system if this message is marked for retry. See Retry and FailureTimeout. Set this property to the integer value 1 (true) if you want the business operation to mark its current in-progress message as having Suspended status. See the section Suspending Messages. 7.4 Suspending Messages As described in the section Business Operation Properties, if you want the business operation to mark its current in-progress message as having Suspended status, set business operation property SuspendMessage to the integer value 1 (true). Typically a business operation will do this for messages that have been rejected by the external system for some reason. Ensemble places a Suspended message on a special queue. While the message waits there, you can use the Ensemble Management Portal to diagnose the problem and resend Suspended messages after the problem is fixed. For example, if the problem is on the external side of the communication, the external system can be repaired, and then the message can be resent. Developing Ensemble Productions 153
Business Operations It is possible to perform a simple resend using the [Ensemble] > [Maintenance] > [Suspended] page, or to choose a new destination for the message using the Resend Message option on the [Ensemble] > [Messages] page. The following sample method is from a business operation that sends a document to an external system. The method sets the SuspendMessage property to 1 if an error returns from the call to Validate the document that is about to be sent: Method validateandindex(pdoc As MyX12.Document) As %Status { If ""=..Validation '$zobjmethod(##this,"onvalidate",pdoc,..validation,.tsc) { Set tsc=##class(myx12.validator).validate(pdoc,..validation) } Set:'$D(tSC) tsc=$$$ok If $$$ISERR(tSC) { Set..SuspendMessage=1 Do..SendAlert(##Class(Ens.AlertRequest).%New($LB(..%ConfigName,"Suspended document "_pdoc.%id()_ " because it failed validation using spec '" _..Validation_"' with error "_ $$$StatusDisplayString(tSC)))) Quit tsc } If ""'=..SearchTableClass { TRY { Set tscstore=$zobjclassmethod(..searchtableclass,"indexdoc",pdoc) If $$$ISERR(tSCStore) $$$LOGWARNING("Failed to construct SearchTable entries") } CATCH errobj { $$$LOGWARNING("Failed to invoke SearchTable class") } } Quit $$$OK } 7.5 Message Maps A message map is an XML document, contained within an XData MessageMap block in the business operation host class. For example: Class MyProduction.Operation Extends Ens.BusinessOperation [ ProcedureBlock ] { XData MessageMap { <MapItems> <MapItem MessageType="MyProduction.MyRequest"> <Method>MethodA</Method> </MapItem> <MapItem MessageType="Ens.StringRequest"> <Method>MethodB</Method> </MapItem> </MapItems> } } 154 Developing Ensemble Productions
The operation of the message map is straightforward. When the business operation receives an incoming request, it searches, starting at the top of the message map, through each MapItem until it finds the first one whose MessageType attribute matches the type of the incoming message. It then invokes the operation method associated with this MapItem. Some things to keep in mind about message maps: Creating a New Business Operation Class The message map is searched from top to bottom; once a match is found, no more searching is performed. If the incoming request object is a subclass of a given MessageType then it is considered a match. If you want to filter out subclasses, be sure to place them above any super classes within the message map. If the incoming request does not match any of the MapItem entries, then an error is written to the Ensemble event log and the request is ignored. 7.6 Creating a New Business Operation Class A business operation host class is simply a class derived from Ens.BusinessOperation. To create a new business operation class, use Ensemble Studio as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Business Operation icon and click OK. 5. Enter a package and class name for the business operation. Click Next. Important: InterSystems recommends that you do not use the package names Demo, Ens, EnsLib, EnsPortal, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 6. If the business operation has an associated outbound adapter class, select it from the drop-down list. Developing Ensemble Productions 155
Business Operations 7. Select whether you want this business operation to use a queue (the default) or whether it is designed to work in-process. Choose Queued unless you have a very specific reason for using In Process. 8. Using the table, enter and edit Operation Methods and their associated request classes for the message map. To add, reorder or delete methods, click the icons to the right of the table. Each time you click the Add icon, a dialog prompts you as follows: Enter a Method Name. Choose a Request Type from a drop-down list of valid request classes. Choose a Response Type from a drop-down list of valid response classes. Enter a Condition that is a valid expression in the language of the business operation. Enter a text Description of the operation method. Click OK to save the method definition or Cancel to ignore it. 9. Click Finish to save your new business operation definition or Cancel to discard it. The resulting business operation class will look something like this: Class MyProduction.Operation Extends Ens.BusinessOperation [ ProcedureBlock ] { Parameter ADAPTER = "MyProduction.OutboundAdapter"; Parameter INVOCATION = "Queue"; XData MessageMap { <MapItems> <MapItem MessageType="MyProduction.MyRequest"> <Method>MyMethod</Method> </MapItem> </MapItems> } Method MyMethod(pRequest As MyProduction.MyRequest, Output presponse As MyProduction.MyResponse) As %Status { Quit $$$OK } } The ADAPTER parameter specifies the name of the associated outbound adapter class. The INVOCATION parameter specifies how the methods of a business operation are invoked. The typical value is Queue which specifies that this business operation runs within its own background job and defines its own message queue which is used to send requests to it. Alternatively, you can set the INVOCATION parameter to InProc. In this case there will be no background job or message queue created for this business operation. Instead, whenever a request is sent to this business operation, 156 Developing Ensemble Productions
Adding a Business Operation to a Production the business operation will be instantiated within the caller s job, and its methods will be invoked within that job, as well. InProc business operations should only be used for special cases. A business operation class defines one or more operation methods, such as MyMethod within the previous example. In order to dispatch messages to a specific operation method, a business operation also defines a MessageMap. A business operation class can define both configurable and non-configurable properties. To make a property configurable, simply add its name to the comma-delimited list of properties in the value of the class s SETTINGS parameter. The configuration display on the [Ensemble] > [Productions] page automatically provides the user interface needed to view and edit the configurable properties. For details, see the Configuration Settings section in the chapter Production Concepts. To fully implement this business operation, you must implement its operation methods as well as one or more of its callback methods, such as the OnInit method. 7.7 Adding a Business Operation to a Production To add a business operation to an Ensemble production, you must first identify (or create) the appropriate business operation host class, and then add the business operation to the production configuration using the Ensemble Management Portal as follows: 1. Start the Business Operation Wizard in one of the following ways: On the [Ensemble] > [Productions] > [Production Model] page, click Add Business Operation. While viewing the configuration diagram on the [Ensemble] > [Productions] page, do one of the following: - Left-click on the diagram background. A row of buttons displays below the diagram. Click Add Operation. - Right-click on the diagram to reveal the context menu. Choose Add, then Business Operation. 2. Choose one of the following types of business operation to add. Your choice determines the fields that display in the Business Operation Wizard form: HL7 Output - Choose TCP, File, or FTP to determine the host class. Each class already exists and requires no programming. Simply choose one. - Give the item a configuration Name. Do not use the characters ;:, Developing Ensemble Productions 157
Business Operations Other - Choose a host class from the OperationClass drop-down list. If the class you need does not appear on this list, create the class in Studio, then return to the [Ensemble] > [Productions] > [Production Model] page to choose it. - Give the item a configuration Name. Do not use the characters ;:, - Enter a text label in the Category field to sort and organize items within the production. Category names are case-sensitive, and space characters are allowed. To place an item in multiple categories, list them in the Category field separated by commas (do not allow spaces around these commas). - Comment is an optional text description. 3. Click OK to save your changes, Cancel to ignore them. 4. Business operations have operational settings whose values you must set from the configuration display on the [Ensemble] > [Productions] page. If you are already viewing that page, simply begin. To navigate to the configuration display from the [Ensemble] > [Productions] > [Production Model] page, click Configure Production. For full details and instructions about how to configure a business operation, see the Business Operation Settings section in the Configuration chapter of Managing Ensemble Productions. 158 Developing Ensemble Productions
8 Outbound Adapters An outbound adapter is responsible for sending requests to external systems. How a Production Relays Outgoing Requests The outbound adapter is a piece of code that adapts the native programming interface of an external application or external database into a form that is understandable to an Ensemble production. Each external application or database that serves a production by means of a business operation must have Developing Ensemble Productions 159
Outbound Adapters its own outbound adapter. However, not every method in the external application or database needs to be mapped to the outbound adapter; only those operations that the production requires. As with inbound adapters, no change to the external application itself is needed to create an outbound adapter. And, the adapter itself is conceptually simple: It relays requests, responses, and data between the production and a specific application or database outside the production. Outbound adapter classes work in conjunction with a business operation classes. In general, the outbound adapter contains general-purpose, reusable code while the business operation will contain productionspecific code (such as special processing logic). Typically you will implement your outbound adapter classes using one of Ensemble s built-in adapter classes. 8.1 Outbound Adapter Life Cycle The life cycle of an outbound adapter object is intertwined with that of its associated business operation object. When a production starts up, the following things related to outbound adapters occur: 1. When a production starts, it creates a background process for each of its configured business operations (there may be more than one process per business operation as specified by its configured PoolSize property). 2. Within each background process, an instance of the business operation class is created. 3. After the business operation object is created, an instance of its related outbound adapter class is created. 4. The values of any configurable properties of the outbound adapter object are set using the values specified by the production definition. 5. If present, the OnInit method of the outbound adapter is called. 6. When the business operation receives a request, one of its methods will call the methods of the outbound adapter in order to send a request to an external system. An Ensemble production continues running until it is stopped, either programmatically or by an administrator using the Ensemble Management Portal. When a production stops, the following events related to outbound adapters occur: 1. Ensemble waits for each business operation to reach a quiescent state (that is, Ensemble waits until each business operation has completed all of its synchronous requests). 2. The OnTearDown method in each outbound adapter is called. 3. All outbound adapter and business operation objects are destroyed and their background processes are killed. 160 Developing Ensemble Productions
Outbound Adapter Methods 4. Each business operation s OnProductionStop class method is called, once for each configured item of that class in the production. When a business operation is disabled by a system administrator, or becomes inactive according to its configured schedule, the production continues to run but the associated outbound adapter is shut down, and its OnTearDown method is executed. 8.2 Outbound Adapter Methods At minimum, an outbound adapter class contains the following operation methods: OnInit and OnTearDown. 8.2.1 The OnInit Method An outbound adapter class may override the OnInit method. This method is called after the outbound adapter object has been created and its configurable property values have been set. The OnInit method provides a way for an outbound adapter to perform any special setup actions. For example, the following OnInit method establishes a connection to an output device when the outbound adapter is started (assuming that this outbound adapter also implements a ConnectToDevice method): Method OnInit() As %Status { // Establish a connection to the output device Set tsc =..ConnectToDevice() Quit tsc } 8.2.2 The OnTearDown Method An outbound adapter class may override the OnTearDown method. This method is called during shutdown before the outbound adapter object is destroyed. The OnTearDown method provides a way for an outbound adapter to perform any special cleanup actions. For example, the following OnTearDown method closes a connection to an output device when the outbound adapter is stopped (assuming that this outbound adapter also implements a CloseDevice method): Method OnTearDown() As %Status { // close the output device Set tsc =..CloseDevice() Quit tsc } Developing Ensemble Productions 161
Outbound Adapters 8.3 Creating a New Outbound Adapter Class An outbound adapter is simply a class derived from the Ens.OutboundAdapter class. The easiest way to create a new outbound adapter class is to use the Ensemble Studio, as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Adapter icon and click OK. 5. Enter a package and class name for the outbound adapter. Click Next. Important: InterSystems recommends that you do not use the package names Demo, Ens, EnsLib, EnsPortal, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 6. For Adapter Type, choose Outbound. 7. Enter and edit Properties using the table. To add, reorder or delete properties, click the icons to the right of the table. Each time you click the Add icon, a dialog prompts you as follows: Enter the property Name. If you want this property to be editable from the configuration display on the Ensemble Management Portal [Ensemble] > [Productions] page, select the Configurable check box to the right of the Name field. Enter a data Type or choose one by clicking the Browse icon to the right of this field. Enter a text Description of the property. Click OK to save the property definition or Cancel to ignore it. 8. Click Finish to save your new outbound adapter definition or Cancel to discard it. The resulting outbound adapter class will look something like this: 162 Developing Ensemble Productions
Class MyProduction.OutboundAdapter Extends Ens.OutboundAdapter [ ProcedureBlock ] { Parameter SETTINGS = "IPAddress,TimeOut"; Property IPAddress As %String(MAXLEN=100); Property TimeOut As %Integer(MINVAL=0, MAXVAL=10); Property Counter As %Integer; } Creating a New Outbound Adapter Class An outbound adapter class can define both configurable properties (like IPAddress and TimeOut in the previous example) and non-configurable properties (like Counter in the previous example). To make a property configurable, simply add its name to the comma-delimited list of properties in the value of the class s SETTINGS parameter. The configuration display on the [Ensemble] > [Productions] page automatically provides the user interface needed to view and edit the configurable properties. For details, see the Configuration Settings section in the chapter Production Concepts. To fully implement an outbound adapter, you must implement one or more methods for the corresponding business operation to invoke. Every outbound adapter is free to define its own API (set of methods) that its associated business operation classes use. Developing Ensemble Productions 163
9 Production Data The moment any piece of data comes into Ensemble, it is recast as an Ensemble object, and remains an Ensemble object for its entire lifespan inside Ensemble. This convention enables systems to exchange incompatible data across a format-free zone (that is, Ensemble) without adversely affecting other residents of that zone. All data is seen in a universal, abstract format. This is the principle called data abstraction. The motivation behind Ensemble abstraction is somewhat similar to the motivation behind the XML standard, which is the establishment of a format-free zone. However, there is a key difference in approach: Ensemble is designed, not simply to enable format-free data exchange, but to do so in a consistently compact, efficient, and streamlined manner. XML offers no facility for ensuring speed. Speed is possible for Ensemble data abstraction because Ensemble incorporates InterSystems core technologies such as a multidimensional data engine, high-performance persistent engine, object engine, data transformation engine, and others, to ensure the highest possible efficiency of transforming the otherwise incompatible data from many lands. Data abstraction can be understood to have two tiers. The first tier of data abstraction is mandatory when the data first enters the system. At this first tier, data is transformed from any external formats (for example Health Level 7 (HL7) or Electronic Data Interchange (EDI) formats) into an Ensemble object. This transformation is handled on the incoming side by inbound adapters; on the outgoing side by outbound adapters. If built-in adapters are used, a production developer does not need to know a great deal about the transformation that is achieved, only that it is necessary for the adapter to work. There is also a second tier of data abstraction. In this tier, an Ensemble object of any type may be transformed into an Ensemble object of any other type. Such a transformation may occur at any time during the lifespan of an Ensemble object. It may occur multiple times, a few times, once, or never. To enable this type of data transformation the production developer must provide an appropriate data transformation object to tell Ensemble what to do. That is, you must provide a class definition that maps properties from one type of object to another. This object stores the information required to achieve the transformation. It is called a data transformation object. Ensemble includes a specialized language called Data Transformation Language (DTL), an extension of XML. DTL permits a developer Developing Ensemble Productions 165
Production Data to explicitly specify data transformation classes without needing to supply exhaustive programming details. The DTL compiler generates the infrastructure for you when you save the class. It is possible to bypass all forms of data abstraction and pass raw, untransformed external data through Ensemble as a payload. Entire data streams can be handled in this manner. However, these strategies are not common. The general case is to use data abstraction and data transformation as described in this chapter. Topics include: Data Transformations Using the DTL Visual Editor Federated Databases Data Persistence and Data Recovery 9.1 Data Transformations A data transformation is a utility object that maps an object of one type into an object of another type. It does this by mapping specific fields from the first object into receiving fields in the second object. Any production entity business service, business process, business operation can use a data transformation at any time it is needed. The use of data transformations inside a production can be as simple or complex as the integration solution requires. 166 Developing Ensemble Productions
Data Transformations The Data Transformation Utility Object The primary purpose of a data transformation is to convert the items received in a response message into the parameters needed to issue a new, follow-on request message. This means that the source and target objects for data transformation are usually Ensemble message objects as described in the chapter Ensemble Messages. These consist of a message header and a message body object. When you transform a message what your data transformation really does with the message is to swap out the old message body object (the source) and exchange it for a new one (the target). Some of the transformations that occur during this process can include: Copy values from properties on the source to properties on the target. Perform calculations using the values of properties on the source. Copy the results of calculations to properties on the target. Assign literal values to properties on the target. Ignore any properties on the source that are not relevant to the target. All of this is controlled by the code within the data transformation. Developing Ensemble Productions 167
Production Data 9.1.1 Data Transformation Classes A data transformation class is a subclass of Ens.DataTransform that specifies: The name of the input ( source ) class The name of the output ( target ) class A series of operations that assign values to the properties of the output object. Each assignment operation consists of a call to the Ens.DataTransform class method Transform. The argument is a simple expression that is evaluated to provide the value for one of the properties in the output class. The language of the expression can be Caché Basic or ObjectScript, and the expression can contain: Literal values Any property in the general-purpose execution context variable called context Properties on the source object Functions and operators from the expression language Calls to methods provided by Ensemble Calls to user-provided methods 9.1.2 Creating a New Data Transformation You can implement Ensemble data transformations in two different, but equally valid ways: Using Data Transformation Language (DTL), a specification based on XML that automatically generates data transformation code from a DTL document or from its corresponding graphical representation. Ensemble generates this type of data transformation as a subclass of the Ens.DataTransformDTL class. It is identical in every way to a class derived from Ens.DataTransform, except that it supports the Ensemble Data Transformation Language (DTL). Using custom code, by creating a subclass of the Ens.DataTransform class and implementing its Transform method. In either case you can begin by using Ensemble Studio, as follows: 1. Start Studio and choose an Ensemble-enabled user namespace. Important: InterSystems recommends that you do not place custom code or data in the systemprovided namespaces ENSLIB or ENSDEMO where it will be deleted the next time you upgrade Ensemble. The ENSEMBLE namespace and any new namespace that you create to hold your work is preserved across Ensemble upgrades. 168 Developing Ensemble Productions
Data Transformations 2. From the File menu select New. 3. The New dialog displays. Select the Production tab. 4. Select the Data Transformation icon and click OK. 5. Enter a package and class name for the data transformation. Click Next. Important: InterSystems recommends that you do not use the package names Demo, Ens, EnsLib, EnsPortal, or CSPX. This causes your work to be deleted the next time you upgrade Ensemble. 6. Select Using the DTL Editor (suggested) or Using Custom Code. 7. In the Source Class field, use the drop-down list to choose a class name, or type a class name in the Source Class field. 8. If the class you select is an HL7 or X12 message class, then you must choose or type the name of a Source Doc Type as well. 9. Repeat the two previous steps for Target Class and (for HL7 or X12 messages) Target Doc Type. 10. Click Finish. The dialog closes. 11. The next step depends on your selection in step 6. If you selected: Using the DTL Editor, the DTL Visual Editor opens a visual representation of the data transformation in the top half of the Class Editor window. The properties of the source class are listed on the left side, the target on the right. The bottom half of the screen displays the DTL representation of the class. The source and target classes. are identified, but otherwise the transformation is empty. You may begin work as described in the section Using the DTL Visual Editor. Using Custom Code, you must implement the Transform method for the new data transformation class. 9.1.3 DTL Data Transformation Examples DTL is similar to the Ensemble Business Process Language (BPL), but DTL provides a limited number of elements whose only purpose is to support data transformations. These are: <assign>, <code>, <foreach>, <if>, <sql>, <trace>, and <transform>. Each of these elements has syntax differences in DTL compared with its definition in BPL. You can use the DTL Visual Editor to generate a DTL data transformation class from a graphical user interface. To learn more about the DTL Visual Editor, continue with this chapter. For full DTL syntax details, see the Ensemble Data Transformation Language Reference. Developing Ensemble Productions 169
Production Data The following is an example of a DTL data transformation class. The DTL <transform>, <trace>, and <assign> statements appear within an XData DTL block in the class code: Class User.NewDTL1 Extends Ens.DataTransformDTL [ ProcedureBlock ] { XData DTL { <?xml version="1.0"?> <transform targetclass='demo.loan.msg.approval' sourceclass='demo.loan.msg.approval' create='new' language='objectscript'> <assign property='target.bankname' value='..toupper(source.bankname)' action='set'/> <trace value='changed all lowercase letters to uppercase!' /> </transform> } } In this example, the target property BankName gets the value of the source property BankName, but only after this value is converted to all uppercase characters. To accomplish this conversion, the data transformation references a function called ToUpper using double-dot syntax as if it were a method in the class. ToUpper is one of a number of utility functions available for use in Ensemble data transformations and business rules. For details, see the Utility Functions section in the chapter Production Concepts. 9.2 Using the DTL Visual Editor When you open a DTL data transformation in Ensemble Studio, or when you create a new DTL data transformation, the DTL Visual Editor displays simultaneous code and diagram representations of the DTL document. The diagram appears in the top half of the window and the DTL code in the bottom half. Within the diagram, the source (input) object appears on the left and the target (output) object on the right. Lines connect the source and target objects across a center divider. 170 Developing Ensemble Productions
Using the DTL Visual Editor DTL Visual Editor, Diagram and Code View Each connector in a DTL diagram corresponds to a statement in the DTL code: <assign>, <if>, or <foreach>. The overall purpose of these statements is to: 1. Identify the source properties to be transformed 2. Perform operations on the source properties (if needed) 3. Copy the results into target properties The next several topics explain how to add new statements to a DTL diagram using the DTL Visual Editor, how to edit statements that are already present in the diagram, or how to remove statements that are no longer needed. 9.2.1 Synchronizing Graphics and Code When you edit the DTL diagram in the top half of the screen, your changes automatically appear in the DTL code in the bottom half of the screen. Items that cannot be entered using the diagram may be added by typing lines of code in the DTL code view. Developing Ensemble Productions 171
Production Data After you edit the DTL code in the bottom half of the screen, simply click on the background of the diagram to update the graphics. Selecting Compile in the Studio toolbar also updates the graphics. 9.2.2 DTL Diagram Column Headers Each column header lists the following information, from top to bottom: Whether this column is the Source or Target column The Ensemble message class, for example EnsLib.HL7.Message For HL7 or X12 messages, the schema category and message structure, for example Demo.HL7.MsgRouter.Schema:ORM_O01 At the left of each column is a positional controller that allows you to move the column header up or down relative to the display. Scrolling in this manner applies to each column separately. You can also click on the neutral background of the column and drag the mouse up or down. The column contents follow the direction of the drag. 9.2.3 Using the Inspector Window Whenever any DTL statement is selected in the DTL Visual Editor window, its attributes display in the Ensemble Studio Inspector window, where you can edit the attributes. If you do not see the Inspector window within Studio, click the View Inspector icon to reveal it. In the following figure, an <assign> connector is selected and the Inspector window displays the editable <assign> attributes property, value, and action. 172 Developing Ensemble Productions
Using the DTL Visual Editor DTL Visual Editor with Inspector Window You can edit any attribute in the Inspector window by clicking on its name or value in the window. For enumerated types like the language attribute, click the values. For longer strings, click the 9.2.4 DTL Diagram Context Menu drop-down icon to display a list of valid popup icon to display a window in which to enter the text. A context-sensitive menu of commands is available for you to use in the DTL Visual Editor. To display the DTL diagram context menu, position the cursor on a DTL diagram and right-click. The following options display: Zoom Choose a zoom factor for the DTL diagram. Choose a large factor to view details, a small factor to gain an overview. Add Action To add an activity to the diagram, left-click in the neutral background, right-click to reveal the context menu, and choose Add Action followed by assign, if, or foreach. Edit Action To change details of an existing activity, left-click on a statement connector in the center bar that separates the two columns of the DTL diagram. Right-click to reveal the context menu. Choose Edit Action. Remove Action To remove an existing activity, left-click on a statement connector in the center bar. Right-click to reveal the context menu. Choose Remove Action. Remove All Remove all activities from the DTL diagram. Set Parent Action When you are editing an <if> activity, use this option to navigate between its <true> and <false> cases. See the section Building an If Statement. Developing Ensemble Productions 173
Production Data Clear Parent Action After you have edited the <true> and <false> cases for an <if> activity, use this option to exit the <if> activity and return to the main diagram. See the section Building an If Statement. Find, Find Again Find and Find Again let you search for a text string in the underlying DTL document. When found, the corresponding string is highlighted in the DTL diagram. Test Transformation Displays a dialog where you can enter a sample message and display the results when Ensemble applies the data transformation to that message. About SVG Viewer Display version and copyright information about the SVG Viewer used by the DTL Visual Editor. 9.2.5 Alternate Views of DTL Code While viewing the DTL diagram of a data transformation, you can change to the DTL class view of the same data transformation by selecting View Other in the Studio toolbar. The result is as shown in the following figure. The DTL code appears within an XData DTL block in the class code. DTL Visual Editor, Class Code View After selecting Compile in the Studio toolbar, you can view the generated class code for the data transformation. From the DTL class code view (shown in the previous illustration) select View Other. The generated code version of the data transformation displays, as shown in the following figure. Note: You can cycle through the DTL Visual Editor view, class code view, and generated code view by clicking View Other repeatedly. 174 Developing Ensemble Productions
Using the DTL Visual Editor DTL Visual Editor, Generated Code View 9.2.6 Assigning Values from Source to Target A data transformation consists mostly of <assign> statements that copy values from properties of the source to properties of the target. It is easy to add a new <assign> statement to a DTL data transformation by dragging and dropping a connector between source and target: 1. Left-click on the circle tab to the right of the source property. Hold down the mouse button. The display looks like this: Developing Ensemble Productions 175
Production Data 2. Drag the cursor to the triangle tab to the left of the target property. The display looks like this: 3. Release the left mouse button. The display looks like this: An <assign> connector draws a line from a source property to a target property, leaving an anchoring dot on the center divider. To select an <assign> connector it is easiest to click on the dot, rather than trying to achieve an exact hit on the line itself. When you click on the dot, it changes color, the connector line turns bold, and the source and target property are highlighted in color. This means the <assign> connector is selected, as shown in the following figure. Connector from Source to Target 9.2.7 Assigning a Literal Value to a Target You can assign a literal value to a target property. To do this, select the target property and right-click to reveal the context menu. Choose Add Action and assign. A dialog pops up. Type a literal numeric or string value in the Expression field and click OK. The literal value assignment is represented by a square dot in the center divider. A connector begins at this square and terminates at the target property, as shown in the following figure. To select the literal assignment connector, click on the square dot. 176 Developing Ensemble Productions
Connector from Literal Value to Property in Target Using the DTL Visual Editor 9.2.8 Editing Expressions for Assign Statements The DTL Visual Editor provides a helpful wizard to make it easier to construct valid <assign> statements. To start the wizard, choose Add Action or Edit Action from the context menu. Important: Add Action and Edit Action allow you to enter an expression that references more than one source property. This is not possible when you use drag-and-drop to assign the value of a single source property to a single target property. You can start the DTL Assign Wizard in one of the following ways: Left-click on a target property in the DTL diagram. Right-click to reveal the context menu. Choose Add Action. Left-click on an <assign> statement connector in the DTL diagram. Right-click to reveal the context menu. Choose Edit Action. In either case, a dialog similar to the following displays. DTL Visual Editor <assign> Wizard Use this dialog as follows: In the Expression field, you may enter: - Literal values - Function calls - The names of source properties Developing Ensemble Productions 177
Production Data - Any combination of these The Expression field can only contain one line of text, and it must be written in the native scripting language of the data transformation (ObjectScript or Caché Basic). The Expression field displays the name of this language in square brackets. If you want to use an Ensemble function in the expression, you may click the f(x) button next to the Expression field. A dialog similar to the following displays. Use this dialog as follows: - When you choose a Function from the drop-down list, more fields display as needed to define the function. You may edit the fields as instructed by the context-sensitive help in the dialog. - The ReplaceStr function shown in the following example is one of a number of utility functions available for use in Ensemble data transformations and business rules. For details, see the Utility Functions section in the chapter Production Concepts. You can click the Help button on the dialog to display this documentation online. - Click OK to save changes, Cancel to exit the dialog without saving. Control returns to the <assign> dialog. Select an Action from the drop-down list. Set is the default action for <assign>. Click the Help button to display documentation for the <assign> element. Click OK to save changes, Cancel to exit the dialog without saving. Control returns to the DTL diagram. 178 Developing Ensemble Productions
Using the DTL Visual Editor 9.2.9 Working with Nested Properties Nested properties, or sub-properties, are found in virtual documents, a type of message body used to contain the complex, structured data typical of Electronic Data Interchange (EDI) formats. For details about this convention, see Ensemble Virtual Documents. This topic describes how the DTL Visual Editor handles nested properties. When a connector is a solid line, it means that the diagram shows the actual properties involved in the <assign>, <if>, or <foreach> statement. When one or both sides of a connector are dashed lines, a nested sub-property is involved on the side where the dashed line appears. Connector from Source to Parent Property in Target You can make this nested property visible by clicking on the expansion icon next to the parent property name to display the sub-properties. While the parent property is expanded, it displays a contraction icon that you can click to hide the sub-property list. A previously expanded property that is now contracted displays a darkened expansion icon. Connector from Source to Nested Property in Target 9.2.10 Assigning All Nested Properties If parent properties in the source and target are identical, you can assign the values of all the nested sub-properties at once. In this case there is no need to expand the parent properties to reveal the subproperties. Simply drag the cursor from the parent property on the source side to the parent property on the target side. In the following DTL diagram, the single connector between the EVN property on the source side and the EVN property on the target side includes all of the following sub-properties of EVN: Developing Ensemble Productions 179
Production Data EventTypeCode RecordedDateTime and all of its sub-properties DateTimePlannedEvent and all of its sub-properties EventReasonCode OperatorID, all of its iterations, and all of its sub-properties EventOccurred and all of its sub-properties Connector Between Two Identical Parent Properties The following single line of DTL code accomplishes the same task: <assign property='target.{evn}' value='source.{evn}' action='set' /> 180 Developing Ensemble Productions
Using the DTL Visual Editor 9.2.11 Building an If Statement A DTL <if> element evaluates a condition that consists of a logical expression in the native scripting language of the data transformation (ObjectScript or Caché Basic). The result of this expression is either true or false. The <if> element may contain one <true> element and one <false> element. If the condition is true, the data transformation executes activities within the <true> element; if false, the <false> element. If either element is missing when needed, the <if> simply skips execution and passes control to the next element in the data transformation. You can build an <if> statement using the DTL visual editor. To do this, select a source property and right-click to reveal the context menu. Choose Add Action and if. A dialog similar to the following displays. The Condition field in this dialog works just like the Expression field in the <assign> wizard dialog. For details, see the section Editing Expressions for Assign Statements. DTL Visual Editor <if> Wizard After you click OK, the DTL diagram displays a new connector that begins at the source property and terminates in a diamond dot in the center divider between the source and target objects. To select the <if> connector, click on the diamond dot. Connector from Source Property to If Statement The <if> statement appears at the bottom of the DTL code, just before the end of the <transform> container. It contains one blank <true> element and one blank <false> element: To add statements to the <true> element, left-click on the <if> connector diamond dot. Right-click to reveal the context menu and choose Set Parent Action. The dot outline changes color to green. Add <assign> statements using any of the techniques described in this topic, including drag-anddrop, expressions, or literal assignments. You can add <if> or <foreach> statements as well. Developing Ensemble Productions 181
Production Data Tip: Remember to select a target property before trying to add an <assign> statement. Select a source property before adding an <if> or <foreach>. As you add statements, connectors appear in the DTL diagram and DTL statements appear within the <true> element in the DTL code window. When you have finished adding statements to the <true> element, left-click on the <if> connector diamond dot. Right-click to reveal the context menu. Choose Set Parent Action to edit the <false> case (the dot outline changes from green to red) or choose Clear Parent Action to stop editing the <if> statement (the dot outline color returns to blue). To add statements to the <false> element, left-click on the <if> connector diamond dot. Rightclick to reveal the context menu and choose Set Parent Action twice. The dot outline changes color from blue to green to red; this confirms that you are editing the <false> case. Add <assign>, <if>, or <foreach> statements as described in this topic. When you have finished adding statements to the <false> element, left-click on the <if> connector diamond dot. Right-click to reveal the context menu. Choose Set Parent Action to edit the <true> case (the dot outline changes from red to green) or choose Clear Parent Action to stop editing the <if> statement (the dot outline color returns to blue). 9.2.12 Building a Foreach Statement The <foreach> element defines a sequence of activities that are executed iteratively, once for every element in a collection, or for repeating properties such as are found in HL7 documents. You can build a <foreach> statement using the DTL visual editor. To do this, select a collection or repeating property in the source message and right-click to reveal the context menu. Choose Add Action and foreach. A dialog similar to the following displays. The Loop Property field automatically contains the name of the source property that you had selected. You may change the name of the Loop Key variable if you wish. DTL Visual Editor <foreach> Wizard 182 Developing Ensemble Productions
After you click OK, the DTL diagram displays a new <foreach> connector that begins at the source property and terminates in a diamond dot. This looks just like the <if> connector. Connector from Source Property to Foreach Statement Using the DTL Visual Editor The corresponding <foreach> statement appears at the bottom of the DTL code, just before the end of the <transform> container. It names a property and a key for iterating over that property. Immediately after you add a new <foreach> element, it automatically becomes the parent action for any <assign>, <if>, or <foreach> statements that you might subsequently add. This means that each new element that you create appears inside the <foreach> element in its location at the bottom of the DTL code. This behavior continues until you Clear Parent Action as described in this topic. If you want to add statements to a <foreach> during a later editing session, you can left-click on the <foreach> diamond dot to select the statement, right-click to reveal the context menu, and choose Set Parent Action. While a <foreach> is the parent action, you can add <assign> statements using any of the techniques described in this topic, including drag-and-drop, expressions, or literal assignments. You can add <if> or <foreach> statements as well. Tip: Remember to select a target property before trying to add an <assign> statement. Select a source property before adding an <if> or <foreach>. As you add statements to the <foreach> element, connectors appear in the DTL diagram and DTL statements appear within the <foreach> element in the DTL code window. When you have finished adding statements to the <foreach> element, left-click on the <foreach> diamond dot. Right-click to reveal the context menu. Choose Clear Parent Action. The dot outline color returns to blue. 9.2.13 Editing the DTL Code The Ensemble Data Transformation Language has elements that cannot be entered using the DTL Visual Editor. These include <sql>, <code>, and <trace>. You can add or edit elements such as these in fact, any DTL statement by typing lines of code into the DTL code view at the bottom of the DTL Visual Editor screen. After you edit the DTL code in the bottom half of the screen, simply click on the background of the diagram to update the graphics. Selecting Compile in the Studio toolbar also updates the graphics. Developing Ensemble Productions 183
Production Data 9.2.14 Testing the DTL Data Transformation When you right-click to reveal the DTL Visual Editor context menu and select Test Transformation, Studio displays a dialog similar to the following. DTL Transformation Test Window Initially the Output Message window is blank and the Input Message window contains a text skeleton in a format appropriate to the source message: For HL7 or other EDI messages, the window displays raw text For regular Ensemble messages, the window displays an XML skeleton with an entry for each of the properties in the message object. To use this dialog: 1. Edit and compile the DTL data transformation class. 2. Right-click to reveal the context menu and select Test Transformation. 3. Edit the Input Message so that it contains appropriate data: 184 Developing Ensemble Productions
For HL7 or other EDI messages, have some saved text files ready so that you can copy and paste text from these files into the Input Message area. For regular Ensemble messages, type in a value for each property. 4. Click Test. The Output Message window displays the results of the data transformation. 5. Repeat steps 3 and 4 as needed. 6. To exit the dialog, click Close. Federated Databases 9.2.15 Import and Export of DTL Diagrams The user can export a DTL diagram to an XML file which can later be imported back into another Ensemble installation. The rules for doing this are the same as for importing or exporting any other Ensemble class to a file: In Ensemble Studio, use the Tools Export and Tools Import commands. 9.3 Federated Databases A production can access an external database via a call to a business operation and outbound adapter. In this case, the scope of possible activities is limited to the methods on the business operation. In other cases, you would like to be able to treat a variety of data sources local and external as if all of them were local to the Ensemble storage engine. A federated database gives you this option. A federated database is a logical construct that automatically determines the appropriate destination for every data request: either the Ensemble database, or an external database via designated connection information. The required mappings must be encoded into the production by its developers. At runtime, configured production items such as business services, business processes, and business operations can use the federated database without actually knowing where the data is. They access all data as if it were local to Ensemble. Developing Ensemble Productions 185
Production Data How a Production Relays Requests via a Federated Database The technology used to set up a federated database is called the SQL Gateway. It can be used with any external database that has an ODBC compliant interface. Additionally, you can permit a non- ODBC database to participate in a federated database by using an outbound adapter to present the non- ODBC database as an ODBC database. For programming details see Using the SQL Gateway. 9.4 Data Persistence and Data Recovery In the event of a planned or unplanned shutdown, Ensemble provides a high degree of recoverability. That is, when the system is restarted it can resume execution with little to no interruption in service. The degree of recovery depends on several factors: the robustness of the external applications; implementation details of the various business services, business processes, and business operations, and the nature of the outage itself. 186 Developing Ensemble Productions
Data Persistence and Data Recovery The following runtime production data is stored in the Ensemble persistent engine to aid in recovery of the system if some sort of breakdown should occur: Message header and body for every message A full archive of the header and body of every message the production has generated since it last started, or since messages were last purged. Session IDs Every business service stores a persistent session ID to identify any initial request that comes into the production. This session ID marks any subsequent message that is issued anywhere within Ensemble to try to complete the initial request. The existence of the session ID, the message archive, and archive search capabilities mean that a system administrator can request a trace of all the messages generated to satisfy a specific incoming request. Suspended messages A business operation can be designed to suspend any messages that fail; such a message goes on a persistent queue where Ensemble keeps all Suspended messages. Later, a system administrator can use the Ensemble Management Portal to diagnose the problem, and resend Suspended messages after the problem is fixed. For example, if the problem is on the external side of the communication, the external system can be repaired, and then the message can be resent. Business rule definitions A business rule provides a simple description of the logic required to make a decision during execution of a business process. Rules are created using the Ensemble Management Portal and stored in the Ensemble database. Runtime statistics, rule log entries, event log entries Ensemble archives detailed records regarding the execution history of business processes, business rules, jobs, and other system entities. Any runtime data that you can view in real time using the Ensemble Management Portal resides in the local Ensemble database, and remains persistent across system outages. Business process execution context Every BPL business process provides execution context variables in which state information is persistently saved to disk and restored from disk, whenever the business process suspends or resumes execution. This feature is especially important for longrunning business processes, which may take days or weeks to complete. Developing Ensemble Productions 187
10 Business Logic This chapter describes Ensemble features that enable non-technical users to assess and direct the flow of application logic in order to meet business goals. These features are: Business Rules Business Activity Monitoring Workflow Each feature has its own book in the Ensemble documentation set. This chapter provides an overview of each feature and explains where to find more information about it. 10.1 Business Rules Business rules allow non-technical users to change the behavior of Ensemble business processes at specific decision points. The logic of the rule can be changed instantly, using a simple forms-based interface in the Ensemble Management Portal. There is no need for programming or diagramming skills to change the rule, and there is no need to modify or compile production code for changes to take effect. Suppose an enterprise runs an Ensemble production that processes loan applications consistently across an international enterprise. The decision process is consistent worldwide, but analysts need to adjust the local acceptance criteria from country to country. Business rules support this division of responsibility as follows: 1. The developer of the business process identifies a decision point, by naming the business rule that will make the decision on behalf of the business process. The business process code does not contain the rule; it references the rule by name. In our example, this rule could be called LoanDecision. Developing Ensemble Productions 189
Business Logic 2. A user at the enterprise, typically a business analyst, defines the rule using a browser-based online form called the Business Rule Editor. This form prompts the user for the simple information required to define a business rule called LoanDecision. Analysts at each regional location run the Business Rule Editor to define specific criteria for the rule. 3. At runtime, the business process invokes the LoanDecision rule. The rule retrieves its decision criteria from the Ensemble configuration database. Based on these criteria, the rule returns an answer to the business process. The business process continues execution based on this answer. Ensemble allows you to define the following types of business rule: Rule set A list of rules that are evaluated sequentially until one of them is found to be true. The true case determines the next action of the business process that invoked the rule. If none of the rules is true, a default value is returned. This is the type of rule that is invoked using the BPL <rule> element. For details, see the book Using Business Rules with Ensemble. Routing rule set A special-purpose rule set for use in message routing productions. For details, see the chapter Message Routing, later in this book. 10.2 Business Activity Monitoring Ensemble includes all the elements you need to provide business activity monitoring (BAM) as part of an enterprise integration project. Ensemble makes business activity monitoring simple to implement and efficient to operate. End users view a set of customized, browser-based corporate dashboards that provide graphical display of real-time information. An Ensemble dashboard is a Web page that displays one or more graphical controls (meters) each of which displays the current value of a metric property. Ensemble supports business activity monitoring with the following elements: Business metrics are specialized business service classes that gather or otherwise calculate specific measured data called metrics. After you add a business metric to a production, it is automatically triggered to calculate its metric values at the time interval specified by its CallInterval configuration setting. These calculations can take a variety of forms, involving calls to business operations, federated databases, the Ensemble storage layer, or any arbitrary source code contained within the business metric class. Dashboards are Web pages that provide a real-time, graphical display of metric values. Each dashboard presents one or more meters; that is, graphical elements that display the current value of a specific metric property within a specific business metric class. Ensemble provides a complete 190 Developing Ensemble Productions
set of built-in meters that includes speedometers, odometers, fuel gauges, light bars, traffic lights, indicator lights, line charts, and bar charts. It is also possible to develop custom meters. For additional details, see the book Using Dashboards with Ensemble. Workflow 10.3 Workflow Workflow makes it possible to incorporate human interaction into automated business processes. Uses of workflow within the enterprise might include order entry, order fulfillment, contract approval, or help desk activities. An Ensemble production achieves workflow using a business process. A business process receives a request, organizes the tasks required to fulfill that request, and then calls upon business operations to perform these tasks. In this way, a business process distributes tasks to participating resources for fulfillment. The resource that fulfills a task on behalf of an Ensemble business process may be an external application or database, or it may be a person. Workflow comes into play when the resource needed to participate in an Ensemble business process is a person: a member of an organization who fulfills a specific role within the enterprise. A typical example of workflow in an enterprise would be a help desk that accepts problem reports from customers, routes the reports to members of the appropriate organizations for action, and upon resolution of the problem, reports the results to the customer. While a workflow resource is a person, it need not be a specific person. Any one of several people might be able to fulfill a certain kind of task. Therefore, to organize distribution of tasks to people, Ensemble permits the definition of workflow roles. A workflow role is a list of users that can fulfill a certain kind of task. Roles generally map to departments or job positions within in the enterprise, such as Accounting, Finance, Teller, Manager, Supervisor, or Director. Any number of workflow users may be members of a workflow role. Assignment of users to roles should make sense from a practical and organizational standpoint. If a person is authorized to perform a task, that person should be a member of the corresponding workflow role. A task is an item of work. A long-running business process may call upon resources that are online (that is, software within the integrated solution) or offline (that is, actions requiring human intervention) to perform work. Both types of resource may be required to complete the business process. In Ensemble terms, a workflow task is an item of work that is performed offline in support of an ongoing business process. Ensemble represents a task with a special-purpose Ensemble message object called a task request. As with all outgoing messages, outgoing task requests leave Ensemble via a business operation. However, instead of using an outbound adapter to connect with the outside world, this special-purpose business operation sends the outgoing task request to the Workflow Engine. The Workflow Engine oversees task distribution and ensures that a task response is returned to the caller. Developing Ensemble Productions 191
Business Logic A workflow operation is a special-purpose business operation that represents a workflow role. A business process sends a task request to a workflow operation in exactly the same way as it sends a request message to a business operation. The distribution of tasks to human participants looks like an ordinary business operation to Ensemble. The book Using Workflow with Ensemble explains how to build workflow into an Ensemble production. 192 Developing Ensemble Productions
11 Message Routing In some sense, all Ensemble productions route and transform messages. This is true because the Ensemble architecture uses internal messaging as described in the chapter Ensemble Messages. However, there is a particular use of Ensemble known as message routing. This refers to an enterprise s need to route large numbers of messages between large numbers of systems via a fast and reliable central switch. When Ensemble plays this role it is called a message router, and the Ensemble production that accomplishes this is called a routing production. Message routing is inherently different from application integration. The examples in the chapter What is an Ensemble Production? in Introducing Ensemble show Ensemble acting as an application integration engine. In these examples, Ensemble connects a selected group of applications that need to talk to each other and cannot do so because they were developed at different times, using different conventions, and with different purposes in mind. For integration solutions, the internal logic can be complex, but a relatively small number of individual elements tie the Ensemble solution together. The core problem for message routing is quite different. In the message routing case, the connection between each pair of systems is called an interface. Each interface is logically simple, but each interface requires more than one Ensemble configuration item to represent it, and there may be hundreds of interfaces in the production. At runtime, the aggregate of all demands placed a routing engine can be severe. Ensemble offers two distinct types of message routing solution. The first is much more common: Message Routing Engine Publish and Subscribe Developing Ensemble Productions 193
Message Routing 11.1 Message Routing Engine Ensemble can act as a message routing engine for enterprises that exchange large quantities of data using Electronic Data Interchange (EDI) formats, including HL7 Versions 2 and 3, X12, and ASTM. In this model, the source and destination for each interface are known. Each interface represents two external systems that need to communicate with each other for a specific purpose, and they do so via Ensemble. The set of Ensemble configuration items required to support a single interface usually consist of: One business service to accept incoming messages. One business operation to send outgoing messages. One business process to direct the work in between. Some of the internal elements that the business process might oversee include: - Routing rules, to direct messages to their destinations based on message contents. - Schema categories, to provide a means to parse and validate message contents. - Data transformations, to apply changes to messages to prepare them for their destinations. A routing production is likely to contain many such interfaces when it is complete. Each interface is self-contained and works independently. This architecture permits you to easily and gradually integrate Ensemble into the enterprise information system, one interface at a time. For more information about Ensemble as an interface engine, consult the following books: Ensemble HL7 Version 2 Development Guide explains how to build Ensemble productions that route and transform EDI messages. This book applies to all routing productions. It combines extensive background information with examples that apply to HL7 Version 2. Ensemble HL7 Version 3 Development Guide explains how to add HL7 Version 3 interfaces to a routing production. Ensemble X12 Development Guide explains how to add X12 interfaces to a routing production. Ensemble ASTM Development Guide explains how to add ASTM E 1394 97 interfaces to a routing production. 194 Developing Ensemble Productions
Publish and Subscribe 11.2 Publish and Subscribe Ensemble supports publish and subscribe message routing. Publish and subscribe refers to the technique of routing a message to one or more subscribers based on the fact that they have previously registered to be notified about messages on a specific topic. 11.2.1 Publish and Subscribe Model Ensemble publish and subscribe messaging works based on the runtime interactions between: Messages Topics Subscribers Subscriptions The following sections describe each of these items and the roles they play in routing messages. 11.2.1.1 Messages A message is an Ensemble message. A system that is external to Ensemble receives a request and directs it into Ensemble, which converts it to an Ensemble message and sends it to a special-purpose business operation for processing. 11.2.1.2 Topics A topic is a string that characterizes the contents of a message. Ensemble does not define any topics; users and their applications define the meanings of topics and subtopics. A topic string has the form A.B.C.D, where A, B, C, and D are subtopic strings delimited by the. (period) character. A topic can contain any number of subtopics; each of these subtopics can be up to 50 characters long. The following are all valid topic strings: books books.fiction books.fiction.latin You can specify a range of topics by using * (the asterisk) as a wildcard character. For example: * can replace any complete subtopic in the topic string (books.*.latin works) * does not work as a partial wildcard (*s.fiction does not work; it does not match books.fiction, reviews.fiction, or any similar string) Developing Ensemble Productions 195
Message Routing A trailing * character matches any number of additional subtopics to the right of the last. (period) character in the topic string (books.* matches books.fiction and books.fiction.latin) 11.2.1.3 Subscribers A subscriber is an entity (a user or an external system) that might be interested in a specific topic or set of topics. A subscriber entry specifies how that entity wishes to be contacted; that is, how Ensemble should send a message to it. 11.2.1.4 Subscriptions A subscription associates a subscriber with a topic string. Suppose you have three subscribers: Abel Baker Charlie And three topics with the convention that A.B.C represents person.location.identifer: Doctor.ICU.88495 Patient.LAB.* *.*.X3562564 In that case, you could define the following subscriptions: Subscriber Abel Abel Baker Baker Charlie Topic Doctor.ICU.88494 Doctor.ICU.88495 Doctor.ICU.88495 Patient.LAB.* *.*.X3562564 This means: Abel is notified whenever the exact topics Doctor.ICU.88494 or Doctor.ICU.88495 are processed. Baker is notified whenever the exact topic Doctor.ICU.88495 is processed. In addition, Baker is notified whenever any message related to patients in the lab are processed. Charlie is notified whenever anything related to a doctor or patient with an identifier of X3562564 is processed. 196 Developing Ensemble Productions
Publish and Subscribe 11.2.2 Publish and Subscribe Implementation Ensemble publish and subscribe messaging uses the following classes in the EnsLib.PubSub package: Classes for Publish and Subscribe Messaging Class Name PubSubOperation Request Response Subscriber Subscription DomainName Utils Target Purpose Business operation that provides publish and subscribe message routing. Request class that packages requests to the PubSubOperation class. Specifies which topic and DomainName should be used to determine how the message should be routed. Optionally, the Request may also contain the message being routed, but the PubSubOperation does not need this information to return its TargetList. Response class that packages responses from the PubSubOperation class. Contains a collection of Target objects called TargetList, which the calling business process consults before dispatching the message to the required destinations. Persistent class that represents individual subscribers. These are entities interested in being notified when certain messages arrive. The Subscriber class includes any information needed to contact the actual subscriber. Persistent class that stores the association between a given Subscriber and a topic string. Persistent class that holds the set of PubSub domain names. Domain names are optional; like namespaces, domains provide a way to keep different subscription lists separate. Utility class that provides a programmatic API for creating and deleting domains, subscribers, and subscriptions. Persistent class that provides details about how to route a message to a destination outside Ensemble. The Target object has a Target property that identifies a configured business process or business operation within the current production. The Target object has an optional Address property that can specify an external address, for example an email address. Developing Ensemble Productions 197
Message Routing 11.2.3 Publish and Subscribe at Runtime To use publish and subscribe features, you must create an Ensemble production that includes an instance of the PubSubOperation. This PubSubOperation does not actually send messages to subscribers; instead, it provides a mechanism to quickly find the set of interested subscribers for a given topic. It is the responsibility of a business process that calls the PubSubOperation to dispatch messages to subscribers. At runtime, an incoming message is sent to a business process, which examines it for identifying details. Based on this analysis, the business process assigns the message a specific topic string that does not contain any wildcards. It then constructs an EnsLib.PubSub.Request message that contains this topic string and sends it to the PubSubOperation. The PubSubOperation uses an extremely fast search algorithm to find and return a list of all subscribers interested in this topic. The PubSubOperation returns an EnsLib.PubSub.Response message that contains a collection of EnsLib.PubSub.Target objects called TargetList. The business process iterates over this collection to dispatch the message to each EnsLib.PubSub.Target in the collection. 11.2.4 Configuring Publish and Subscribe When you configure publish and subscribe features for an Ensemble production, the basic steps are: 1. (Optional) Create domains. 2. Create a list of subscribers. 3. Create subscriptions to associate subscribers with topics. There are two approaches to configuring PubSub: Use CSP pages in the EnsLib.PubSub package that work within the Ensemble Management Portal. Manipulate the objects directly using the API provided in EnsLib.PubSub.Util. To view the EnsLib.PubSub CSP pages, enter one of the following URIs into a browser. You must prefix these URIs with http://localhost:57772/csp/ensemble/, where 57772 is the port number for your Ensemble server: 198 Developing Ensemble Productions
Publish and Subscribe CSP Pages for Publish and Subscribe Messaging CSP Page UtilEnsSubscribers.csp UtilEnsSubscriberEdit.csp UtilEnsSubscriptions.csp UtilEnsSubscriptionEdit.csp UtilEnsPubSubDomains.csp UtilEnsPubSubDomainEdit.csp Purpose View a list of subscribers Create or edit a subscriber entry View a list of subscriptions Create or edit a subscription entry View a list of PubSub domains Create or edit a PubSub domain entry All of these pages link to each other, so the simplest way to integrate these CSP pages into the Ensemble Management Portal is to add one of them as a link from the [Ensemble] > [Home] main menu. To add the [Ensemble] > [PubSub Subscriptions] page as the starting link, do the following: 1. Start Ensemble Studio. 2. Choose File > Change Namespace or F4. 3. Choose the ENSEMBLE namespace. 4. In the Workspace window, choose the Namespace tab. 5. Expand the CSP Files list item. 6. Find the CSP page UtilEnsHome.csp in the list and open it for editing. 7. Scroll to the bottom of the file. Change the following text from: <Action href="wfhome.csp"> <Caption>Workflow Portal</Caption> <Popup>Go to the Ensemble Workflow Management Portal</Popup> </Action> To: <Action href="wfhome.csp"> <Caption>Workflow Portal</Caption> <Popup>Go to the Ensemble Workflow Management Portal</Popup> </Action> <Action href="utilenssubscriptions.csp"> <Caption>Publish and Subscribe</Caption> <Popup>Go to the PubSub Subscription Page</Popup> </Action> 8. 9. Choose Build > Compile or Ctrl-F7 or the icon. Choose View > Web Page or the icon. The new [Ensemble] > [Home] page displays. Developing Ensemble Productions 199
Message Routing 10. In the main menu, below Workflow, click the Publish and Subscribe option. The [Ensemble] > [PubSub Subscriptions] page displays. 11. From here you may click Show Domains, Show Subscribers, Show Subscriptions, or Create New Subscription. The CSP pages for domains and subscribers are similar to that for subscriptions, but each provides a different Create button: Create New Subscriber or Create New Domain. 200 Developing Ensemble Productions
Index Symbols $$$ASSERT, 37 $$$EnsError, 59 $$$EnsSystemError, 59, 110, 111 $$$LOGERROR, 37 $$$LOGINFO, 37 $$$LOGWARNING, 37 $$$systrace, 39 $$$TRACE, 39, 110 <ActorPoolSize>, 31 <Item>, 31 <Production>, 31 <Setting>, 31 A abstraction, 3, 165 actor pool, 15, 79, 109 ADAPTER parameter, 103, 156 Adapter property, 153 adapters about, 85 see also inbound; outbound adding business operations, 157 business processes, 118 business services, 104 items to a production, 21 alarms, 43 alert message, in event log, 42 alerts about, 41 SETTINGS parameter, 42 applications client, 85 composite, 86 external, 6, 159 integration, 3 archive see persistence asynchronous messages, 75 B body, message see message body BPL about, 114 and business processes, 114, 142 diagrams, 126 graphical conventions, 126 Visual Editor, 125 BREAK, 58 business activity monitoring about, 190 business operations about, 145 ADAPTER parameter, 156 adding to a production, 157 and workflow, 192 class methods, 149 class properties, 152 developing, 155 INVOCATION parameter, 156 login credentials, 34 message map, 154 publish and subscribe, 195 SETTINGS parameter, 157 XData section, 154 business processes about, 107 adding to a production, 118 and BPL, 114, 142 and workflow, 191 class methods, 110 developing, 114 diagrams, 116, 125 execution context, 120, 187 persistence, 120, 187 SETTINGS parameter, 117 XData section, 142 Business Process Language see BPL business rules about, 189 persistence, 187 Developing Ensemble Productions 201
types of, 190 business services about, 93 ADAPTER parameter, 103 adding to a production, 104 class methods, 98 developing, 103 login credentials, 34 SETTINGS parameter, 103 C call center see alerts CallInterval, 89, 190 callrequest object, 122 callresponse object, 123 classes and the SETTINGS parameter, 27 business operation, 155 business process, 114 business service, 103 data transformation, 168 host classes, 7 inbound adapter, 90 message, 73, 82 outbound adapter, 162 persistent, 186 CleanProduction, 61 client applications, 6, 85 composite applications, 86 configuration and the SETTINGS parameter, 27 login credentials, 34 pool size, 15 productions, 8, 29 connections inbound adapters, 85 login credentials, 34 outbound adapters, 159 context, execution about, 120 callrequest, 122 callresponse, 123 context, 121 persistence, 187 process, 125 request, 122 response, 122 status, 124 syncresponses, 123 synctimedout, 124 context object, 121 coordination see flow of control CreateBusinessService, 105 credentials, login, 34 D dashboards viewing, 190 data integrating, 3 persistence, 186 recovery, 186 transformations about, 165 and DTL, 165, 168, 169, 170 class methods, 168 developing, 168 diagrams, 170 XData section, 170 database external, 7 federated, 185 local to Ensemble, 165, 185, 187 Data Transformation Language see DTL debugging, 39 $$$ASSERT, 37 $$$LOGERROR, 37 $$$LOGINFO, 37 $$$LOGWARNING, 37 $$$TRACE, 39 about, 57, 58 with BREAK, 58 deferred response about, 76 role of business operations, 152, 152 role of business processes, 113 role of business services, 101 DeferResponse, 152, 153 development about, 8 business operations, 155 business processes, 114 business services, 103 202 Developing Ensemble Productions
data transformations, 168 debugging, 58 editors see editors inbound adapters, 90 messages, 82 outbound adapters, 162 productions, 8, 21, 104, 118, 157 testing, 57 tools see tools DTL about, 165 and data transformations, 168, 169, 170 diagrams, 170 graphical conventions, 170 Visual Editor, 170 E editors BPL Visual Editor, 125 DTL Visual Editor, 170 Management Portal, 8, 58 Studio, 8, 25 Ens.Actor, 79, 109 Ens.Alert, 41 Ens.BusinessOperation, 8, 155 Ens.BusinessProcess, 8, 116 Ens.BusinessProcessBPL, 114, 120 Ens.BusinessService, 7, 103 Ens.DataTransform, 168 Ens.DataTransformDTL, 169 Ens.Director, 61, 105 Ens.Host, 7 Ens.InboundAdapter, 27, 90 Ens.OutboundAdapter, 162 Ens.Request, 73, 82 Ens.Response, 7, 73, 82, 103 Ens.Rule.FunctionSet, 48 enterprise application integration, 3 errors error codes, 60 event log and <alert>, 42 and <trace>, 40 and alerts, 41 and log utilities, 37 collection of entries, 58 persistence, 187 events, system, 17 examples, 27, 110, 111, 142 execution context about, 120 callrequest, 122 callresponse, 123 context, 121 persistence, 187 process, 125 request, 122 response, 122 status, 124 syncresponses, 123 synctimedout, 124 external applications, 6, 159 external databases, 7 F failure recovery, 186 FailureTimeout, 153 federated database, 185 flow of control business operations, 147 business processes, 109 business services, 96 inbound adapters, 87 outbound adapters, 160 production, while running, 4 production startup and shutdown, 9 G graphical user interface see editors H header, message see message header host classes, 7 I inbound adapters about, 85 class methods, 88 developing, 90 login credentials, 34 Developing Ensemble Productions 203
SETTINGS parameter, 91 instantiation business operation, 147 business process, 109 business service, 96 inbound adapter, 87 outbound adapter, 160 integration applications, 3 data, 3 enterprise-wide, 3 interfaces, 194 INVOCATION parameter, 156 J jobs, system, 15, 79, 109 L library sample code, 27, 110, 111, 142 local database, 165, 185, 187 log, event see event log login credentials, 34 log utilities $$$ASSERT, 37 $$$LOGERROR, 37 $$$LOGINFO, 37 $$$LOGWARNING, 37 M Management Portal about, 8, 58 and business operations, 157 and business processes, 116, 117 and business services, 103 and credentials, 34 and dashboards, 190 and inbound adapters, 91 and outbound adapters, 163 and pool size, 15 and productions, 8, 27, 29 and sessions, 79, 95 and suspended messages, 81 debugging code, 58 testing code, 58 map, message see message map messages about, 73 asynchronous, 75 deferred response, 76 developing, 82 document-based, 75 message body, 73, 75 message header, 73, 80 message map, 154 persistence, 187 primary request, 78 property-based, 75 publish and subscribe, 195 queues, 79 request, 73 response, 73 routing engines, 194 sessions, 79 status, 81 suspended see suspended messages synchronous, 75 methods business operation, 149 business process, 110 business service, 98 data transformation, 168 inbound adapter, 88 outbound adapter, 161 monitoring, 57, 190 O objects see classes; instantiation; persistence ODBC, 186 OnGetConnections, 102 OnInit, 88, 98, 150, 161 OnProcessInput, 99 OnProductionStart, 99, 150 OnProductionStop, 99, 150 OnRequest, 110 OnResponse, 111 OnTask, 89 OnTearDown, 88, 99, 150, 161 operation, business see business operation 204 Developing Ensemble Productions
orchestration, 93, 107, 145, 189 outbound adapters about, 159 class methods, 161 developing, 162 login credentials, 34 SETTINGS parameter, 163 P password, 34 persistence about, 186 business processes, 120, 187 business rules, 187 logs, 187 messages, 187 sessions, 187 statistics, 187 suspended messages, 187 pool, actor, 15, 109 PoolSize, 87 Portal, Management see Management Portal primary request, 78 process, business see business process process, system see jobs ProcessInput, 89, 106 process object, 125 productions about, 3 configuring, 8, 29 debugging, 57 developing, 8, 21, 25, 104, 118, 157 SETTINGS parameter, 8 starting if suspended, 61 startup and shutdown, 9 status of, 10 stopping if suspended, 61 structure of message object, 73 testing, 57 XData section, 27, 31 Productions page Stopped, 61 Suspended, 61 properties business operation, 152 execution context, 120 publish and subscribe, 195 Q queues, 79 R records see persistence recovery, 186 remote connections, 34 reporting, 190 request object, 122 requests about, 73 primary, 78 resources and workflow, 191 response object, 122 responses about, 73 Retry, 153 RetryInterval, 153 routing, message, 193 rule, business see business rule Running, 11 runtime statistics collection, 58 persistence, 187 S security, 34 SendDeferredResponse, 101, 113, 152 SendRequestAsync, 100, 112, 151 SendRequestSync, 100, 112, 151 service, business see business service sessions about, 79 and message header, 81 identifier, 95 persistence, 187 SetTimer, 113 SETTINGS parameter, 8, 42, 91, 103, 117, 157, 163 SQL, 186 Developing Ensemble Productions 205
starting suspended production, 61 statistics collection, 58 persistence, 187 status suspended productions, 61 status of messages, 81 status value, 124 Stopped, 11 Stopped status, 61 stopping suspended production, 61 storage, 165, 185, 187 Studio about, 8, 25 and business operations, 155 and business processes, 114 and business services, 103 and data transformations, 168 and inbound adapter, 90 and messages, 82 and outbound adapters, 162 debugging code, 58 support desk see alerts Suspended, 11 suspended messages about, 81 marking a message suspended, 153 persistence, 187 Suspended status, 61 SuspendMessage, 153 SVG, 125, 170 synchronous messages, 75 syncresponses collection, 123 synctimedout value, 124 system events, 17 system process see jobs system trace utilities $$$systrace, 39 see also trace utilities T testing, 57, 58 tools BPL Visual Editor, 125 DTL Visual Editor, 170 Management Portal, 8, 58 Studio, 8, 25 trace message, in event log, 40 trace utilities $$$systrace, 39 $$$TRACE, 39, 110 transformation, data see data transformation Troubled, 11 U username, 34 V variables see execution context virtual documents, 75 Visual Editor BPL, for business processes, 125 DTL, for data transformations, 170 see also editors; tools W warehouse see persistence workflow about, 191 workflow operations about, 192 X XData section code comments within, 67 in business operations, 154 in business processes, 142 in data transformations, 170 in productions, 27, 31 XML and BPL, 114, 114 and business operations, 154 and business processes, 114, 114, 142 and data transformations, 165, 168, 169, 170 and DTL, 165, 168, 169 and productions, 27, 31 206 Developing Ensemble Productions