Value Mapping Replication Scenario

Value Mapping Replication Scenario


Background

PI Mapping Runtime can require external data for serveral reasons. Most common are different names for same unities in different systems. For example material classes vary often as well as names for organizations. A mapping program requires in such cases an access to a table where the values from different systems are correlated. There are quite different strategies to implement such a scenario:
  • Put the data direct into the mapping program: Most serios disadvantage would be a bad maintenance; the program has to be changed and retested in case of new or changed values .
  • Reading the data from an external file or a PI table: Unusual maintenance and no control of authorization
  • Access the data during runtime via lookup: Can lead to performance issues. Analyzing any errors could be difficult as the monitoring isnt that smooze as for message traffic. A temporary connection problem to the value mapping storage would be an additional risc.
  • Storing the data in a SAP ECC table for usual maintenance (SM30) and good control of authorization and replicating them by any change to PI Java Runtime Cache for a good runtime performance

Description of the scenario

The external data (correlation of different values) are stored in SAP ECC z-table. By any change of the table content an ABAP program calls a proxy, which replicates the whole table content. There wont be any performance issues if the data are not changed too often and if this are not too much data. This preconditions shouldnt be a problem in the most cases. The full table replication is much easier than a delta load and can be implemented within a few hours.

The data are replicated to Java Runtime Mapping Cache, they can be controlled from Runtime Workbench. A standard function from Message Mapping can make use of the correlated values, the Runtime performance for this sceanrio is better than for any scenario with lookup.

Value Mapping Replication Scenario

Example

Suppose we have different purchase organizations in a SAP system and a third party system. We are planning to add later organizations and we might want to add another third party system in future. To exchange messages we need to map that organizations by an external table.

Mapping Table at SAP System

The mapping table is created at the SAP system (transaction SE11).
The context is individual for our mapping case (and therefore for our scenario and our third party system). The context and at least one of the mapping values should be key of the table.
Transparent Table (SE11) for Mapping Values

Table Maintenance Generator

The function Utilities / Table Maintenance Generator at SE11 allows to create a quick controlled table maintenance from SM30). We can choose directly a Authorization Group for a control of access. The Function Group, which later will be extended, must be in the customers namespace. From this dialog we can jump to the event handling: Environment / Modification / Events
Table Maintenance Dialog Generator

Events from Table Maintenance

An event can be defined in that step, for example "02 - After saving in the database", and a FORM routine what should be called if that event was raised. A own FORM should be typed in here, which will be created in the next step.

Event and FORM routine to be called

Function Group

A new include needs to created in the Function Group (SE80), what was typed in at the Table Maintenance Dialog. It has to be in the customers namespace. During the activation there could popup some confusing messages which can be ignored. The include just contains the FORM routine from the last step.

New Include in the Function Group containing the FORM routine

ABAP Outbound Proxy

With the SAP BASIS Software Component two ABAP outbound proxies were delivered (transaction SPROXY). In our example the synchronous proxy is used.

ABAP Proxy ValueMappingReplicationOutSynchronous

It can be used to send messages directly (as XML) to the PI Integration Engine. The view tabs are very helpful during implementation of the ABAP program (the FORM) routine. They provide an overview about the structure and by clicking on an element the type can be copied from "ABAP Name Ref.".

  • Operation: Fixed Value: Insert, Delete, DeleteGroup, DeleteContext or DeleteContextGenerice. This value determines the action. In our example we use "Insert" and "DeleteContext".
  • GroupID: 2 Values with the same GroupID belong together (correlation). To create that 32 character hexadecimal number function module ICF_CREATE_GUID is used.
  • Context: Values of one context belong to one scenario. For values of one context can be searched at RTW and one context can be deleted by only one message.
  • Identifier(VALUE): The value of the parameter in the different systems. In our case the value for the purchase organization.
  • scheme: A scheme what the value is about. In our case the fix value "PurchaseOrg". The scheme would allow to extend the scenario for other mapping tasks to use only one ECC table for a lot PI scenarios. In our example a constant is used, the more generic scenario would require a variable value there.
  • agency: The system (or the "agency") what the value is belonging to. In our case SAP or the the third party system.

Source Code of FORM routine:

Java Inbound Proxys

The Java inbound proxies on the Integration Server can easily be activated by calling a simple URL:
Asynchronous: http://:/ProxyServer/register?ns=http://sap.com/xi/XI/System&interface=ValueMappingReplication &bean=localejbs/sap.com/com.sap.xi.services/ValueMappingApplication &method=valueMappingReplication
Synchronous: http://:/ProxyServer/register?ns=http://sap.com/xi/XI/System&interface=ValueMappingReplicationSynchronous &bean=localejbs/sap.com/com.sap.xi.services/ValueMappingApplicationSynchronous &method=valueMappingReplicationSynchronous

