Sunteți pe pagina 1din 54

Contents

Introduction to Business Object Processing Framework (BOPF) ..................................................................................... 3


What does BOPF stand for? ........................................................................................................................................ 3
Who uses BOPF? ......................................................................................................................................................... 3
How can SAP customers use BOPF? ............................................................................................................................ 3
What are the main components of the application infrastructure? ........................................................................... 3
What are the elements of the programming model? ................................................................................................. 6
What kind of development environment is available for BOPF? ................................................................................ 7
NOTE............................................................................................................................................................................ 8
How to get started? .................................................................................................................................................... 8
Navigating the BOPF: Part 2 Business Object Overview ............................................................................................... 9
Business Objects Overview ......................................................................................................................................... 9
Anatomy of a Business Object ..................................................................................................................................... 9
Nodes ...................................................................................................................................................................... 9
Actions .................................................................................................................................................................... 9
Associations .......................................................................................................................................................... 10
Determinations ..................................................................................................................................................... 10
Validations ............................................................................................................................................................ 11
Queries .................................................................................................................................................................. 11
Next Steps ................................................................................................................................................................. 12
Navigating the BOPF: Part 3 Working with the BOPF API ........................................................................................... 13
BOPF API Overview ................................................................................................................................................... 13
Case Study: Building a Simple Report Program to Manipulate Customer Objects ................................................... 14
Getting Started .......................................................................................................................................................... 15
Creating New Customers........................................................................................................................................... 16
Performing Customer Queries .................................................................................................................................. 22
Modifying Customer Records .................................................................................................................................... 31
Next Steps ................................................................................................................................................................. 33
Navigating the BOPF: Part 4 Advanced BOPF API Features ........................................................................................ 34
Performing Consistency Checks & Validations .......................................................................................................... 34
Triggering Actions...................................................................................................................................................... 36
Action Validations ..................................................................................................................................................... 38
Transaction Management ......................................................................................................................................... 39
Next Steps ................................................................................................................................................................. 40
Navigating the BOPF: Part 5 Enhancement Techniques ............................................................................................. 40
What to Enhance? ..................................................................................................................................................... 40
Custom Attributes ..................................................................................................................................................... 40
New Sub-Nodes ......................................................................................................................................................... 40
Determinations ......................................................................................................................................................... 40
Consistency Validations............................................................................................................................................. 41
Actions ....................................................................................................................................................................... 41
Queries ...................................................................................................................................................................... 41
Working with the Enhancement Workbench ............................................................................................................ 42
Enhancing the BO Data Model .................................................................................................................................. 43
Defining Determinations ........................................................................................................................................... 45
Implementing Class: .............................................................................................................................................. 45
Determination Pattern: ......................................................................................................................................... 46
Defining Consistency Validations .............................................................................................................................. 46
Implementing Class: .............................................................................................................................................. 47
Request Nodes: ..................................................................................................................................................... 47
Impact: .................................................................................................................................................................. 47
Working with Actions ................................................................................................................................................ 47
Implementing Class: .............................................................................................................................................. 47
Action Cardinality:................................................................................................................................................. 47
Parameter Structure: ............................................................................................................................................ 47
Defining Custom Queries .......................................................................................................................................... 49
Next Steps ................................................................................................................................................................. 50
Navigating the BOPF: Part 6 Testing & UI Integration ................................................................................................ 51
Working with the BOPF Test UI ................................................................................................................................. 51
Editing BO Instances .................................................................................................................................................. 51
Triggering Actions, Validations, & Determinations ................................................................................................... 53
UI Integration and the FBI Framework ...................................................................................................................... 53
Conclusion ................................................................................................................................................................. 54
INTRODUCTION TO BUSINESS OBJECT PROCESSING FRAMEWORK (BOPF)

Wouldn't you like to streamline and simplify the development process for your business
applications?

Then you should get to know more about BOPF, our infrastructure for developing business objects
that is available for the SAP Business Suite. With the Business Object Processing Framework, you
will save time during the development cycle because you don't have to implement all the technical
details yourself - details such as authorization control, low-level transaction handling, buffer
management, provisioning of consumer API, or business logic orchestration. Using the model-driven
approach in BOPF, you can instead focus your attention more on the actual business requirements
themselves.

WHAT DOES BOPF STAND FOR?

The Business Object Processing Framework is an ABAP OO-based framework that provides a set of
generic services and functionalities to speed up, standardize, and modularize your development.
BOPF manages the entire life cycle of your business objects and covers all aspects of your business
application development. Instead of expending effort for developing an application infrastructure, the
developer can focus on the individual business logic. Using BOPF, you get the whole application
infrastructure and integration of various components for free. This allows you to rapidly build
applications on a stable and customer-proved infrastructure.

WHO USES BOPF?

BOPF is not really a new framework. In fact, it is well established and broadly used in multiple SAP
ByDesign and SAP Business Suite applications and products for example, Transportation
Management (TM), Environment, Health and Safety (EH&S), SAP Supplier Lifecycle Management,
SAP Management of Change, SAP Quality Issue Management, to name but a few. Apart from its use
in SAP internal development, BOPF is also used in customer development projects.

HOW CAN SAP CUSTOMERS USE BOPF?

Due to increased interest, BOPF is also used in SAP customer development projects. It is released
with SAP Business Suite EHP5 SP11, SAP Business Suite EHP6 SP05, and SAP Business
Suite EHP7. Moreover, starting with the SAP NetWeaver 7.50 release, BOPF is available in the SAP
NetWeaver standalone system - as part of the SAP BASIS layer.

WHAT ARE THE MAIN CO MPONENTS OF THE APPL ICATION INFRASTRUCTURE?

With BOPF, you have a framework at your disposal with which you can seamlessly integrate different
components of business applications. You can use them out-of-the-box. The advantages of using
BOPF are thus obvious:

When using BOPF you dont have to care about the development of adapters or integration layers to
consume the following components:
Figure: BOPF acts as a bridging unit between various components

User Interfaces and Consumption

Dynpro BOPF provides a standard interface for consumption by the classic Dynpro UI.

Web Dynpro / Floor The generation and configuration of complex user interfaces has never been as easy
Plan Manager as it is today with the FPM. FPM is implemented as a Web Dynpro component and
(FPM) can be easily integrated with BOPF. BOPF provides configurable and codeless
integration of FPM and enables you to seamlessly consume the services of BOPF
Business Objects in a modification-free environment.

More: Floorplan Manager for Web Dynpro ABAP and Web Dynpro ABAP on SCN

SAPUI5 SAPUI5 is designed for building lightweight UIs for casual use.

More: UI Developer Center on SCN

Gateway (OData) SAP NetWeaver Gateway is a technology that provides a convenient way to connect
devices, environments, and platforms to SAP software based on market standards.
The BOPF integration of the Gateway is based on REST and OData standards.

More: SAP NetWeaver Gateway on SCN

Business Object The Business Object Layer (BOL) provides a generic API for accessing business
Layer & GenIL data.
The Generic Interaction Layer (GenIL) enables uniform access to business data
using a stateless request/response format. BOPF provides adapters for BOL and
GenIL integration.

More: SAP CRM on SCN

Process Integration

Post Processing With BOPF BOs, you can integrate business processes using the Post Processing
Workflow Workflow.

More: Post Processing Framework (PPF) (on SCN )

Infrastructure Component

Archive Development With ADK you archive not only table records but also business instances.
Kit (ADK) Using BOPF you can select which BO instances have to be archived and then
trigger the archiving process for them.

More: Archive Development Kit on the SAP help portal

Change Documents BOPF uses the SAP NetWeaver Change Documents solution for recording
changes on business object data.

More: Change Documents on the SAP help portal

Application Logging Application logging is used to record particular events during the execution
of an application so that you can reconstruct them later, if necessary.

In BOPF, application logging is integrated with the help of the Application


Log BO. This business object supports you when reading or writing
application-specific log messages.

More: Application Log - Guidelines for Developers on the SAP help portal

Enterprise Search The search service of SAP NetWeaver provides a framework for enterprise-
wide indexing of and searching for structured (business objects) and
unstructured data (documents).

BOPF design time provides you with a convenient way for enabling BOPF
business objects for Enterprise Search. Using an existing BO model, you
have the option of importing the BO data and, in this way, creating a
corresponding Enterprise Search model.
More: Enterprise Search on SCN

Business Rules Framework BRF+ is a rule engine. It provides a comprehensive API and user interface for
plus (BRF+) defining and processing business rules and expressions.

With a BOPF-specific expression type, it is possible to create BO data


retrieval expressions in BRF+. These expressions make data of BOs available
in BRF+ environments that support any kind of rule processing.

More: Business Rule Framework plus on SCN

WHAT ARE THE ELEMENT S OF THE PROGRAMMING MODEL?

The business objects are the basic units of the BOPF-based programming model. Business
applications or processes operate on certain business objects. A business object is represented as a
hierarchical tree of nodes. A single node includes a set of semantically related business object data
and the corresponding business logic. On the technical level, each node is implemented with a
regular Dictionary table, where each node instance corresponds to a single table entry (table rows).
Nodes, attributes, and alternative keys set up the data part of a business object. Again from a
technical viewpoint, attributes form the columns of the table. A node serves as an anchor point for
connecting the business logic of the business object.

For each node, several types of entities can be defined to form the specific business logic partof a
business object.

Node Entity is used ...

Action to implement a service (operation or behavior) of a business object. An action is


explicitly triggered by a service consumer, such as the user interface.

Determination to provide functions that are automatically executed as soon as certain trigger
conditions are fulfilled. A determination is triggered internally due to changes
made to the instance of a business object.