Integration Builder Configuration

  • Sending System: SAP System >= WAS 6.20
  • Receiving System: Integration Server
  • Receiver Determination: Sender: SAP-System / IF: ValueMappingReplicationSynchronous / NS: http://sap.com/xi/XI/System - Receiver: Integration Server
  • Interface Determination: Sender: SAP-System / IF: ValueMappingReplicationSynchronous / NS: http://sap.com/xi/XI/System - Receiver: Integration Server Inbound-IF: ValueMappingReplicationSynchronous / Inbound-NS: http://sap.com/xi/XI/System - no Mapping
  • Communication Channel: Component: Integration Server - Adapter Type: XI-Receiver - HTTP Destination: Destination to Integration Engine
  • Destination: Type: H, Host: Java host, Service No: Java Port, Path-Prefix: /MessagingSystem/receive/JPR/XI
  • Receiver Agreement: Sender: SAP-System - Receiver: Integration Server / IF: ValueMappingReplicationSynchronous / NS: http://sap.com/xi/XI/System - Receiver Channel: like above

Replication Control

The proxy replication can be monitored at transaction SXMB_MONI either at SAP and at PI. The values are available at Runtime Workbench / Cache Monitoring / Cache Instance: Mapping Runtime Cache, CAche Object: Value Mapping Groups

Use in Message Mapping

Value Mappings can maintained with standard function "Value Mapping". The context must be typed in, as well the Schema ("PurchaseOrg" for our example). The organizations are mapped by the typed in values for source and target agency. The behaviour regarding exceptions of the function can be maintained: Source value, default value or runtime exception

Standard Function Value Mapping

SAP Help Linx

Value Mapping
Value Mapping Replication for Mass Data

Excel Files - How to handle them in SAP XI/PI (The Alternatives)

Excel Files - How to handle them in SAP XI/PI (The Alternatives)


Life would have been easy if XI/PI provided us with the option of handling data of MS Excel files in a standard way. Unfortunately it doesnt !

So how can Excel files be handled in XI/PI?

There are actually quite a few options available for us;

1. Use Conversion Agent - Reference

2. Use XSLT Mapping - Reference

3. Use JAVA

Its the third option that we will be looking into in this blog.

There are free APIs available to help us read or create an excel file. One such API is the JExcelAPI

I found it to be a very simple API to use and code. The jar files for building any project using the JExcel API can be downloaded from here

The solution that I assume is the best would be to code a module. The module can be coded in such a way so that you can make it generic across scenarios as per your landscape and requirements.

Lets now look at the design of two scenarios.

a. Read an Excel File

You can use the package jxl to your advantage in this case. The method getWorkbook(java.io.InputStream is) can be used in the module to read the workbook. There are various interfaces like sheet and cell that provides you various methods to access the data.

Once you access the data you can write out the source XML directly from the module so that it can be used for transformation. If you are lazy, and dont want to build the XML from your module itself, then make sure you write out a flat file format from your module and leave the XML conversion to the MessageTransformBean (Plain2XML), that will be next in chain after your custom module.

b. Writing an Excel File

Comparing reading to writing excel files, reading is relatively an easy task you can perform with the API. For writing out an excel file, the API provides you numerous interfaces and methods that can help you also do the following if required in a scenario;

1. Formating - Format cells in terms of font, font colour, number and date formatting

2. You can also edit the cells in terms of assigning background colours, borders etc.

3. Even formulas can be applied to the excel file

There are two ways you can code your module. The first would be to take the target XML itself as the input, parse the XML and then convert it to the required XML format. This would mean you implement a SAX or DOM parser to help you read data from the XML. The other option is to use the MessageTransformBean (XML2Plain) first in the chain to create a flat file format. You can then using String functions in the module to play around with the payload. I personally prefer this since its quite easy to manipulate Strings :)

To create/write Excel files, the package jxl.write should be used. You can use the method createWorkbook(java.io.OutputStream os) of the Workbook class in the module. As mentioned earlier, it is also possible to set font, font colour, background colour, borders etc for the cells.

I have written a sample class which tries to create an excel output that you can base as a reference while building your custom module. The code also documents the formatting of cells, just in case your client expects some 'delicacies' of that kind :)

Find the code here - LINK

Note:

There are also other APIs other than JExcel that can be used. Another widely used API is POI-HSSF and POI-XSSF, part of the Apache POI project. You can also explore that option, but on a personal note I found the JExcel API much easier to use.

Maintain PI 7.1 Adapter Modules in NWDI

Maintain PI 7.1 Adapter Modules in NWDI


As NWDI get's more powerful I try to use it for an increasing number of projects. In that spirit I've picked up the topic of putting PI Adapters and Modules under NWDI-control again and digged through the available SCs.

The good message: One can easily develop PI Modules in NWDI, the only thing needed are the right dependencies. Here's a brief walkthrough:

Set up the NWDI-Project

  • add the SC SAP_XIAF to your track. I used SAPXIAF06P_7-20001975.SCA, if you know whether this guide also works on 3.0, 7.0 and 7.11 components please add a comment
  • create a new J2EE/EJB Module, remember to set the Java EE Version to 1.4
  • create a new J2EE/Enterprise Application, remember to set the Java EE Version to 1.4 and reference the module
  • add references to the SC SAP_XIAF:

  1. com.sap.aii.af.ifc.facade for the Message-Interfaces
  2. com.sap.aii.af.lib.facade for the Module-Interfaces
SAP_XIAF references


  • for facilitating the logging api you might also want to reference

  1. tc/bl/logging/api

ENGFACADE references



Alltogether the module's references should look like this:

all needed references

  • Also add those references to the Enterprise Application DC, don't forget to set the deploy time & run time reference hooks

deploy & runtime references


Develop the module

Now you're all set up and ready to go. Create an EJB 2.1 Stateless Session Bean implementing com.sap.aii.af.lib.mp.module.Module...

/*
* (non-Javadoc)
*
* @see com.sap.aii.af.lib.mp.module.Module#process(com.sap.aii.af.lib.mp.module.ModuleContext,
* com.sap.aii.af.lib.mp.module.ModuleData)
*/
public ModuleData process(ModuleContext ctx, ModuleData md)
throws ModuleException {
final com.sap.engine.interfaces.messaging.api.Message message;
final com.sap.engine.interfaces.messaging.api.XMLPayload document;
final com.sap.engine.interfaces.messaging.api.auditlog.AuditAccess auditAccess;

try {
Object principalData = md.getPrincipalData();
message = (com.sap.engine.interfaces.messaging.api.Message) principalData;
document = message.getDocument();
auditAccess = com.sap.engine.interfaces.messaging.api.PublicAPIAccessFactory
.getPublicAPIAccess().getAuditAccess();
auditAccess
.addAuditLogEntry(
message.getMessageKey(),
com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus.SUCCESS,
"Everything is fine.");

document.setContent("important message".getBytes());

return md;
} catch (Exception e) {
throw new ModuleException("Cannot process message in module: " + e,
e);
}

}


Remember you still need to set up ejb-jar.xml, ejb-j2ee-engine.xml and application-j2ee-engine.xml. Consult help.sap.com and the sample module for detailed documentation.

When you're done you can use shiny things like CBS and CMS for your new module.

Note:

  1. There is another blog you might want to have a look at by Alka Panday: "J2EE Adapter Module development using NWDI" describing how to expose the SAP libraries as external library DCs.
  2. If you know a more EJB3-like way to get a working module please drop me some lines.

Adapter Engine Lost

Adapter Engine Lost


Adapter Engine Lost

Sometimes when you have installed SAP Process Integration, the Adapter Engine Component doesn’t appear in the Runtime WorkBench.
I don’t know why, but in two installations that I made in clustered systems, the Adapter Engine did not appears in the Runtime Workbench.

It’s strange when you see that SAP J2EE Engine works correctly and the Adapter Engine component is wrong in Runtime Workbench application, that was my situaciĆ³n. I started to investigate what was the aplication where I could make the configuration for this issue and I found that all component setting were configured in CIM model aplication.
Fortunately, I had installed the development and quality systems and I could check how was configure the CIM model in those systems.
What happened in my production system? Nothing was configured !!!!!! All entries of Adapter Engine had dissapeared !!!!!
The solution was check the entries into development and quality system and create those entries in production system. This job is very boring but is the only solution that I know.
Now I tell us what options into the CIM model you must to create.
1. First, go to http://server:port/sld and click over CIM Instance options
image
2. Once into the application, choose this option
image
  • XI Remote Admin Service: In this part, there weren't anything option configured. We had to create AdminTool, Cache_Refresh, Runtime Check for af, Directory, Repository, and rwb SAP XIRemoteAdminServices.
  • XI Adapter Service: In this option I created all adapters for my production system, BC, CIDX, File, JDBC, JMS, Mail, MarketPlace, RFC, RNIF, SOAP, WS, XI and XIRA XIAdapterService.
  • Finally I had to configure the HTTP Service Port option creating severals services ports, Basic URLs, HTTP Service Port, Pipeline, Port for Admin Tool, JMS, MAIL, JDBC, Runtime Check af, Runtime Check Directory, Runtime Check Repository, Runtime Check rwb, SOAP, WS, XI, XIRA.