Validation to either validate whether a specific action can be executed on a specific node
instance (action validations) or whether a set of node instances is consistent
(consistency validations).

Query to search for business object instances that meet certain search criteria.

Authorization to provide an authorization concept for BO nodes (for their data and for the
Check operations on their data).

Association to connect business object instances that are located on different nodes.
Figure: Business object metadata model

WHAT KIND OF DEVELOP MENT ENVIRONMENT IS AVAILABLE FOR BOPF?

Tool Support Features

SAP Internal Design These are internal SAP tools and utilities that provide developers with a
Time Tools (BOBF) comprehensive feature set for building BO-centered applications for SAP Business
Suite.

BO Builder (BOB) This tool targets simple enhancement scenarios.

Customers can enhance SAP business objects and also create their own simple
business objects in the customer namespace. The creation of business objects,
nodes, actions, determinations, queries, or validations is extensively supported by
wizard-driven tools and utilities.
BO Builder is available through SAP GUI and is released for customers with SAP
Business Suite EHP5 upwards

BO Builder for This tool targets experienced BOPF developers.


eXperts (BOBX) It also provides SAP Business Suite customers with a comprehensive feature set for
building BO-centered applications so that they can use it for their own development
projects.

BO Builder for eXperts is available through SAP GUI and is released for customers
with SAP Business Suite EHP6 upward.
(Eclipse-Based) With SAP Business Suite EHP7 a new Eclipse-based client application
ABAP Development
Tools for BOPF will be provided as part of an ABAP Development Tools installation. This set of
tools runs on top of the Eclipse-based ABAP IDE and is aimed at supporting all
kinds of BO-centric use cases: it allows both the creation of new BOPF-
applications and the enhancement of existing ones.

BO Builder Test Starting from development environment, you can always test the current range of
Environment (BOBT) functions of each business object (or enhancement).

BO-Specific Debugging on the business object entities level enables you to speed up the
Debugging troubleshooting process:

You can set breakpoints for entities such as actions, determinations, and
validations. Furthermore, you have the option of setting watchpoints for certain
activities on the nodes (for example, to update a particular node attribute).

Integrated BO Test BOPF supports test automation and test-driven development. From the outset,
Infrastructure you can apply ABAP unit tests to test isolated units of business objects, such as
actions, validations, or determinations. In addition, with the scenario testing
function, you can extend the tests to processes that consist of several steps.

NOTE

As a SAP customer, you can use the BO Builder (BOB), the BO Builder for eXperts (BOBX), or the
Eclipse-based client for the development of your own business objects. Here, you will benefit from
that interoperability is ensured between these development tools. So you can, for example,
create new business objects in the BOB tool and then edit them in another tool on.

HOW TO GET STARTED?

Getting Started with BOPF guides you through all the steps required to create from scratch your first
business object and to implement a basic operation using the BOPF API.
NAVIGATING THE BOPF: PART 2 BUSINESS OBJECT OVERVIEW

BUSINESS OBJECTS OVE RVIEW

According to SAPs BOPF Enhancement Workbench documentation, business objects within the
BOPF are a representation of a type of uniquely identifiable business entity described by a structural
model and an internal process model. This is to say that BOPF business objects:

Have a well-defined component model.

Have a well-defined process model which governs the business object lifecycle, behaviours, etc.

Execute within a container-like environment which handles low-level tasks such as caching,
transaction management, and so on.

In this regard, BOs in the BOPF are not unlike objects developed in other component architectures
(e.g. EJBs in Java, Microsoft COM+, etc.).

ANATOMY OF A BUSINES S OBJECT

From a modelling perspective, BOs are made up of several different types of entities:

NODES
Nodes are used to model a BOs data.

Nodes are arranged hierarchically to model the various dimensions of the BO data. This hierarchy is
organized underneath a single root node (much like XML). From there, the hierarchy can be nested
arbitrarily deep depending upon business requirements.

There are several different node types supported by the BOPF. However, most of the time youll find
yourself working with persistent nodes (e.g. nodes which are backed by the database). It is also
possible to define transient nodes whose contents are loaded on demand at runtime. These types of
nodes can come in handy whenever we want to bridge some alternative persistence model (e.g. data
obtained via service calls).

Each node consists of one or more attributes which describe the type of data stored within the node:

Attributes come in two distinct varieties: persistent attributes and transient attributes. Persistent
attributes represent those attributes that will be persisted whenever the BO is saved. Transient
attributes are volatile attributes which are loaded on demand.

A nodes attributes are defined in terms of structure definitions from the ABAP Dictionary.

At runtime, a BO node is like a container which may have zero, one, or many rows. If youre familiar
with the concept of controller contexts with the Web Dynpro programming model, then this concept
should feel familiar to you. If not, dont worry; well demonstrate how this works whenever we look at
the BOPF API.

ACTIONS
Actions define the services (or behaviour) of a BO.

Actions are assigned to individual nodes within a BO.

The functionality provided by an action is (usually) defined in terms of an ABAP Objects class that
implements the /BOBF/IF_FRW_ACTION interface.

To some extent, it is appropriate to think of actions as being similar to the methods of an ABAP
Objects class.

ASSOCIATIONS
Though BOs are designed to be self-contained, autonomous entities, they do not have to exist in
isolation. With associations, we can define a direct and unidirectional relationship from one BO to
another.

For example, in just a moment, well take a look at a sample BO


called /BOBF/DEMO_SALES_ORDER which is used to model sales orders. Here, well see how the product
assignments for sales order items is defined in terms of an association with a product BO
called /BOBF/DEMO_PRODUCT. This composition technique makes it possible to not only leverage the
product BOs data model, but also its behaviors, etc.

Associations allow us to integrate BOs together in complex assemblies la Legos.

DETERMINATIONS
According to the aforementioned BOPF enhancement guide, a determination is an element assigned
to a business object node that describes internal changing business logic on the business object.

In some respects, determinations are analogous to database triggers. In other words, they are
functions that are triggered whenever certain triggering conditions are fulfilled. These conditions are
described in terms of a series of patterns:

Derive dependent data immediately after modification

This pattern allows us to react to changes made to a given BO node. For example, we might use this
event to go clean up some related data.

Derive dependent data before saving

This pattern allows us to hang some custom logic on a given BO node before it is saved. This could
be as simple as using a number range object to assign an ID value to a node attribute or as complex
as triggering an interface.

Fill transient attributes of persistent nodes

This pattern is often used in conjunction with UI development. Here, we might want to load labels and
descriptive texts into a series of transient attributes to be displayed on the screen.

Note: This determination can be bypassed via the API if the lookup process introduces unnecessary
overhead.

Derive instances of transient nodes


This pattern allows us to load transient nodes into memory on demand. Here, for example, we might
lookup real-time status data from a Web service and load it into the attributes of a transient node from
downstream consumption.

Determination patterns are described in detail within the aforementioned BOPF enhancement guide.

The logic within a determination is defined via an ABAP Objects class that implements
the /BOBF/IF_FRW_DETERMINATION interface.

VALIDATIONS
According to the BOPF enhancement guide, validations are an element of a business object node
that describes some internal checking business logic on the business object.

Validations come in two distinct forms:

Action Validations

Action validations are used to determine whether or not a particular action can be executed against a
BO node.

Consistency Validations

As the name suggests, consistency validations are used to ensure that a BO node is consistent. Such
validations are called at pre-defined points within the BOPF BO transaction cycle to ensure that BO
nodes are persisted in a consistent state.

The validation logic is encapsulated within an ABAP Objects class that implements
the /BOBF/IF_FRW_VALIDATION interface.

QUERIES
Queries are BO node entities which allow us to search for BOs using various types of search criteria.

Queries make it possible for consumers to access BOs without knowing the BO key up front.

Queries also integrate quite nicely with search frameworks and the like.

Queries come in two varieties:

Node Attribute Queries

Node attribute queries are modeled queries whose logic is defined within the BOPF runtime. These
simple queries can be used whenever you simply need to search for BO nodes by their attributes (e.g.
ID = 12345).

Custom Queries

Custom queries allow you define your own query logic by plugging in an ABAP Objects class that
implements the /BOBF/IF_FRW_QUERY interface.

The figure below illustrates how all of these entities fit together within a BO node definition. Here, Ive
pulled up a BO called /BOBF/DEMO_SALES_ORDER in Transaction /BOBF/CONF_UI. Here, the BO
metadata is organized into several different panels:
On the top left-hand side of the screen, you can see the BOs node structure. Here, you can see that
the node structure is organized underneath a top-level ROOT node which models sales order header
data. Underneath this node are several child nodes which model sales order items, customer
assignment, and texts. The ITEM node in turn encompasses its own child nodes to model item-level
data.

On the bottom left-hand side of the screen, we can browse through the node collection of a BO and
view the entity assignments of a given node. As you can see in the figure, each node contains folders
which organize assigned actions, validations, and so on.

In the middle of the screen, we can view additional details about a selected node by double-clicking
on a node within the Node Structure panel on the left-hand side of the screen. Here, we can look at a
nodes data model, implementation classes, and so on.

Well have an opportunity to get a little more hands on with these entities in upcoming blog entries.
For now, our focus is on grasping how pieces fit together and where to go to find the information we
need to get started with a BO.

NEXT STEPS

At this point, you should have a decent feel for how BOs are modeled at design time. In my next blog,
well shift gears and begin manipulating BOs using the provided BOPF APIs. This will help put all of
these entities into perspective.
NAVIGATING THE BOPF: PART 3 WORKING WITH THE BOPF API

the construction of a simple ABAP report program used to perform CRUD operations on a sample
BOPF BO shipped by default by SAP: /BOBF/DEMO_CUSTOMER.