Proceed with caution when you make the relationship betwen the components, it is very important do it correctly.
When I finished the services creation into the CIM model I had to restart the SAP J2EE Engine and the Adapter Engine appeared in Runtime Workbench with green colour.
Note:
There are one note (Note 764176 - Error in XI due to inconsistent SLDcontents) where it described a similar problem with other solution.

Adapter Engine Lost

Adapter Engine Lost


Adapter Engine Lost

Sometimes when you have installed SAP Process Integration, the Adapter Engine Component doesn’t appear in the Runtime WorkBench.
I don’t know why, but in two installations that I made in clustered systems, the Adapter Engine did not appears in the Runtime Workbench.

It’s strange when you see that SAP J2EE Engine works correctly and the Adapter Engine component is wrong in Runtime Workbench application, that was my situaciĆ³n. I started to investigate what was the aplication where I could make the configuration for this issue and I found that all component setting were configured in CIM model aplication.
Fortunately, I had installed the development and quality systems and I could check how was configure the CIM model in those systems.
What happened in my production system? Nothing was configured !!!!!! All entries of Adapter Engine had dissapeared !!!!!
The solution was check the entries into development and quality system and create those entries in production system. This job is very boring but is the only solution that I know.
Now I tell us what options into the CIM model you must to create.
1. First, go to http://server:port/sld and click over CIM Instance options
image
2. Once into the application, choose this option
image
  • XI Remote Admin Service: In this part, there weren't anything option configured. We had to create AdminTool, Cache_Refresh, Runtime Check for af, Directory, Repository, and rwb SAP XIRemoteAdminServices.
  • XI Adapter Service: In this option I created all adapters for my production system, BC, CIDX, File, JDBC, JMS, Mail, MarketPlace, RFC, RNIF, SOAP, WS, XI and XIRA XIAdapterService.
  • Finally I had to configure the HTTP Service Port option creating severals services ports, Basic URLs, HTTP Service Port, Pipeline, Port for Admin Tool, JMS, MAIL, JDBC, Runtime Check af, Runtime Check Directory, Runtime Check Repository, Runtime Check rwb, SOAP, WS, XI, XIRA.

Proceed with caution when you make the relationship betwen the components, it is very important do it correctly.
When I finished the services creation into the CIM model I had to restart the SAP J2EE Engine and the Adapter Engine appeared in Runtime Workbench with green colour.
Note:
There are one note (Note 764176 - Error in XI due to inconsistent SLDcontents) where it described a similar problem with other solution.

Creating Custom Enterprise Services using ABAP and XI

Creating Custom Enterprise Services using ABAP and XI

Enterprise Services

Enterprise Services are highly-integrated Web services (based on open standards like WSDL, XML, UDDI and SOAP etc.) that are implemented by using some sort of underlying technology or vendor product. They are encapsulated with business logic representing actions against data entities that have scope across application domains and can be reassembled quickly to implement new innovative Business Services. Enterprise Services thus allows implementation of cost effective business processes in a timely manner to meet changing business requirements.

There are times where we need to enhance a standard Enterprise Services or create a Custom Enterprise Service to accommodate our business requirements. In this weblog we will have look into the methods for creating a Custom Enterprise Service using ABAP.

Creating Custom Enterprise Services in ABAP

To create services in ABAP, there are essentially two ways.

Inside-Out: We start at the back end, with an existing application to service enable any particular piece of functionality. This is called the inside out approach because we start with the implementation and move out toward the interface.

Outside-In: In outside-in approach we start with the interface and work in toward the implementation or we can say starting with modeling we move towards the implementation to create Enterprise services.

Apart from starting at different places, the inside-out and the outside-in approach also differ in other important ways. Services created from the inside-out follow the message response pattern, which is synchronous whereas Services created from the outside-in can be synchronous or asynchronous, not requiring a response from the service consumer; as a result, such services are even more loosely coupled and more flexible.

The Inside-Out approach

Creating a service from the inside out takes a piece of application functionality and makes it available as a web service. That piece of application functionality can be a BAPI, a remotely enabled function module(entities that are callable from outside the application), or a Remote Function Call (RFC).

For example, a Management person might ask for a service to retrieve Partner data but in our SAP CRM system there's already a Partner Read function . If we could simply turn that into a web service, it could solve the problem. Creating services from the inside-out provides an easy way to turn that functionality into a web service within short time frame.

So, creating services from the inside-out approach is a straightforward process, as shown in Figure -1. We start with a piece of existing functionality, starts a wizard to generate the web service, and finally we activate (in ABAP terminology) or deploy the service (if Java based). Generating the web service creates all the necessary deployment artifacts, including the Web Services Description Language (WSDL) file, automatically for us. Having created the service, we can test it using SAP's Web Service Homepage.

Figure -1. Steps involved in creating a service from the Inside-Out approach

Steps for creating a service from the Inside-Out

To create a service we can either start by service enabling a remote-enabled function module in the ABAP Function Builder using transaction SE37 or we can start service creation from transaction SE80 in the ABAP Development Workbench.

To start the wizard in SE37, by locating the function module that we want to service enable and then select Utilities -> More Utilities -> Create Web Service -> From the Function Module, as shown in Figure -2.

Figure - 2. Creating a web service based on a function module

Creating a web service based on a function module

Selecting this option starts the Web Service Creation Wizard, shown in Figure -3. The wizard provides an overview of the process on the left side of the screen. In the center of the screen, we can see the function module (ZCFT_CUSTOMER_GETDETAIL) that will be service enabled.

Figure -3. The Web Service Creation Wizard

The Web Service Creation Wizard

Pressing Continue displays the next screen, shown in Figure -4. Here we specify a name for the service definition and a description, then select the endpoint type. The endpoint type defaults to the function module since we started the wizard while viewing a function module.

Figure -4. Web Service naming

Web Service naming

We press Continue to display the screen shown in Figure -5. Here the wizard confirms which endpoint we want to service enable, defaulting to the function module where we started the wizard. The checkbox for the mapping of names (shown in German in Figure -5) allows us to map ABAP-style names to a more conventional style by removing the underscores and turning uppercase letters to lowercase. This determines how the names appear in the WSDL file.

Figure -5. Choosing an Endpoint

Choosing an Endpoint

We press Continue to display the screen shown in Figure -6. This screen configures the web service using profiles. These profiles include details such as the type of authentication the web service will use. We assign a SOAP profile, choosing either secure SOAP or the basic authorization SOAP profile.

Secure SOAP offers HTTP authentication using SAP logon tickets and X.509 certificates. The basic authorization SOAP profile is more common, with HTTP basic authentication (username and password). It is also possible to choose a profile that offers no security, which can be used for a public web service. We can change these options later also.

Selecting the checkbox releases the web service to the SOAP runtime immediately after completing the wizard. We can also release the service manually using the transaction WSCONFIG and by providing the name of the web service.

Figure -6. Choosing a Profile for Security Settings

Choosing a Profile for Security Settings

We press Continue to display the final screen in this wizard, as shown in Figure -7.

Pressing Complete on this screen creates objects for the interface and web service description, and releases the service to the SOAP runtime (as we have the checkbox “Release Service for Runtime” checked).

A Create Object Directory Entry pop up appears where we are prompted to save the service definition objects; if they are local objects, save them in the temporary directory.

We are also prompted with a Customizing Request pop up where we can specify that this service be moved from the test system to the production system, for example. We click OK to continue.

Figure -7. Completing the Web Service Wizard

Completing the Web Service Wizard

In the Object Navigator, enterprise services are found in a folder under the Function Modules folder. Opening the Enterprise Services folder displays the Service Definitions folder. In this folder, we can see the object we created.

At this point, we can improve the service definition and interface, by making some fine adjustment, in a couple of different ways. To start, we select the service definition we created and edit that object, selecting the Interface tab. We can change the names of the fields in the interface, perhaps customizing them for a partner. By default, the interface for the web service includes all the same parameters as the function module on which it is based. But in many cases, this is not optimal. Each field in the interface has an associated Exposed checkbox and deselecting it results in hiding the field. We can also customize the defaults for the fields in the interface like e.g. for a given partner we can streamline the process by filling in their name, customer number, and shipping address as defaults.

Now once we are done with the service creation we move on to the testing part. To test the created web service “Z_Customer_GetDetails_WS”, we go to a transaction called WSADMIN, which displays the Web Service Administration for SOAP Runtime screen. Testing of Service using WSADMIN is discussed at the end of this weblog.

The Outside-In approach

Outside-in development essentially involves modeling, generating stubs, and providing the implementation for the web service. Outside-in development starts at a business level, looking at critical business processes and modeling them into services that implement those processes.

From a developer's perspective, to create a service from the outside in, we start in the SAP NetWeaver XI Integration Repository. As we start developing services from the outside in, we use more of the principles of ESA, such as abstraction from programming languages, hiding the implementation details, and reusing data types where possible.

Figure -8. XI Integration Repository and its relationship to XI Integration Builder