BOPF API OVERVIEW

Before we begin coding with the BOPF API, lets first take a look at its basic structure. The UML class
diagram below highlights some of the main classes that make up the BOPF API. At the end of the
day, there are three main objects that well be working with to perform most of the operations within
the BOPF:

/BOBF/IF_TRA_TRANSACTION_MGR

This object reference provides a transaction manager which can be used to manage transactional
changes. Such transactions could contain a single step (e.g. update node X) or be strung out across
multiple steps (add a node, call an action, and so on).

/BOBF/IF_TRA_SERVICE_MANAGER

The service manager object reference provides us with the methods we need to lookup BO nodes,
update BO nodes, trigger validations, perform actions, and so on.

/BOBF/IF_FRW_CONFIGURATION

This object reference provides us with metadata for a particular BO. Well explore the utility of having
access to this metadata coming up shortly.
In the upcoming sections, Ill show you how these various API classes collaborate in typical BOPF
use cases. Along the way, well encounter other useful classes that can be used to perform specific
tasks. You can find a complete class listing within package /BOBF/MAIN.

Note: As youll soon see, the BOPF API is extremely generic in nature. While this provides
tremendous flexibility, it also adds a certain amount of tedium to common tasks. Thus, in many
applications, you may find that SAP has elected to wrap the API up in another API that is more
convenient to work with. For example, in the SAP EHSM solution, SAP defines an Easy Node
Access API which simplfies the way that developers traverse BO nodes, perform updates, and so on.

CASE STUDY: BUILDING A SIMPLE REPORT PRO GRAM TO MANIPULATE CUSTOMER OBJECTS

To demonstrate the BOPF API, well build a custom report program which performs basic CRUD
operations on a sample BO provided by SAP: /BOBF/DEMO_CUSTOMER. The figure below shows the
makeup of this BO in Transaction /BOBF/CONF_UI.

Our sample program provides a basic UI as shown below. Here, users have the option of creating,
changing, and displaying a particular customer using its ID number. Sort of a simplified Transaction
XK01-XK03 if you will.
GETTING STARTED

To drive the application functionality, well create a local test driver class called LCL_DEMO. As you can
see in the code excerpt below, this test driver class loads the core BOPF API objects at setup
whenever the CONSTRUCTOR method is invoked. Here, the factory classes illustrated in the UML class
diagram shown in the previous section are used to load the various object references.

CLASS lcl_demo DEFINITION CREATE PRIVATE.


PRIVATE SECTION.
DATA mo_txn_mngr TYPE REF TO /bobf/if_tra_transaction_mgr.
DATA mo_svc_mngr TYPE REF TO /bobf/if_tra_service_manager.
DATA mo_bo_conf TYPE REF TO /bobf/if_frw_configuration.

METHODS:
constructor RAISING /bobf/cx_frw.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.


METHOD constructor.
"Obtain a reference to the BOPF transaction manager:
me->mo_txn_mngr =
/bobf/cl_tra_trans_mgr_factory=>get_transaction_manager( ).

"Obtain a reference to the BOPF service manager:


me->mo_svc_mngr =
/bobf/cl_tra_serv_mgr_factory=>get_service_manager(
/bobf/if_demo_customer_c=>sc_bo_key ).

"Access the metadata for the /BOBF/DEMO_CUSTOMER BO:


me->mo_bo_conf =
/bobf/cl_frw_factory=>get_configuration(
/bobf/if_demo_customer_c=>sc_bo_key ).
ENDMETHOD. " METHOD constructor
ENDCLASS.

For the most part, this should seem fairly straightforward. However, you might be wondering where I
came up with the IV_BO_KEY parameter in
the GET_SERVICE_MANAGER() and GET_CONFIGURATION() factory method calls. This value is provided
to us via the BOs constants interface (/BOBF/IF_DEMO_CUSTOMER_C in this case) which can be found
within the BO configuration in Transaction /BOBF/CONF_UI (see below). This auto-generated
constants interface provides us with a convenient mechanism for addressing a BOs key, its defined
nodes, associations, queries, and so on. Well end up using this interface quite a bit during the course
of our development.
CREATING NEW CUSTOME RS
Once we have the basic framework in place, we are ready to commence with the development of the
various CRUD operations that our application will support. To get things started, well take a look at
the creation of a new customer instance. For the most part, this involves little more than a call to
the MODIFY() method of the /BOBF/IF_TRA_SERVICE_MANAGER object reference. Of course, as you can
see in the code excerpt below, there is a fair amount of setup that we must do before we can call this
method.

CLASS lcl_demo DEFINITION CREATE PRIVATE.


PUBLIC SECTION.
CLASS-METHODS:
create_customer IMPORTING iv_customer_id
TYPE /bobf/demo_customer_id.
...
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.


METHOD create_customer.
"Method-Local Data Declarations:
DATA lo_driver TYPE REF TO lcl_demo.
DATA lt_mod TYPE /bobf/t_frw_modification.
DATA lo_change TYPE REF TO /bobf/if_tra_change.
DATA lo_message TYPE REF TO /bobf/if_frw_message.
DATA lv_rejected TYPE boole_d.
DATA lx_bopf_ex TYPE REF TO /bobf/cx_frw.
DATA lv_err_msg TYPE string.

DATA lr_s_root TYPE REF TO /bobf/s_demo_customer_hdr_k.


DATA lr_s_txt TYPE REF TO /bobf/s_demo_short_text_k.
DATA lr_s_txt_hdr TYPE REF TO /bobf/s_demo_longtext_hdr_k.
DATA lr_s_txt_cont TYPE REF TO /bobf/s_demo_longtext_item_k.

FIELD-SYMBOLS:
<ls_mod> LIKE LINE OF lt_mod.

"Use the BOPF API to create a new customer record:


TRY.
"Instantiate the driver class:
CREATE OBJECT lo_driver.

"Build the ROOT node:


CREATE DATA lr_s_root.
lr_s_root->key = /bobf/cl_frw_factory=>get_new_key( ).
lr_s_root->customer_id = iv_customer_id.
lr_s_root->sales_org = 'AMER'.
lr_s_root->cust_curr = 'USD'.
lr_s_root->address_contry = 'US'.
lr_s_root->address = '1234 Any Street'.

APPEND INITIAL LINE TO lt_mod ASSIGNING <ls_mod>.


<ls_mod>-node = /bobf/if_demo_customer_c=>sc_node-root.
<ls_mod>-change_mode = /bobf/if_frw_c=>sc_modify_create.
<ls_mod>-key = lr_s_root->key.
<ls_mod>-data = lr_s_root.

"Build the ROOT_TEXT node:


CREATE DATA lr_s_txt.
lr_s_txt->key = /bobf/cl_frw_factory=>get_new_key( ).
lr_s_txt->text = 'Sample Customer Record'.
lr_s_txt->language = sy-langu.

APPEND INITIAL LINE TO lt_mod ASSIGNING <ls_mod>.


<ls_mod>-node = /bobf/if_demo_customer_c=>sc_node-root_text.
<ls_mod>-change_mode = /bobf/if_frw_c=>sc_modify_create.
<ls_mod>-source_node = /bobf/if_demo_customer_c=>sc_node-root.
<ls_mod>-association =

/bobf/if_demo_customer_c=>sc_association-root-root_text.
<ls_mod>-source_key = lr_s_root->key.
<ls_mod>-key = lr_s_txt->key.
<ls_mod>-data = lr_s_txt.

"Build the ROOT_LONG_TEXT node:


"If you look at the node type for this node, you'll notice that
"it's a "Delegated Node". In other words, it is defined in terms
"of the /BOBF/DEMO_TEXT_COLLECTION business object. The following
"code accounts for this indirection.
CREATE DATA lr_s_txt_hdr.
lr_s_txt_hdr->key = /bobf/cl_frw_factory=>get_new_key( ).

APPEND INITIAL LINE TO lt_mod ASSIGNING <ls_mod>.


<ls_mod>-node = /bobf/if_demo_customer_c=>sc_node-root_long_text.
<ls_mod>-change_mode = /bobf/if_frw_c=>sc_modify_create.
<ls_mod>-source_node = /bobf/if_demo_customer_c=>sc_node-root.
<ls_mod>-association =

/bobf/if_demo_customer_c=>sc_association-root-root_long_text.
<ls_mod>-source_key = lr_s_root->key.
<ls_mod>-key = lr_s_txt_hdr->key.
<ls_mod>-data = lr_s_txt_hdr.
"Create the CONTENT node:
CREATE DATA lr_s_txt_cont.
lr_s_txt_cont->key = /bobf/cl_frw_factory=>get_new_key( ).
lr_s_txt_cont->language = sy-langu.
lr_s_txt_cont->text_type = 'MEMO'.
lr_s_txt_cont->text_content = 'Demo customer created via BOPF API.'.

APPEND INITIAL LINE TO lt_mod ASSIGNING <ls_mod>.


<ls_mod>-node =

lo_driver->mo_bo_conf->query_node(

iv_proxy_node_name = 'ROOT_LONG_TXT.CONTENT' ).
<ls_mod>-change_mode = /bobf/if_frw_c=>sc_modify_create.
<ls_mod>-source_node = /bobf/if_demo_customer_c=>sc_node-root_long_text.
<ls_mod>-source_key = lr_s_txt_hdr->key.
<ls_mod>-key = lr_s_txt_cont->key.
<ls_mod>-data = lr_s_txt_cont.

<ls_mod>-association =
lo_driver->mo_bo_conf->query_assoc(
iv_node_key = /bobf/if_demo_customer_c=>sc_node-root_long_text
iv_assoc_name = 'CONTENT' ).