XI Integration Repository and its relationship to XI Integration Builder

The three major steps in this process are modeling the message interface in the SAP NetWeaver XI Integration Repository, generating a proxy from that model, and finally providing the implementation.

In the XI Integration Builder, software component versions are listed down the left side of the screen as a means of structuring the content. We can browse the repository to find out what interfaces exist. If two interfaces have the same name, the system can use the associated namespace to resolve any conflicts, definitively determining which one is intended. Typically, when we are developing, we creates a new namespace to separate our services from others that might have the same name.

Modeling a message interface in the repository requires three smaller steps:

1. Create the data type, using XML schema.

2. Create the message type, an XML entity that describes the message that will be sent over the wire.

3. Create the interface that uses the message type to describe the request and the response.

Although each step involves XML, we don't have to write the XML. Instead, the XML entities are automatically generated for us based on our work in the XI Integration Builder.

In the hierarchy for the namespace we create, we'll see Interface Objects, which include all the elements needed to define a service from the outside in. We start by creating a new data type. In our example, we'll create data types for Sales Order request. First, we create the input data type, which includes two elements: the Sales_Order_No and Sales_Document_Item type, as shown in Figure -9. As we can see, we also specify the type. Also note on this screen that the elements can be defined in mixed case rather than uppercase, as is the convention with ABAP.

Figure -9. Creating the input data type

Creating the input data type

Next, we create an output data type that has several elements, including Material_Number, Material_Group, and Division etc. as shown in Figure -10.

Figure -10. Creating the output data type

Creating the output data type

Creating the message type is the next step. The message type defines the request and response messages that will be sent over the wire. We create the input message type, as shown in Figure -11. To specify the data type, we drag-and-drop the input data type from the left hand panel to the field. Similarly, we drag-and-drop the namespace to fill in that field. Creating the output message follows the same process.

Figure -11. Creating the input message type

Creating the input message type

The final step is to create the message interface. Creating a new message interface displays a screen similar to Figure -12.

This service is synchronous, so both input and output message types must be specified.

At this point, we are finished modeling the interface. Now we use the transaction SPROXY to generate the proxy. The proxy generation retrieves the WSDL description of the interface from the Integration Repository using HTTP. In order for this proxy integration to occur, the system has to be preconfigured accordingly on the SAP NetWeaver XI side (in the system landscape directory) and in the ABAP backend (using transaction SM59, RFC Destinations).

Figure -12. Creating the message interface

Creating the message interface

SPROXY displays a view of the Integration Repository that we just used for modeling the message interface. Double-clicking on the message interface we created, MI_SalesOrder_Sync, brings up a popup box where we specify that we want to generate a proxy for this service, which displays the screen shown in Figure -13.

Figure -13. Generating the proxies

Generating the proxies

Figure – 14. Proxy Structure

Proxy Structure

Generating a proxy creates all the entities we need. Save the proxy, and then activate it. The next step is to create the implementation in the backend system using the ABAP Development Workbench. The class and proxy have already been given ABAP names; all that remains is to implement the class itself in the ABAP system. Double-clicking the class name displays the method of the class in the Class Builder. Double-clicking the method allows us to insert the implementation code. The developer can also use ABAP Development Workbench using transaction SE80 to implement the class and insert the code for the method, as shown in Figure -15.

Figure -15. Inserting the implementation

Inserting the implementation

Having created this functionality from the outside in the next step is to enable it as a web service using the Web Service Creation Wizard (Figure -16).

Figure -16. Exposing it as a Web Service

Exposing it as a Web Service

Running the wizard is essentially the same process described earlier, with one difference; in this case, we choose Message Interface as the endpoint instead of Function Module (Figure -17) and then in the “Choose Endpoint” step (Figure 18) we put the ABAP Name of our Message Interface as generated by SPROXY transaction.

Figure -17. Chose Message Interface

Chose Message Interface

Figure -18. Provide Message Interface name as Generated by SProxy

Provide Message Interface name as Generated by SProxy

So to sum up all these steps, first we model the interface in the Integration Repository, generate a proxy from that, insert the implementation for the class, and finally service enable the newly created XI endpoint using the Web Service Creation Wizard. In the new version of SAP NetWeaver PI, this final step is no longer necessary.

Testing Service using WSADMIN

As discussed earlier to test the web services we use the transaction WSADMIN. It displays the Web Service Homepage, which lists all the available services. We select the service we created and click the Web Service Homepage icon (as displayed in Figure 19) or press “Ctrl+F8”. A “Settings for WSDL Generation” pop up appears, asking for a WSDL style; we choose Document Style.

Figure -19. Web Service Administration (WSADMIN)