"Create the customer record:


CALL METHOD lo_driver->mo_svc_mngr->modify
EXPORTING
it_modification = lt_mod
IMPORTING
eo_change = lo_change
eo_message = lo_message.

"Check for errors:


IF lo_message IS BOUND.
IF lo_message->check( ) EQ abap_true.
lo_driver->display_messages( lo_message ).
RETURN.
ENDIF.
ENDIF.

"Apply the transactional changes:


CALL METHOD lo_driver->mo_txn_mngr->save
IMPORTING
eo_message = lo_message
ev_rejected = lv_rejected.

IF lv_rejected EQ abap_true.
lo_driver->display_messages( lo_message ).
RETURN.
ENDIF.

"If we get to here, then the operation was successful:


WRITE: / 'Customer', iv_customer_id, 'created successfully.'.
CATCH /bobf/cx_frw INTO lx_bopf_ex.
lv_err_msg = lx_bopf_ex->get_text( ).
WRITE: / lv_err_msg.
ENDTRY.
ENDMETHOD. " METHOD create_customer
ENDCLASS.

As you can see in the code excerpt above, the majority of the code is devoted to building a table
which is passed in the IT_MODIFICATION parameter of the MODIFY() method. Here, a separate record
is created for each node row that is being modified (or inserted in this case). This record contains
information such as the node object key (NODE), the edit mode (CHANGE_MODE), the row key (KEY) which
is an auto-generated GUID, association/parent key information, and of course, the actual data (DATA).
If youve ever worked with ALE IDocs, then this will probably feel vaguely familiar.

Looking more closely at the population of the node row data, you can see that were working with data
references which are created dynamically using the CREATE DATA statement. This indirection is
necessary since the BOPF API is generic in nature. You can find the structure definitions for each
node by double-clicking on the node in Transaction /BOBF/CONF_UI and looking at the COMBINED
STRUCTURE field (see below).
Once the modification table is filled out, we can call the MODIFY() method to insert the record(s).
Assuming all is successful, we can then commit the transaction by calling the SAVE() method on
the /BOBF/IF_TRA_TRANSACTION_MANAGER instance. Should any errors occur, we can display the error
messages using methods of the /BOBF/IF_FRW_MESSAGE object reference which is returned from both
methods. This is evidenced by the simple utility method DISPLAY_MESSAGES() shown below. Thats
pretty much all there is to it.

CLASS lcl_demo DEFINITION CREATE PRIVATE.


PRIVATE SECTION.
METHODS:
display_messages IMPORTING io_message
TYPE REF TO /bobf/if_frw_message.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.


METHOD display_messages.
"Method-Local Data Declarations:
DATA lt_messages TYPE /bobf/t_frw_message_k.
DATA lv_msg_text TYPE string.
FIELD-SYMBOLS <ls_message> LIKE LINE OF lt_messages.

"Sanity check:
CHECK io_message IS BOUND.
"Output each of the messages in the collection:
io_message->get_messages( IMPORTING et_message = lt_messages ).
LOOP AT lt_messages ASSIGNING <ls_message>.
lv_msg_text = <ls_message>-message->get_text( ).
WRITE: / lv_msg_text.
ENDLOOP.
ENDMETHOD. " METHOD display_messages
ENDCLASS.

PERFORMING CUSTOMER QUERIES

If you look closely at the customer creation code illustrated in the previous section, you can see that
each node row is keyed by an auto-generated GUID of type /BOBF/CONF_KEY (see below). Since most
users dont happen to have 32-character hex strings memorized, we typically have to resort to queries
if we want to find particular BO instances. For example, in our customer demo program, we want to
provide a way for users to lookup customers using their customer ID value. Of course, we could have
just as easily defined an alternative query selection to pull the customer records.

As we learned in the previous blog post, most BOs come with one or more queries which allow us to
search for BOs according to various node criteria. In the case of the /BOBF/DEMO_CUSTOMER business
object, we want to use the SELECT_BY_ATTRIBUTES query attached to the ROOT node (see below). This
allows us to lookup customers by their ID value.
The code excerpt below shows how we defined our query in a method
called GET_CUSTOMER_FOR_ID(). As you can see, the query is executed by calling the aptly
named QUERY() method of the /BOBF/IF_TRA_SERVICE_MANAGER instance. The query parameters are
provided in the form of an internal table of type /BOBF/T_FRW_QUERY_SELPARAM. This table type has a
similar look and feel to a range table or SELECT-OPTION. The results of the query are returned in a
table of type /BOBF/T_FRW_KEY. This table contains the keys of the node rows that matched the query
parameters. In our sample case, there should be only one match, so we simply return the first key in
the list.

CLASS lcl_demo DEFINITION CREATE PRIVATE.


PRIVATE SECTION.
METHODS:
get_customer_for_id IMPORTING iv_customer_id
TYPE /bobf/demo_customer_id
RETURNING VALUE(rv_customer_key)
TYPE /bobf/conf_key
RAISING /bobf/cx_frw.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.


METHOD get_customer_for_id.
"Method-Local Data Declarations:
DATA lo_driver TYPE REF TO lcl_demo.
DATA lt_parameters TYPE /bobf/t_frw_query_selparam.
DATA lt_customer_keys TYPE /bobf/t_frw_key.
DATA lx_bopf_ex TYPE REF TO /bobf/cx_frw.
DATA lv_err_msg TYPE string.
FIELD-SYMBOLS <ls_parameter> LIKE LINE OF lt_parameters.
FIELD-SYMBOLS <ls_customer_key> LIKE LINE OF lt_customer_keys.

"Instantiate the test driver class:


CREATE OBJECT lo_driver.

"Though we could conceivably lookup the customer using an SQL query,


"the preferred method of selection is a BOPF query:
APPEND INITIAL LINE TO lt_parameters ASSIGNING <ls_parameter>.
<ls_parameter>-attribute_name =

/bobf/if_demo_customer_c=>sc_query_attribute-root-select_by_attributes-
customer_id.
<ls_parameter>-sign = 'I'.
<ls_parameter>-option = 'EQ'.
<ls_parameter>-low = iv_customer_id.

CALL METHOD lo_driver->mo_svc_mngr->query


EXPORTING
iv_query_key =

/bobf/if_demo_customer_c=>sc_query-root-select_by_attributes
it_selection_parameters = lt_parameters
IMPORTING
et_key = lt_customer_keys.

"Return the matching customer's KEY value:


READ TABLE lt_customer_keys INDEX 1 ASSIGNING <ls_customer_key>.
IF sy-subrc EQ 0.
rv_customer_key = <ls_customer_key>-key.
ENDIF.
ENDMETHOD. " METHOD get_customer_for_id
ENDCLASS.

Displaying Customer Records

With the query logic now in place, we now know which customer record to lookup. The question is,
how do we retrieve it? For this task, we must use the

RETRIEVE() and RETRIEVE_BY_ASSOCIATION() methods provided by


the /BOBF/IF_TRA_SERVICE_MANAGERinstance. As simple as this sounds, the devil is in the details.
Here, in addition to constructing the calls to the RETRIEVE*() methods, we must also dynamically
define the result tables which will be used to store the results.

As you can see in the code excerpt below, we begin our search by accessing the customer ROOT node
using the RETRIEVE() method. Here, the heavy lifting is performed by
the GET_NODE_ROW() and GET_NODE_TABLE() helper methods. Looking at the implementation of
the GET_NODE_TABLE() method, you can see how were using
the /BOBF/IF_FRW_CONFIGURATION object reference to lookup the nodes metadata. This metadata
provides us with the information we need to construct an internal table to house the results returned
from the RETRIEVE() method. The GET_NODE_ROW() method then dynamically retrieves the record
located at the index defined by the IV_INDEX parameter.

Within the DISPLAY_CUSTOMER() method, we get our hands on the results by performing a cast on the
returned structure reference. From here, we can access the row attributes as per usual.

After the root node has been retrieved, we can traverse to the child nodes of
the /BOBF/DEMO_CUSTOMERobject using the RETRIEVE_BY_ASSOCIATION() method. Here, the process is
basically the same. The primary difference is in the way we lookup the association metadata which is
used to build the call to RETRIEVE_BY_ASSOCIATION() . Once again, we perform a cast on the returned
structure reference and display the sub-node attributes from there.

CLASS lcl_demo DEFINITION CREATE PRIVATE.


PUBLIC SECTION.
CLASS-METHODS:
display_customer IMPORTING iv_customer_id
TYPE /bobf/demo_customer_id.

PRIVATE SECTION.

METHODS:
get_node_table IMPORTING iv_key TYPE /bobf/conf_key
iv_node_key TYPE /bobf/obm_node_key
iv_edit_mode TYPE /bobf/conf_edit_mode

DEFAULT /bobf/if_conf_c=>sc_edit_read_only
RETURNING VALUE(rr_data) TYPE REF TO data
RAISING /bobf/cx_frw,

get_node_row IMPORTING iv_key TYPE /bobf/conf_key


iv_node_key TYPE /bobf/obm_node_key
iv_edit_mode TYPE /bobf/conf_edit_mode

DEFAULT /bobf/if_conf_c=>sc_edit_read_only
iv_index TYPE i DEFAULT 1
RETURNING VALUE(rr_data) TYPE REF TO data
RAISING /bobf/cx_frw,

get_node_table_by_assoc IMPORTING iv_key TYPE /bobf/conf_key


iv_node_key TYPE /bobf/obm_node_key
iv_assoc_key TYPE /bobf/obm_assoc_key
iv_edit_mode TYPE /bobf/conf_edit_mode
DEFAULT /bobf/if_conf_c=>sc_edit_read_only
RETURNING VALUE(rr_data) TYPE REF TO data
RAISING /bobf/cx_frw,