Web Service Administration (WSADMIN)

The Web Service Homepage appears (Figure-20). We authenticate with username and password, and then the overview page for the web service will appear.

Figure -20. Web Service Homepage

Web Service Homepage

From the Overview page for the Web Service (Figure-21), we can see the URL for the WSDL document, review the features assigned to the web service, and see the service's Universal Description, Discovery, and Integration (UDDI) status.

Figure -21. Overview page for the Web Service

Overview page for the Web Service

We press the Test button to display the test page, which lists the operations for the web service (in this case, there is only one as shown in Figure -22); we select the operation and click Test. The interface appears, as shown in Figure -23.

Figure -22. Test page for the Web Service

Test page for the Web Service

Figure -23. Web Service Input Interface

Web Service Input Interface

We fill in the fields and click Send. The request is sent to the SOAP runtime and the screen displays both the request and the response, as shown in Figure -24. The call goes to SOAP via HTTP and the appropriate response is returned.

Figure -24. The results from testing the web service

The results from testing the web service

This weblog shows how you can easily create custom enterprise services using ABAP and XI (or PI 7.0). I hope this will help some of you and provide all the relevant information at one place.

How to append Carriage Return in the end of each tag of xml file

How to append Carriage Return in the end of each tag of xml file

Purpose

Purpose of this web log is to give a solution to the above mentioned title and also this is a frequently occurring question in SDN XI forum.

Introduction
This is a frequently occurring question these days in SDN XI forums, How to append a carriage return after some place and after end of tag of xml or some string. So I tried to give solution in generic way b y writing a simple UDF.

Here is the input structure I am using and treating this as and input to the UDF as xmlString.

ToveJaniReminderDon't forget me this weekend!

Output we want

Tove

Jani

Reminder

Don't forget me this weekend!



UDF for this

public String AddNewLineinEndofXMLTag(String xmlString,Container container){

//write your code here
String res = "";
int flag = 0;
for(int i = 0;i
{
if(xmlString.charAt =='<')
{
flag = 1;
res = res + xmlString.charAt ;
}
else
{
if(xmlString.charAt =='>')
{
flag = 0;
res = res +xmlString.charAt + "\n";
}
else
{
res = res +xmlString.charAt ;
}
}
}

return res;

}

I hope, it will help many people to solve their purpose. You can also customized it and use it with some other requirements as well as with similar kind of scenarios.


Different ways to keep your Interface from processing duplicate files

Different ways to keep your Interface from processing duplicate files

One of the most repeated requirements concerned with interfaces implementing Source File Adapters is to some how keep the interfaces from processing duplicate files.

Recently we faced a similar requirement at our project. Our goal was to implement a solution that would be generic and easy to implement. Below are a few of the best solutions that we identified. These solutions can be implemented independently or certain aspects of each solution can be picked and merged together to provide a *better* solution.

The author is fully aware that there are other ways to do this .

Solution 1: The good old Adapter Module

A search on SDN threw up an excellent article by Sandeep Jaiswal.

To implement Sandeep's approach, we had to make some changes to suit our requirements. We decided to archive the file instead of deleting the contents of the file using the ArchiveFile() function (as opposed to DeleteFile()):

public void ArchiveFile(String FileName, String ArchiveLocation)throws Exception {
try {

File myFile = new File(FileName);

File archiveDirectory = new File(ArchiveLocation);
myFile.renameTo(new File(archiveDirectory, (myFile.getName() + "_duplicate_" + new Timestamp(new Date().getTime()).toString().replace(':', '-'))));
}
catch (Exception e){
throw e;
}
}

This will only work when the file system is NFS (not FTP). The archive location will be received as a parameter to the adapter module :

From an XI architectural perspective, it is correct for us to try to stop the processing of the duplicate early in the Adapter Engine (which is what this implementaion does).

This adapter module was easily the most generic/easy to use solution to the duplicate file problem. But if I had to be very critical I would have to point out the following *flaws* :

1) It is not a good practice to use File IO from within the Adapter module. As a matter of fact, it is not a good practice to use File IO from any Java Bean. Using Java IO from anywhere within XI (adapter engine/integration engine) can be a serious performance hit. We will come back to this point later in the article.

2) The error/alert messages that are generated when the duplicate file is encountered aren't as expected. i.e. We never actually see the error that is thrown in the code :

throw new ModuleException(fileName.trim() + " has already been processed by SAP PI");

Instead we see the uninformative:


In our effort to be perfect we looked for alternatives.

Solution 2 : Why not in Message Mapping?

An UDF can be implemented in message mapping to check if the file has been processed. The function DuplicateFileCheck() will accept the database file name (file which will hold the list of processed file names) as a parameter. If the database file does not already exist, it will be created :

String processedFileDatabase = processedFile[0];
String sourceFileName;

DynamicConfiguration attrib = (DynamicConfiguration)container.getTransformationParameters().get(StreamTransformationConstants.DYNAMIC_CONFIGURATION);
DynamicConfigurationKey fileKey = DynamicConfigurationKey.create("http:/"+"/sap.com/xi/XI/System/File","FileName");

attrib.put(fileKey,attrib.get(fileKey));
sourceFileName = attrib.get(fileKey);


File fileDB=new File(processedFileDatabase);

if (!(fileDB.exists() && fileDB.canWrite() && fileDB.canRead())){
fileDB.createNewFile();
}

Vector fileNameList = new Vector();
BufferedReader br = null;
br = new BufferedReader(new FileReader(processedFileDatabase));

String name = new String();
//loop and read a line from the file as long as we dont get null
while ((name = br.readLine()) != null)
//add the read word to the wordList
fileNameList.add(name);
br.close();

boolean fileAlreadyProcessed = fileNameList.contains(sourceFileName);

if (!fileAlreadyProcessed) {
Writer output = new BufferedWriter(new FileWriter(new File(processedFileDatabase),true));
output.write(sourceFileName + "\r\n");
output.flush();
output.close();
}

result.addValue("" + !fileAlreadyProcessed);

Implementing the code as listed above re-introduces Java IO and hence the performance hit described in solution 1. An alternative to using the Java IO would be to access a table through the dynamic configuration class. The table will hold the list of all processed files (instead of the file).

In graphical message mapping, only the target root node should be mapped using the DuplicateFileCheck() function as follows:

This implementation gets the job done for *most* of our interfaces. The problem is that this approach requires a Message Mapping to exist, which was not the case for all interfaces. For example, we have a couple interfaces which are only concerned with moving *.zip files from one location to another. Another problem with approach is we cannot save or keep a copy of the duplicate source files since the adapter engine would have already archived/deleted it.

Now before we make XI conservatives cry anymore (yes.. we know that this doesn't belong in the integration engine).. We'll move quickly on to the third solution.

Solution 3 : The flexible Receiver Determination

The third approach requires both an adapter module implementation and some changes in the configuration scenario. Within the adapter module a check will be done to see if the source file is duplicate or not.. if the file is duplicate a new XML Payload will be created for the message which will hold the following :


The file mysourcefile.txt has already been processed by SAP PI

The code to build the new Payload is given below :

XMLPayload xmlpayload = msg.getDocument();

if (flag == true) {
Audit.addAuditLogEntry(
amk,
AuditLogStatus.ERROR,
"NewDuplicateFileCheck:File"+ fileName+ " has been already processed by SAP PI");
DocumentBuilderFactory factory;
factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();

Document document=builder.newDocument();

Element rootElement = document.createElement("Root");
Element childElement = document.createElement("DuplicateFlag");
childElement.appendChild(document.createTextNode("File "+ fileName.trim() + " has already been processed by SAP PI."));

rootElement.appendChild(childElement);
document.appendChild(rootElement);

TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer transformer = tfactory.newTransformer();
Source src = new DOMSource(document); // DOM source is our DOM doc
ByteArrayOutputStream myBytes = new ByteArrayOutputStream();
Result dest = new StreamResult(myBytes);

transformer.transform(src,dest);

byte[] docContent = myBytes.toByteArray();

if(docContent != null){
xmlpayload.setContent(docContent);
msg.setDocument(xmlpayload);
inputModuleData.setPrincipalData(msg);
}


//throw new ModuleException(fileName + "is already processed");
}




Note that we will no longer be throwing the Module Exception from within the adapter module.

In the receiver determination we will check for the DuplicateFlag node using Xpath Expressions and we will route the message to different receivers based on the existence of the flag:

We configure a mail adapter which implements the MessageTransformBean as follows :


This results in a nice e-mail message displaying the name of the duplicate file that was already processed :

The drawback with this approach is that once again we cannot control how XI handles the duplicate file (it will be either archived or deleted based on the sender adapter settings).


Solution 4 : Enhanced Receiver Determination - In theory only

Unfortunately we do not have code or screenshots for this solution.

This approach involves using the Dynamic Configuration class to maintain/check a table holding a list of all files that have been processed by the interface. Based on whether the file is duplicate or not a different receiver is identified (similar to solution 3).

Again, since this will be done through enhanced receiver determination, we cannot control what the sender adapter does (has already done) with the duplicate file.


SAP Developer Network SAP Weblogs: SAP Process Integration (PI)