get_node_row_by_assoc IMPORTING iv_key TYPE /bobf/conf_key


iv_node_key TYPE /bobf/obm_node_key
iv_assoc_key TYPE /bobf/obm_assoc_key
iv_edit_mode TYPE /bobf/conf_edit_mode

DEFAULT /bobf/if_conf_c=>sc_edit_read_only
iv_index TYPE i DEFAULT 1
RETURNING VALUE(rr_data) TYPE REF TO data
RAISING /bobf/cx_frw.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.


METHOD display_customer.
"Method-Local Data Declarations:
DATA lo_driver TYPE REF TO lcl_demo.
DATA lv_customer_key TYPE /bobf/conf_key.
DATA lx_bopf_ex TYPE REF TO /bobf/cx_frw.
DATA lv_err_msg TYPE string.

DATA lr_s_root TYPE REF TO /bobf/s_demo_customer_hdr_k.


DATA lr_s_text TYPE REF TO /bobf/s_demo_short_text_k.

"Try to display the selected customer:


TRY.
"Instantiate the test driver class:
CREATE OBJECT lo_driver.

"Lookup the customer's key attribute using a query:


lv_customer_key = lo_driver->get_customer_for_id( iv_customer_id ).

"Display the header-level details for the customer:


lr_s_root ?=
lo_driver->get_node_row(

iv_key = lv_customer_key
iv_node_key = /bobf/if_demo_customer_c=>sc_node-root
iv_index = 1 ).
WRITE: / 'Display Customer', lr_s_root->customer_id.
ULINE.
WRITE: / 'Sales Organization:', lr_s_root->sales_org.
WRITE: / 'Address:', lr_s_root->address.
SKIP.

"Traverse to the ROOT_TEXT node to display the customer short text:


lr_s_text ?=
lo_driver->get_node_row_by_assoc(

iv_key = lv_customer_key
iv_node_key = /bobf/if_demo_customer_c=>sc_node-root
iv_assoc_key = /bobf/if_demo_customer_c=>sc_association-root-root_text
iv_index = 1 ).
WRITE: / 'Short Text:', lr_s_text->text.
CATCH /bobf/cx_frw INTO lx_bopf_ex.
lv_err_msg = lx_bopf_ex->get_text( ).
WRITE: / lv_err_msg.
ENDTRY.
ENDMETHOD. " METHOD display_customer

METHOD get_node_table.
"Method-Local Data Declarations:
DATA lt_key TYPE /bobf/t_frw_key.
DATA ls_node_conf TYPE /bobf/s_confro_node.
DATA lo_change TYPE REF TO /bobf/if_tra_change.

DATA lo_message TYPE REF TO /bobf/if_frw_message.

FIELD-SYMBOLS <ls_key> LIKE LINE OF lt_key.


FIELD-SYMBOLS <lt_data> TYPE INDEX TABLE.

"Lookup the node's configuration:


CALL METHOD mo_bo_conf->get_node
EXPORTING
iv_node_key = iv_node_key
IMPORTING
es_node = ls_node_conf.

"Use the node configuration metadata to create the result table:


CREATE DATA rr_data TYPE (ls_node_conf-data_table_type).
ASSIGN rr_data->* TO <lt_data>.
"Retrieve the target node:
APPEND INITIAL LINE TO lt_key ASSIGNING <ls_key>.
<ls_key>-key = iv_key.

CALL METHOD mo_svc_mngr->retrieve


EXPORTING
iv_node_key = iv_node_key
it_key = lt_key
IMPORTING
eo_message = lo_message
eo_change = lo_change
et_data = <lt_data>.

"Check the results:


IF lo_message IS BOUND.
IF lo_message->check( ) EQ abap_true.
display_messages( lo_message ).
RAISE EXCEPTION TYPE /bobf/cx_dac.
ENDIF.
ENDIF.
ENDMETHOD. " METHOD get_node_table

METHOD get_node_row.
"Method-Local Data Declarations:
DATA lr_t_data TYPE REF TO data.

FIELD-SYMBOLS <lt_data> TYPE INDEX TABLE.


FIELD-SYMBOLS <ls_row> TYPE ANY.

"Lookup the node data:


lr_t_data =
get_node_table( iv_key = iv_key
iv_node_key = iv_node_key
iv_edit_mode = iv_edit_mode ).

IF lr_t_data IS NOT BOUND.


RAISE EXCEPTION TYPE /bobf/cx_dac.
ENDIF.

"Try to pull the record at the specified index:


ASSIGN lr_t_data->* TO <lt_data>.
READ TABLE <lt_data> INDEX iv_index ASSIGNING <ls_row>.
IF sy-subrc EQ 0.
GET REFERENCE OF <ls_row> INTO rr_data.
ELSE.
RAISE EXCEPTION TYPE /bobf/cx_dac.
ENDIF.
ENDMETHOD. " METHOD get_node_row

METHOD get_node_table_by_assoc.
"Method-Local Data Declarations:
DATA lt_key TYPE /bobf/t_frw_key.
DATA ls_node_conf TYPE /bobf/s_confro_node.
DATA ls_association TYPE /bobf/s_confro_assoc.
DATA lo_change TYPE REF TO /bobf/if_tra_change.
DATA lo_message TYPE REF TO /bobf/if_frw_message.

FIELD-SYMBOLS <ls_key> LIKE LINE OF lt_key.


FIELD-SYMBOLS <lt_data> TYPE INDEX TABLE.

"Lookup the association metadata to find out more


"information about the target sub-node:
CALL METHOD mo_bo_conf->get_assoc
EXPORTING
iv_assoc_key = iv_assoc_key
iv_node_key = iv_node_key
IMPORTING
es_assoc = ls_association.

IF ls_association-target_node IS NOT BOUND.


RAISE EXCEPTION TYPE /bobf/cx_dac.
ENDIF.

"Use the node configuration metadata to create the result table:

ls_node_conf = ls_association-target_node->*.

CREATE DATA rr_data TYPE (ls_node_conf-data_table_type).


ASSIGN rr_data->* TO <lt_data>.
"Retrieve the target node:
APPEND INITIAL LINE TO lt_key ASSIGNING <ls_key>.
<ls_key>-key = iv_key.

CALL METHOD mo_svc_mngr->retrieve_by_association


EXPORTING
iv_node_key = iv_node_key
it_key = lt_key
iv_association = iv_assoc_key
iv_fill_data = abap_true
IMPORTING
eo_message = lo_message
eo_change = lo_change
et_data = <lt_data>.

"Check the results:


IF lo_message IS BOUND.
IF lo_message->check( ) EQ abap_true.
display_messages( lo_message ).
RAISE EXCEPTION TYPE /bobf/cx_dac.
ENDIF.
ENDIF.
ENDMETHOD. " METHOD get_node_table_by_assoc

METHOD get_node_row_by_assoc.
"Method-Local Data Declarations:
DATA lr_t_data TYPE REF TO data.

FIELD-SYMBOLS <lt_data> TYPE INDEX TABLE.


FIELD-SYMBOLS <ls_row> TYPE ANY.

"Lookup the node data:


lr_t_data =
get_node_table_by_assoc( iv_key = iv_key
iv_node_key = iv_node_key
iv_assoc_key = iv_assoc_key
iv_edit_mode = iv_edit_mode ).

IF lr_t_data IS NOT BOUND.


RAISE EXCEPTION TYPE /bobf/cx_dac.
ENDIF.
"Try to pull the record at the specified index:
ASSIGN lr_t_data->* TO <lt_data>.
READ TABLE <lt_data> INDEX iv_index ASSIGNING <ls_row>.
IF sy-subrc EQ 0.
GET REFERENCE OF <ls_row> INTO rr_data.
ELSE.
RAISE EXCEPTION TYPE /bobf/cx_dac.
ENDIF.
ENDMETHOD. " METHOD get_node_row_by_assoc
ENDCLASS.

Note: In this simple example, we didnt bother to drill down to display the contents of
the ROOT_LONG_TEXTnode. However, if we had wanted to do so, we would have needed to create a
separate service manager instance for the /BOBF/DEMO_TEXT_COLLECTION business object since the
data within that node is defined by that delegated BO as opposed to the /BOBF/DEMO_CUSTOMER BO.
Otherwise, the process is the same.

MODIFYING CUSTOMER RECORDS

The process of modifying a customer record essentially combines logic from the display and create
functions. The basic process is as follows:

First, we perform a query to find the target customer record.

Next, we use the RETRIEVE*() methods to retrieve the node rows we wish to modify. Using the
returned structure references, we can modify the target attributes using simple assignment
statements.

Finally, we collect the node row changes into the modification table that is fed into MODIFY()method
provided by the /BOBF/IF_TRA_SERVICE_MANAGER instance.

The code excerpt below shows how the changes are carried out. Here, were simply updating the
address string on the customer. Of course, we could have performed wholesale changes if we had
wanted to.

CLASS lcl_demo DEFINITION CREATE PRIVATE.


PUBLIC SECTION.
CLASS-METHODS:
change_customer IMPORTING iv_customer_id
TYPE /bobf/demo_customer_id.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.


METHOD change_customer.
"Method-Local Data Declarations:
DATA lo_driver TYPE REF TO lcl_demo.
DATA lv_customer_key TYPE /bobf/conf_key.
DATA lt_mod TYPE /bobf/t_frw_modification.
DATA lo_change TYPE REF TO /bobf/if_tra_change.
DATA lo_message TYPE REF TO /bobf/if_frw_message.
DATA lv_rejected TYPE boole_d.
DATA lx_bopf_ex TYPE REF TO /bobf/cx_frw.
DATA lv_err_msg TYPE string.

FIELD-SYMBOLS:
<ls_mod> LIKE LINE OF lt_mod.

DATA lr_s_root TYPE REF TO /bobf/s_demo_customer_hdr_k.

"Try to change the address on the selected customer:


TRY.
"Instantiate the test driver class:
CREATE OBJECT lo_driver.

"Access the customer ROOT node:


lv_customer_key = lo_driver->get_customer_for_id( iv_customer_id ).

lr_s_root ?=
lo_driver->get_node_row( iv_key = lv_customer_key
iv_node_key = /bobf/if_demo_customer_c=>sc_node-root
iv_edit_mode = /bobf/if_conf_c=>sc_edit_exclusive
iv_index = 1 ).

"Change the address string on the customer:


lr_s_root->address = '1234 Boardwalk Ave.'.

APPEND INITIAL LINE TO lt_mod ASSIGNING <ls_mod>.


<ls_mod>-node = /bobf/if_demo_customer_c=>sc_node-root.
<ls_mod>-change_mode = /bobf/if_frw_c=>sc_modify_update.
<ls_mod>-key = lr_s_root->key.
<ls_mod>-data = lr_s_root.

"Update the customer record:


CALL METHOD lo_driver->mo_svc_mngr->modify
EXPORTING
it_modification = lt_mod
IMPORTING
eo_change = lo_change
eo_message = lo_message.

"Check for errors:


IF lo_message IS BOUND.
IF lo_message->check( ) EQ abap_true.
lo_driver->display_messages( lo_message ).
RETURN.
ENDIF.
ENDIF.

"Apply the transactional changes:


CALL METHOD lo_driver->mo_txn_mngr->save
IMPORTING
eo_message = lo_message
ev_rejected = lv_rejected.

IF lv_rejected EQ abap_true.
lo_driver->display_messages( lo_message ).
RETURN.
ENDIF.

"If we get to here, then the operation was successful:


WRITE: / 'Customer', iv_customer_id, 'updated successfully.'.
CATCH /bobf/cx_frw INTO lx_bopf_ex.
lv_err_msg = lx_bopf_ex->get_text( ).
WRITE: / lv_err_msg.
ENDTRY.
ENDMETHOD. " METHOD change_customer
ENDCLASS.

NEXT STEPS

I often find that the best way to learn a technology framework is to see how it plays out via code. At
this level, we can clearly visualize the relationships between the various entities and see how they
perform at runtime. Hopefully after reading this post, you should have a better understanding of how
all the BOPF pieces fit together. In my next blog post, well expand upon what weve learned and
consider some more advanced features of the BOPF API.
NAVIGATING THE BOPF: PART 4 ADVANCED BOPF API FEATURES

PERFORMING CONSISTENC Y CHECKS & VALIDATIONS

In keeping with the object-oriented paradigm, business objects (BOs) are designed to combine
business data and business functions together into one tidy capsule (hence the
term ENCAPSULATION). One of the primary benefits of combining these entities is to ensure that
updates to business data are reliably filtered through a set of business rules. To put this concept into
perspective, imagine a BO which defines a header-level status field (e.g. 01 = Initial, 02 = In Process,
03 = Closed). Now, from a pure data perspective, theres nothing stopping us from updating the status
field using the MODIFY() method of the /BOBF/IF_TRA_SERVICE_MANAGER interface (or heck, even via
an SQL UPDATE statement). However, from a business perspective, there are probably some rules
which define when, where, and how we should change the status field. For example, it might be that
the BO cannot be closed until any open line items are closed out, etc.

Whatever the business rules might be, the point is that we want to ensure that a BO is consistent
throughout each checkpoint in its object lifecycle. As we learned in part 2 of this blog series, the
BOPF allows us to define these consistency checks in the form of VALIDATIONS. For example, in
the screenshot below, you can see how SAP has created a validation called CHECK_ROOT for
the ROOT node of the /BOBF/DEMO_SALES_ORDER demo BO. This validation is used to perform a
consistency check on the sales order header-level fields to make sure that they are valid before an
update is committed to the database.

One of the nice things about validations like CHECK_ROOT is that they are automatically called by the
BOPF framework at specific points within the transaction lifecycle. However, sometimes we might
want to trigger such validations interactively. For example, when building a UI on top of a BO, we
might want to provide a check function which validates user input before they save their changes.
This is demonstrated in the /BOBF/DEMO_SALES_ORDER Web Dynpro ABAP application shown below.
From a code perspective, the heavy lifting for the check operation is driven by
the CHECK_CONSISTENCY()method of the /BOBF/IF_TRA_SERVICE_MANAGER interface as shown in the
code excerpt below. Here, we simply provide the service manager with the target node key and the
BO instance key and the framework will take care of calling the various validations on our behalf. We
can then check the results of the validation by looking at the /BOBF/IF_FRW_MESSAGE instance which
was introduced in the previous blog.

DATA lt_key TYPE /bobf/t_frw_key.

FIELD-SYMBOLS <ls_key> LIKE LINE OF lt_key.

DATA lo_message TYPE REF TO /bobf/if_frw_message.


TRY.

APPEND INITIAL LINE TO lt_key ASSIGNING <ls_key>.

<ls_key>-key = iv_key. "<== Sales Order BO Key

CALL METHOD mo_svc_mngr->check_consistency

EXPORTING

iv_node_key = /bobf/if_demo_sales_order_c=>sc_node-root

it_key = lt_key

iv_check_scope = '1'

IMPORTING

eo_message = lo_message.

...

CATCH /bobf/cx_frw INTO lx_frw.

...

ENDTRY.

Ill show you how to implement validations within a BO in an upcoming blog entry.

TRIGGERING ACTIONS

The behaviors of a business object within the BOPF are defined as ACTIONS. From a conceptual
point-of-view, actions are analogous to methods/functions in the object-oriented paradigm. The
following code excerpt demonstrates how actions are called using the BOPF API. Here, were calling
the DELIVER action defined in the ROOT node of the /BOBF/DEMO_SALES_ORDER demo BO. As you can
see, the code reads like a dynamic function/method call since we have generically pass the name of
the action along with its parameters to the DO_ACTION() method of
the /BOBF/IF_TRA_SERVICE_MANAGER interface. Other than that, its pretty much business as usual.

DATA lt_key TYPE /bobf/t_frw_key.

FIELD-SYMBOLS <ls_key> LIKE LINE OF lt_key.

DATA ls_parameters TYPE /bobf/s_demo_sales_order_hdr_d.

DATA lr_s_parameters TYPE REF TO data.

DATA lo_change TYPE REF TO /bobf/if_tra_change.

DATA lo_message TYPE REF TO /bobf/if_frw_message.

DATA lt_failed_key TYPE /bobf/t_frw_key.

DATA lt_failed_act_key TYPE /bobf/t_frw_key.


TRY.

"Set the BO instance key:

APPEND INITIAL LINE TO lt_key ASSIGNING <ls_key>.

<ls_key>-key = iv_key. "<== Sales Order BO Key

"Populate the parameter structure that contains parameters passed

"to the action:

ls_parameters-item_no = '001'.

GET REFERENCE OF ls_parameters INTO lr_s_parameters.

"Call the DELIVER action defined on the ROOT node:

CALL METHOD mo_svc_mngr->do_action

EXPORTING

iv_act_key = /bobf/if_demo_sales_order_c=>sc_action-root-deliver

it_key = lt_key

is_parameters = lr_s_parameters

IMPORTING

eo_change = lo_change

eo_message = lo_message

et_failed_key = lt_failed_key

et_failed_action_key = lt_failed_act_key.

...

CATCH /bobf/cx_frw INTO lx_frw.

...

ENDTRY.

We can verify if a BOPF action call was successful by querying the EO_MESSAGE object reference
and/or the ET_FAILED_KEY table parameters returned by the DO_ACTION() method. Refer back to my
previous blog for an example of the former technique. As always, remember to commit the transaction
using the

SAVE() method defined by the /BOBF/IF_TRA_TRANSACTION_MGR interface.


ACTION VALIDATIONS

In part two of this blog series, I mentioned that there are technically two different types of validations:
the consistency check validations discussed earlier in this blog and action validations which are used
to determine whether or not an action can be executed at runtime. Since the BOPF framework
invokes action validations automatically whenever actions are invoked, it is rare that you will have a
need to invoke them directly. However, the /BOBF/IF_TRA_SERVICE_MANAGER interface does provide
the DO_ACTION() method if you wish to do so (see the code excerpt below).

DATA lt_key TYPE /bobf/t_frw_key.

FIELD-SYMBOLS <ls_key> LIKE LINE OF lt_key.

DATA ls_parameters TYPE /bobf/s_demo_sales_order_hdr_d.

DATA lr_s_parameters TYPE REF TO data.

DATA lo_message TYPE REF TO /bobf/if_frw_message.

DATA lt_failed_key TYPE /bobf/t_frw_key.

DATA lt_failed_act_key TYPE /bobf/t_frw_key.

TRY.

"Set the BO instance key:

APPEND INITIAL LINE TO lt_key ASSIGNING <ls_key>.

<ls_key>-key = iv_key. "<== Sales Order BO Key

"Populate the parameter structure that contains parameters passed

"to the action:

ls_parameters-item_no = '001'.

GET REFERENCE OF ls_parameters INTO lr_s_parameters.

"Check to see if the DELIVER action can be invoked:

CALL METHOD mo_svc_mngr->check_action

EXPORTING

iv_act_key = /bobf/if_demo_sales_order_c=>sc_action-root-deliver

it_key = lt_key

is_parameters = lr_s_parameters

IMPORTING
eo_message = lo_message

et_failed_key = lt_failed_key

et_failed_action_key = lt_failed_act_key.

...

CATCH /bobf/cx_frw INTO lx_frw.

...

ENDTRY.

TRANSACTION MANAGEMENT

Another element of the BOPF API that we have glossed over up to now is the transaction manager
interface /BOBF/IF_TRA_TRANSACTION_MGR . This interface provides us with a simplified access point
into a highly sophisticated transaction management framework. While the details of this framework
are beyond the scope of this blog series, suffice it to say that the BOPF transaction manager does
more here than simply provide basic object-relational persistence. It also handles caching,
transactional locking, and more. You can see how some of these features are implemented by looking
at the TRANSACTIONAL BEHAVIOR settings of a business object definition in Transaction
/BOBF/CONF_UI (see below).
So far, we have seen a bit of the /BOBF/IF_TRA_TRANSACTION_MGR on display whenever we looked at
how to insert/update records. Here, as you may recall, we used SAVE() method of
the /BOBF/IF_TRA_TRANSACTION_MGR interface to save these records. In many respects,
the SAVE() method is analogous to the COMMIT WORK statement in ABAP in that it commits the
transactional changes to the database. Here, as is the case with the COMMIT WORK statement, we
could be committing multiple updates as one logical unit of work (LUW) e.g. an insert followed by a
series of updates.

Once a transaction is committed, we can reset the transaction manager by calling


the CLEANUP()method. Or, alternatively, we can also use this method to abandon an in-flight
transaction once an error condition has been detected. In the latter case, this is analogous to using
the ROLLBACK WORK statement in ABAP to rollback a transaction.

During the course of a transaction, the BOPF transaction manager tracks the changes that are made
to individual business objects internally so that it can determine what needs to be committed and/or
rolled back. If desired, we can get a peek of the queued up changes by calling
the GET_TRANSACTIONAL_CHANGES() method of the /BOBF/IF_TRA_TRANSACTION_MGR interface. This
method will return an object reference of type /BOBF/IF_TRA_CHANGE that can be used to query the
change list, modify it in certain cases, and so on.

NEXT STEPS

At this point, we have hit on most of the high points when it comes to interacting with the BOPF API
from a client perspective. In my next blog, well shift gears and begin looking at ways of enhancing
BOs using the BOPF toolset.

NAVIGATING THE BOPF: PART 5 ENHANCEMENT TECHNIQUES

WHAT TO ENHANCE?

Before we dive into the exploration of specific enhancement techniques, lets first take a look at the
kinds of entities were allowed to enhance in a business object. Aside from implicit enhancements
applied to implementation classes using the Enhancement Framework, the types of entities that we
can enhance within a business object are as follows:

CUSTOM ATTRIBUTES

For a given node, we might want to define a handful of additional custom attributes.These attributes
could be persistent (i.e., they get appended to the target database table which contains the node
data) or transient in nature.

NEW SUB-NODES

In some cases, we may need to do more than simply define a few new attributes on an existing node.
Using the relational data model as our guide, we may determine that a new sub-node is needed to
properly model some new dimension of data (e.g. 1-to-many relations, etc.). Depending on the
requirement, the sub-node(s) might be persistent or transient in nature.

DETERMINATIONS
If we add new custom attributes to a given node, it stands to reason that we might also want to create
a custom determination to manage these attributes.

Or, we might have a standalone requirement which calls for some sort of trigger to be fired
whenever a specific event occurs (e.g. fire an event to spawn a workflow, etc.).

CONSISTENCY VALIDATIONS

If we are enhancing the data model of a business object, we might want to define a consistency
validation to ensure that the new data points remain consistent.

A custom validation might also be used to graft in a new set of business rules or a custom security
model.

ACTIONS

If we have certain operations which need to be performed on a business object, we would prefer to
encapsulate those operations as an action on the business object as opposed to some standalone
function module or class.

QUERIES

In some cases, the set of defined queries for a business object might not be sufficient for our needs.
In these situations, we might want to define custom queries to encapsulate the selection logic so that
we can use the generic query services of the BOPF API as opposed to some custom selection
method.

You can find a detailed treatment of supported enhancement options in the BOPF ENHANCEMENT
WORKBENCH HELP documentation which is provided as a separate download in SAP Note
#1457235. This document provides a wealth of information concerning the use of the BOPF
Enhancement Workbench, enhancement strategies, and even the BOPF framework in general. Given
the amount of detail provided there, I wont attempt to re-invent the wheel in this blog post. Instead, Ill
simply hit on the high points and leave the nitty-gritty details to the help documentation.
WORKING WITH THE ENHANCEMENT WORKBENCH

When enhancing a business object, youll be spending quite a bit of time with the BOPF
Enhancement Workbench which can be accessed using Transaction BOPF_EWB. Here,
enhancement projects are organized into ENHANCEMENT OBJECTS. From a conceptual point-of-
view, enhancement objects bear a lot of similarities to sub-classes in the object-oriented programming
(OOP) paradigm. This is to say that enhancement objects INHERIT all of the entities of their parent
BO. With this foundation in place, we can begin defining custom entities in much the same way we
might add new attributes/methods to a subclass in the ABAP Class Builder tool. However, as is the
case with classes in the OOP world, we cannot extend BOs which are marked as final or that do not
have the Business Object can be enhanced flag set (see below).

All of the BOs which are eligible for enhancement will show up in the Enhancement Browser
perspective of the BOPF Enhancement Workbench shown below. To create an enhancement, simply
right-click on the BO that you wish to enhance and select the Create Enhancement menu option (see
below). From here, the BOPF Enhancement Workbench will guide you through a wizard process
which allows you to select the name of the enhancement object, the constants interface for the
enhancement object, and so on.
Once the enhancement is created, you will be able to edit your enhancement object in the workbench
perspective of the BOPF Enhancement Workbench shown below. As you can see, it has a similar
look-and-feel to that of the normal BO browser tool (Transaction /BOBF/CONF_UI). From here, we
can begin adding custom entities by right-clicking on the target node and selecting from the available
menu options. Well see how this works in the upcoming sections.

One final item I would draw your attention to with enhancement objects is the assigned constants
interface (highlighted above). This constants interface can be used to access the enhancement object
entities in the same way that the super BOs constants interface is used for BOPF API calls, etc.

ENHANCING THE BO DAT A MODEL

Perhaps the most common type of enhancement to BOs in the BOPF is the addition of new fields.
Here, we have the option of adding new fields to existing nodes or creating sub-nodes to model more
complex relationships. In the former case, we sometimes dont even need to create an enhancement
object; just a simple append structure will suffice (see below).
For more complex data requirements, we typically need to define sub-nodes. This can be achieved by
right-clicking on the parent node and selecting the Create Subnode menu option. This kicks off a
wizard process in which you can select the sub-nodes name, its persistent and/or transient
structures, and the rest of the auto-generated dictionary types which go along with a node definition
(e.g. combined structure/table type, database table, etc.). Most of this is pretty standard stuff, but I
would draw your attention to the step which creates the persistent and/or transient structures. Note
that these structures must exist in the database BEFORE you move on from the Attributes step in the
wizard process. And, in the case of the persistent structure, you must include
the /BOBF/S_ADMIN structure as the first component.
After the custom sub-node is created, you can fill out its attributes by adding components to the
persistent/transient structures defined by the sub-node. If the sub-node is a persistent node, then we
can create, modify, and retrieve node instances using the BOPF API as per usual. However, in the
case of transient nodes, we need determinations to pre-fetch the data for us. Well see how to define
such determinations next.

DEFINING DETERMINATIONS

According to the help documentation, determinations encapsulate internal changing business logic on
a business object. Unlike the logic encapsulated in actions which can be triggered at any time, the
business logic contained within determinations is triggered as specific times within the BO life cycle
(e.g. right before a node is saved, etc.). So, in a way, it is appropriate to think of determinations as
being a little bit like user exits/BAdIs/enhancement spots in that they provide a place to hang custom
logic at particular points within the process flow.

Once we determine (no pun intended) that we want to create a determination for a given node, we
can do so by simply right-clicking on that node and selecting the Create Determination menu option.
This will spawn a wizard which guides us through the process. Here, there are two main properties
that we must account for:

IMPLEMENTING CLASS:
We must create or assign an ABAP Objects class that implements
the /BOBF/IF_FRW_DETERMINATION interface.
DETERMINATION PATTERN:
This property defines the event which triggers the determination. As you can see below, the set of
available patterns will vary depending on the type of node youre enhancing, its location in the node
hierarchy, and so on.

Once a pattern is selected, you may be presented with additional options for refining when an event is
triggered. For example, if we select the pattern Derive dependent data immediately after
modification, we will have the opportunity to specify if the dependent data should be created/modified
after any modification, only when the node is created the first time, etc.

Because determinations can be used for a lot of different things, they can be implemented in a lot of
different ways. Here, it is very important that you pay close attention to selecting the right pattern for
the right job. The aforementioned help documentation provides a good set of guidelines to assist
here. Other valuable resources include the interface documentation for
the /BOBF/IF_FRW_DETERMINATIONinterface in the Class Builder tool and SAP standard-delivered
determinations implementations available in the system youre working on.

DEFINING CONSISTENCY VALIDATIONS

The process of defining a custom consistency validation is quite similar to the one used to define
determinations. Walking through the wizard process, there are three main properties that we must
account for:
IMPLEMENTING CLASS:
Here, we must create/assign an ABAP Objects class which implements
the /BOBF/IF_FRW_VALIDATION interface.

REQUEST NODES:
This property allows us to specify which node operations should force a validation to occur (e.g.
during creates, updates, etc.)

IMPACT:
With this property, we can specify the behavior of the BOPF framework in cases where the validation
fails. For example, should we simply return an error message, prevent the requested operation from
proceeding, or both?

From an implementation perspective, the /BOBF/IF_FRW_VALIDATION interface provides us with


everything we need to perform the validation check: the context of the validation, the current data
within the node instance being validated, and so on. For more information about how to implement the
validation class, I would highly recommend that you read through the interface documentation for
the /BOBF/IF_FRW_VALIDATION interface in the Class Builder tool. It can also be helpful to look at
various standard-delivered classes which already implement this interface to see common
patterns/idioms used by SAP.

WORKING WITH ACTIONS

When it comes to the customization of actions, we have a couple of options:

We can create a brand new action definition for a given node (standard or custom).

We can enhance existing actions with pre/post action enhancements.

The first case is pretty straightforward. Basically, we simply follow along with the wizard process up to
the point that we reach the Settings step shown below. Here, we must define three main properties for
the action:

IMPLEMENTING CLASS:
This property is used to specify the ABAP Objects class which encapsulates the action logic. The
class must implement the /BOBF/IF_FRW_ACTION interface.

ACTION CARDINALITY:
The action cardinality property defines the scope of the action. This is somewhat analogous to the
way we have the option of defining class methods or instance methods within a regular ABAP Objects
class. In this case however, we also have the third option of defining a sort of mass-processing
action which works on multiple node instances at once.

PARAMETER STRUCTURE:
If we wish to pass parameters to the action, we can plug in an ABAP Dictionary structure here to
encapsulate the parameters.
Once the action is created, we simply need to plug in the relevant logic in the defined implementation
class. You can find implementation details for this in the interface documentation and/or sample
action classes in the system.

In order to create a pre/post action enhancement, the target action definition in the super BO must
have its Action Can Be Enhanced flag set (see below). Assuming that the flag is set, then we can
proceed through the corresponding wizard process in much the same way we would if we were
creating a custom action from scratch. Indeed, as is the case with regular actions, the implementation
class(es) for pre/post action enhancements must implement the /BOBF/IF_FRW_ACTION interface.
Before you go to implement a pre/post action enhancement, I would definitely recommend that you
read through the help documentation so that you understand what you can and cannot do within an
action enhancement. Most of the rules are intuitive, but you can definitely get into trouble if you abuse
these enhancements by using them for things they werent designed for.

DEFINING CUSTOM QUERIES

Compared to the various enhancement options weve seen thus far, custom queries are perhaps the
easiest entities to create within an enhancement object. Indeed, if all we want is a simple node
attribute query, we can zip through the wizard and have a working model up and running in a matter
of minutes. If we want something a little more custom/sophisticated, our job is only marginally more
difficult (at least from a configuration perspective) in that we must assign an implementing class and
an optional data type which serves as the parameter structure passed into the query from the client
side (see below).
From an implementation perspective, all of the query logic for a custom query gets encapsulated in
the implementation class (which must implement the /BOBF/IF_FRW_QUERY interface). For the most
part, youll find that the framework doesnt really get in the way with regards to how we go about
implementing the query. Basically, it passes in the query parameters up front and its up to us to figure
out how to find all of the node instances which match the given parameters. Here, we must pay
careful attention to the SQL statements that we use since the query may be used extensively by a
number of different clients.

NEXT STEPS

Hopefully by now you have a general feel for how BOs are enhanced and the basic steps required to
achieve these enhancements. As is the case with most programming-related subjects, the best way to
really drive these concepts home is to look at live examples and experiment for yourself. I would also
highly recommend that you read through the aforementioned help documentation as it devotes quite a
bit of time to understanding when and where to apply specific enhancement techniques.

In my next and final blog post in this series, Ill demonstrate another useful tool within the BOPF
toolset: the BO test tool. This tool can be used to experiment with BOs and perform ad hoc unit tests,
etc.
NAVIGATING THE BOPF: PART 6 TESTING & UI INTEGRATION

WORKING WITH THE BOP F TEST UI

We can access the BOPF Test UI by opening up Transaction /BOBF/TEST_UI. When you initially
open up the tool, youll be presented with a screen like the one shown below. From here, we can
begin working with a BO instance by plugging in the BO type in the SELECT BO input field (either
key it in or use the provided input help) and hitting the ENTER key. This causes the BO metadata to
be loaded into context so that we can use it to guide ourselves through the editing process.

EDITING BO INSTANCES

Once the BO metadata is loaded, we have two choices for maintenance:

To create a new BO instance, we can double-click on the root node contained in the Metadata and
Instances tree on the left-hand side of the editor screen and then select the Create button in the
toolbar (see below). This will cause a new record to be created and loaded into an editable ALV grid.
From here, we can begin filling in node attributes, creating sub-node instances, and so on. Here, I
would draw your attention to the MESSAGES panel located in the bottom left-hand corner of the
editor. These messages can be used to help you fill in the right data.

If the BO instance that we want to maintain/display exists already, then we can load it into context
using the LOAD INSTANCES button menu. As you can see in the screenshot below, this menu
affords us with several different alternatives for loading node instances: via a BOPF node query, by
the node instance key, or by an alternative key (e.g. ID). Regardless of the menu path that we take,
the system will attempt to find the target node instance(s) and then load them into the editor window.
From here, we can select individual node instances by double-clicking on them in the METADATA
AND INSTANCES tree located on the left-hand side of the screen.

To edit node instances, we can select the node instance record in the editor on the right-hand side of
the screen and choose the appropriate option from the EDIT button menu (see below). Then, we can
edit attributes for a node instance using the provided input fields. Alternatively, we also have the
option of deleting a node instance (or indeed an entire BO instance in the case of a root node
instance) by clicking on the DELETE NODE INSTANCES button.

Regardless of whether or not were creating a new BO instance or editing an existing one, the entire
scope of our changes is tracked via a BOPF transaction like the one we would create if we were doing
all this by hand using the BOPF API. At any point along the way, we can choose to commit the
changes using the SAVE TRANSACTION button, or revert the changes using the CLEANUP
TRANSACTION button. Then, we can start the process over by selecting another BO instance or
editing the existing one in place. All in all, its kind of like table maintenance on steroids. But wait,
theres more!

TRIGGERING ACTIONS, VALIDATIONS, & DETERMINATIONS

In addition to the basic CRUD operations described earlier, the test UI also provides functions to call
actions, validations, and even trigger determinations. For a given node instance, these functions can
be accessed in the node instance toolbar via the CHECK and ACTIONS button menus (see below). If
you read through my blog posts related to the BOPF API, then these should feel quite intuitive.

UI INTEGRATION AND THE FBI FRAMEWORK

Since the focus of this blog series has been primarily on introducing the BOPF framework, I have
purposefully avoided digressing into specific applications of the BOPF (e.g. in Transportation
Management or EHSM) since these products add additional layers on top of the BOPF that can sort
of cloud the picture a bit if you dont understand core principles of the BOPF itself. However, before I
bring this blog series to a close, I would be remiss if I didnt point out one important (and relatively
generic) framework built on top of the BOPF: the FLOORPLAN MANAGER BOPF
INTEGRATION (FBI) framework. As the name suggests, this framework links BOs from the BOPF
with Web UIs based on the Floorplan Manager (FPM) framework and Web Dynpro ABAP (WDA).

If youre developing Web UIs on top of BOs from the BOPF, then the FBI is definitely something to
take a look at. Essentially, the FBI exploits the genericity of the BOPF API and the accessibility of BO
model data to enable the rapid development of GENERIC USER INTERFACE BUILDING
BLOCKS (GUIBBs) based on BO nodes. Here, for example, we could create a form GUIBB that
allows users to populate the data for a BO node using a simple input form. In many applications, this
can be achieved without having to write a single line of code. While a detailed discussion of the FBI is
beyond the scope of this blog series, a quick Google search will lead you to some pretty decent
resource materials. If youre new to FPM, I would also offer a shameless plug for my book Web
Dynpro ABAP: The Comprehensive Guide (SAP PRESS, 2012).

CONCLUSION

When I first started working with the BOPF almost a year ago, I was surprised at how little
documentation there was to get started with. So, what youve seen in this series is the result of a lot of
trial-and-error and lessons learned by debugging past application-specific frameworks into the heart
of the BOPF itself. If youre just getting started with the BOPF, then I hope that youll find this series
useful to get you up and running. In the coming months and years, I think many more learning
resources will materialize to supplement what Ive offered here. Indeed, the number of new dimension
applications based on the BOPF appears to be growing by the day

One complaint I sometimes hear from other developers is that the BOPF API is cumbersome to work
with. On this point, I can agree to a point. However, I would argue that such complexities can be
abstracted away pretty easily with a wrapper class or two and some good old fashioned RTTI code.
Other than that, once you get used to the BOPF, I think youll find that you like it. And this is coming
from a developer who has had many bad experiences with BO frameworks (both in and outside
SAPcurse you EJBs!!!). All in all though, I have found the BOPF to be very comprehensive and
flexible. For me, one of the feel tests I normally conduct to gauge the effectiveness of a framework is
to ask myself how often the framework gets in my way: either because its too intractible, limited in
functionality or whatever. I have yet to run into any such occurrences with the BOPF. It does a good
job of providing default behaviors/functionality while at the same time affording you the opportunity to
tweak just about everything. For example, if I want to build my own caching mechanism, I can do so
by plugging in my own subclass. If I want to pull data from a HANA appliance in real time, I can do so
in a determination. You get the idea. Its all there, so just poke around a bit and I think youll find what
you need.

S-ar putea să vă placă și