分类 SAP 下的文章

SAP Gateway在S4/HANA时代的ABAP开发模型中有着重要的地位。SAP Gateway是什么?它对ABAP开发有怎样的影响?可以为我们提供哪些方便?这篇译文将浅要地讨论这些话题。

SAP NetWeaver Gateway是一项基于市场标准的技术,它提供了简单的方式以连接SAP软件与设备、环境和平台。这个框架允许实现创新的、以人为本的解决方案,为SAP的商务软件带来了新体验:比如社交与协作环境、手机和笔记本设备以及富internet应用。

简而言之,NetWeaver Gateway是一个ABAP组件集,它附加在你已有的SAP ERP系统上,并提供了简单的、以人为本的工具来访问你的业务信息,并且降低了消费数据所需要的知识门槛,使得使用者不需要了解SAP系统内部的工作机制。Gateway提供了易用的、定义良好的API,提供了入口以访问SAP系统中富有价值的业务数据和功能。

本文链接:http://www.cnblogs.com/hhelibeb/p/7600998.html

原文链接:A simple overview on SAP Netweaver Gateway

1.1 兼容性

  • OPEN - 任何设备,任何体验,任何平台
  • PEOPLE - 优化用户交互场景
  • TIMELESS - 不分裂,任何SAP Business Suite版本
  • DEVELOPERS - 简单的API,不需要SAP知识,任何工具(都可以)
  • STANDARDS - 基于REST,ATOM/OData

SAP NetWeaver Gateway提供SAP应用与任何语言或模型的连接能力,借助REST services和OData/ATOM协议,实现这种连接不需要SAP方面的知识。

1.2 REST & OData

REST: 表现层状态转化(Representational State Transfer)是分布式系统的软件架构风格,例如万维网。凭借其更为简单的风格,REST已经逐渐代替了其它设计模型如SOAP。REST使用标准的GET, PUT, POST & DELETE方法和HTTP协议已有的特性。REST的主要目标包含组件交互的可测量性、接口的通用性、组件部署的独立性、中间组件减小延迟、增强安全性和封装遗留系统(legacy systems)等。

OData: 开放数据协议(Open Data Protocol)是一个用于查询和更新数据的开放的互联网协议。该协议允许消费者经由HTTP协议向数据源查询,并以Atom、JSON或者plain XML等格式返回数据,可以对数据编码、排序或者过滤。

1.3 关键优势

  • REST允许你的系统由此降低消费数据的门槛,因为借助它,无需SAP系统的专业知识也能消费其中的业务数据和功能。
  • 通过一个简单易用、非专有的接口,隐藏SAP系统背后的技术复杂性。
  • 让你的SAP业务数据和功能可以从符合以下特性的任何设备访问:
    • 通过HTTP(S)协议通信。
    • 理解OData消息
  • 提供服务生成工具(Service Provisioning tools),允许为已存在的ABAP功能快速生成REST实现。
  • 为主流IDE提供插件,比如Eclipse,Visual Studio和Xcode.

2.0 使用开源工具访问SAP业务数据

通过SAP NetWeaver Gateway消费数据只需要用HTTP(S)请求即可。这不需要使用任何SAP先前的软件或协议。应用开发者通过SAP NetWeaver Gateway接口消费数据也不需要有ABAP编程经验,甚至完全不需要懂得SAP内部的工作原理。

使用通常的开发工具,比如微软的.NET和苹果的XCode,或者开源语言,比如Ruby和PHP,我们可以轻松地通过消费SAP服务器提供的OData消息为SAP业务数据和功能创建用户界面。为了让OData的消费处理变得更加简单,SAP发布了多个版本的Gateway Consumption Tool。这个工具现在可以在Visual Studio和Xcode中使用,它可以生成OData代理对象。另外,它也可以将已生成的代理对象包装并生成基本应用。

微软的OData协议基于Atom发布协议(Atom Publishing Protocol),相应地,该协议基于Atom 联合格式(Atom Syndication Format)。SAP利用了OData内建的标准扩展特性来提供自己的注解(Annotations)。OData数据格式和SAP注解的结合使得SAP业务信息同时实现了自描述和高可读性。这两个特性各自地降低了SAP业务信息和功能的获取门槛,使它们更易于为其它外部设备上的业务应用所利用。

3.0 聚焦SAP NetWeaver Gateway

SAP NetWeaver Gateway接口的焦点在于它的REST能力允许非SAP系统应用轻松地消费SAP的数据与功能。它们包括:

  • 任何外部应用,比如微软Office应用可以通过.NET(甚至VBA)进行消费。
  • 桌面机器可以通过由PHP、Java或Ruby等后台支持的Web应用进行消费。
  • 移动端原生应用,比如iPad/iPhone或者安卓设备或者黑莓设备。
  • 嵌入式设备,比如制造业机器人或者卫星导航系统中的路线规划软件。
  • 任何你可以想到的可编程的、支持HTTP(S)协议的业务场景。

SAP NetWeaver Gateway接口可以用于任何支持HTTP(S)的可编程设备。为提供这一兼容性,它通过以下手段隐藏了系统内存在的复杂性:

协议适配:OData成为了向/从SAP系统供应/消费业务数据的唯一协议。

服务适配:不同类型和版本的SAP系统现在表现为单一的、集成的业务信息库。

4.0 开发过程

SAP NetWeaver Gateway软件由多种服务生成工具提供,它可以生成必要的源代码,以启动你的外部应用的开发。这些工具可以用于连接多种常用IDE,比如Eclipse,Visual Studio和Xcode。对这三个IDE,存在可用的扩展,所以开发者无需具备SAP知识。

SAP NetWeaver Gateway可以根据已有的BAPI、RFC和ABAP Dynpro屏幕创建新的Gateway对象。在生成Gateway对象时,生成工具使用起来和RFC生成器、BOR生成器和屏幕生成器一样。我们也可以通过Gateway附加组件来构建自定义Gateway对象,它会提供OData通道。这是一系列ABAP类和接口,可以用于在SAP系统中开发你自己的Gateway模型对象。需要在SAP NetWeaver Gateway中注册它们,这样就可以通过RESTful服务在外部访问。

可以通过以下图表轻松理解这些开发过程中的步骤:

5.0 总结

SAP NetWeaver Gateway不是用于由标准用户使用的事务型应用的通道,也不会替代现有的中间件如SAP NetWeaver PI。此外,SAP NetWeaver Gateway的目标也不是A2A或B2B场景。相反,SAP NetWeaver Gateway是一扇通往SAP业务数据和功能的门。它的目标受众是被称为临时平台用户(Occasional Platform Users ,OPU)的群体。这些人需要通过易于消费的方式实现特定的(ad hoc)SAP数据和功能访问。

动机

现在大家都知道单元测试对我们代码的好处。并且我们都承认它是开发过程中不可或缺的一部分。但是在把代码切换到数据库的模式下的时候,我们被粗暴地打回了软件测试的黑暗年代...我们现在面临着逻辑下推到ABAP CDS entities后,代码要如何测试的难题。

CDS Test Double Framework允许开发者们通过众所周知的ABAP Unit Test Framework自动化地测试CDS entities。

本文链接:http://www.cnblogs.com/hhelibeb/p/7376232.html

英文原文:Introduction to CDS Test Double Framework – How to write unit tests for ABAP CDS Entities?

挑战

因为CDS entity中的逻辑运行在下层的数据库中(独立于abap runtime),使用传统的ABAP依赖注入解决方案以实现测试成为了不可能的事情。entity的依赖组件需要在数据库中加上测试替身,并且我们必须确保CDS entity测试的时候数据库引擎调用/执行这些测试替身(double)。

为了可以在CDS entity under test (CUT)中可控地测试逻辑,我们需要通过测试替身注射测试专用数据。这意味着必须将测试数据插入到测试替身中,这样数据可以在CUT执行时被测试替身们返回。对于在ABAP CDS上下文中有着固有的只读属性的依赖组件(比如数据库视图和数据库函数),这是一项特别的挑战。

本文中重要的缩写:

CUT = CDS entity Under Test

DOC = Depended-On Component

CDS Test Double Framework

CDS Test Double Framework处理了以上的挑战,并且可以实现CDS entities测试的自动化:

  1. 在相同的Database Schema中为每个依赖组件创建临时的可更新测试替身
    1. 复制依赖组件表,但不复制任何数据。不复制依赖数据库表的主键约束。这允许你轻松地插入测试数据,而不用担心数据的完整性。相似的,数据库索引也不会被复制。
    2. 为依赖数据库视图创建数据库表。这些表有着和依赖数据库视图相同的结构。
    3. 依赖数据库functions(由带有参数的依赖CDS视图和依赖表function产生)会被复制,并且function的测试替身实现会被修改为允许插入需要的测试数据。
  2. 在相同的Database Schema创建一个CDS entity under test(CUT)的临时副本。从各种意义上来看,这个副本是为CUT服务的。在原始的CDS entity中实现的逻辑在副本中同样存在,但是依赖组件被替换为了相应的测试替身。测试替身是由我们的CDS Test Double Framework所创建的。

测试什么?

单元测试应当专注于由一个给定视图实现的有价值的功能定义。不是所有的CDS视图都需要一个单元测试。在实现单元测试之前,建议辨别出entity中与测试有关的方面。

通常,需要为某些包含了代码下推的方法的entity进行单元测试。潜在的测试候选者包括:

Calculations and/or filters, conversions, conditional expressions 比如 CASE…THEN…ELSE or COALESCE, type changing CAST operations, cardinality changes or checks against NULL values,  JOIN behavior, complex where conditions 等.

单元测试不应用于测试那些更适用于静态检查、集成测试等技术的CDS entities属性。如果不能从单元测试中获取任何价值的话,也不应进行它,比如对于那些简单的CDS投影视图。

怎样使用CDS Test Double Framework写单元测试?

在下一部分,我们会通过被广泛应用的ABAP Unit Test Framework为以下的CDS视图创建单元测试。

@AbapCatalog.sqlViewName: 'zSo_Items_By_1'
@EndUserText.label: 'Aggregations/functions in SELECT list'
@AbapCatalog.compiler.compareFilter: true
define
viewSalesorder_Items_By_TaxRateas select fromCdsFrwk_Sales_Order_Item
association
[1] to snwd_so as _sales_order on so_guid =_sales_order.node_key
{
so_guid,
coalesce ( _sales_order.so_id, '9999999999' ) asso_id,
currency_code,
sum( gross_amount ) assum_gross_amount,
tax_rate,
_sales_order
}
group byso_guid,
_sales_order.so_id,
currency_code,
tax_rate

 

SAP标准的REST adapter有着XML/JSON转换的功能,它很有用,因为一方面SAP PI/PO内部以XML格式处理数据,而另一方面,在处理REST架构风格的时候,JSON才是事实上的格式。

然而,观察下网上有关REST Adapter的相关问题,可以得出一个结论:XML消息处理后生成的JSON输出并非总是正确的,有时候它会把人引入歧途。SAP积极地增强了REST Adapter的各方面功能——定制化和特性丰富的JSON处理就是其中一个重点领域。许多相关特性已经在记录在SAP Help的文档中。但是其中的一项相当强大、灵活的功能——名为“增强XML/JSON转换”的功能,却只是简单地在SAP Note 2175218中提及。在本文中,我将阐述这个功能的用法,以及提供有效参数化方法的细节。

在内部,REST adapter使用了第三方的Jettison以实现JSON处理。在标准配置中,REST adapter依赖于Jettison处理器默认的转换逻辑,它不会考虑或关联相应的消息类型中定义的有效元素属性,而是有自己的优化和类型机制,该机制基于所要处理的XML文档的元素的值的本来性质,而非消息的XSD schema。这样一来的结果是,有时转换会导致不合需求的输出。以下是两个通常的例子:

  • 如果一个XML元素定义为数组,但是在被转换的XML有效数据中只包含一行,Jettison处理器将可能会将其转换为非数组类型
  • 如果一个XML元素定义为字符串,但是在被转换的XML有效数据中只有数字型的值,Jettison处理器将可能会将其转换为整数类型

在某些情况下,不合适的类型转换对程序而言是不可接受的——这也是增强XML/JSON转换可以帮助我们解决的问题。

SAP Note 2175218介绍了增强XML/JSON转换背后的一个想法,它是有关JSON处理器如何对待特别的XML元素的明确的描述。让我们基于一个练习例子来测验这个功能:

 

下面是一个消息类型的定义,它用于同步场景的返回消息,我们在其中使用了REST sender channel。如你所见,它包含了多种类型的元素,包含一个数组:

 

 XML格式的示例回复消息是这样的:

 

使用REST sender channel的标准配置,将上面的XML消息格式化后的JSON相应消息是这样的:

 

可以注意到,某些元素类型被错误的解释了,比如:

  • 元素“ID”没有被视为字符串,而是数字——Jettison处理器将它作为数字对待,因为元素的值只包含数字类型的字符;
  • 元素“Properties”没有被视为数组,Jettison处理器将它作为嵌套结构中的非数组对象,因为这个元素只包含“Property”的一个子实体(没有其它兄弟元素)。

让我们通过增强XML/JSON转换来修复它。在REST sender channel中,增强XML/JSON转换的参数化信息存储在表 “Custom XML/JSON Conversion Rules”中。下面是针对之前高亮的有问题的类型和转换不匹配的配置。

 

 

在再次执行接口后,检查被格式化为JSON的响应消息,可以观察到,现在产生了正确的JSON输出:

 

我在官方材料中没有看到有关于参数化的细节,所以让我来总结下增强XML/JSON转换中可以使用的可接受的和有效值,以及有关它们的使用的解释性说明。内容在下表:

字段

描述

有效值

XML 命名空间

XML元素的命名空间

 

前缀

XML元素命名空间前缀

 

名称

XML元素名

 

类型

XML元素类型。

以下类型是当前支持的:

String, Integer, Decimal, Boolean.

只要它是有效值列表中提到的值之一,就不会区分类型值的符号。

如果没有指定值,不会应用指定的XML/JSON转换指令,而是会执行默认的Jettison处理器逻辑。

String type

string

xs:string

xsd:string

Integer type

int

integer

xs:integer

xsd:integer

Decimal type

decimal

numeric

float

xs:decimal

xsd:decimal

Boolean type

bool

boolean

xs:boolean

xsd:boolean

数组类型

XML元素是否是数组的指示符。

只要它是有效值列表中提到的值之一,就不会区分类型值的符号。

如果没有指定值,数组指示符默认为false。

如果是数组:

1

true

yes

如果不是数组:

0

false

no

默认值

在XML/JSON转换失败的情况下会赋给JSON元素的值。

 

例如,在上面给的demo中,元素“Quantity”的值会被作为整数处理。如果原始值不能转换为整数(比如含有字母),JSON输出会得到一个默认值。在该情况下,这个值是“0”。

需要注意的是,对于默认值而言,系统不会针对在“TYPE”中指定的类型进行元素类型检查——它会被当作字符串。在这种方式下,比如,你可以指定默认值“Invalid value”给“Quantity”。系统不会提示错误,无论是在communication channel激活的时候还是REST adapter运行期间处理相关消息的时候,即便默认值和元素类型(整型)完全不匹配。记住这点,应当注意设置默认值时要保持其类型的一致性。

Any value.

下面的值有点特别:

“null”

(带引号) – 被解释为字符串“null”

null

(无引号) – 被解释为null

“”

(只有引号 – 被解释为空字符串

 

本文链接:http://www.cnblogs.com/hhelibeb/p/7395567.html

英文原文:REST Adapter in PI/PO: Enhanced XML/JSON Conversion

参考阅读:PI REST Adapter – JSON to XML conversion

       JSONTransformBean Part 1: Converting JSON content to XML

 

在长期的停滞后,Open SQL的发展终于从沉睡中醒来。从ABAP 7.40开始,SAP推进了某些关键的改变,以尽可能地包含SQL92中的特性,并提供与ABAP CDS中的DDL里面的SELECT一样的功能给Open SQL。为了实现这些目标,ABAP运行时环境中引入了一个新的SQL parser作为Open SQL的新基础。结果就是,Open SQL现在可以在ABAP中扮演一些和以往不同的角色了。

虽然在7.40之前,Open SQL更多地被视为ABAP语言本身的一部分,但在同时,SQL关键字变得越来越介词化了。关于这点,主要的体现之一便是有关宿主变量的新规则。在7.40之前,你可以像在其它ABAP语句中使用ABAP变量那样在Open SQL中使用它们。实际上,这种自由阻止了更高效的开发。Open SQL语句在被转换为native SQL之后才会在数据库中运行。为了在WHERE条件中实现比简单比较更为复杂的东西,Open SQL parser必须能清晰的区分运算符两端的东西到底是ABAP变量、还是数据库内容,从而发送相应的内容给数据库。为了完成这一任务,Open SQL中的ABAP变量因此成为了完全的宿主变量host variables)。就像ABAP变量在native SQL中的成分一样(EXEC SQL)。你可以(而且应当)在Open SQL中的ABAP 宿主变量前加上转义符@实际上,只有这样做了,你才能使用ABAP 7.40版本之后的全部Open SQL新特性。Open SQL中引入的其它的基础修改也是为了让其更加适应未来,比如逗号分隔、以及将SELECT语句的INTO附加项放在authentic SQL子句的后面。(译注:authentic是什么意思没看懂,不过这句话的意思应当是指INTO语句不应是SQL本身的一部分,所以要放到后面以示区分)

 

这些方法带来的第一个好处,已经在ABAP 7.40版本中放出,包括可以在不同操作数位置使用的SQL表达式,以及内联声明的可能性。在ABAP 7.50中,Open SQL依然在发展着,本文将介绍一些新特性(未来还会有更多)。

 

本文链接:http://www.cnblogs.com/hhelibeb/p/7135899.html

原文标题:ABAP News for Release 7.50 – Host and Other Expressions in Open SQL

宿主表达式

在大多数可以放置宿主变量的地方,包含7.40版本以来的SQL表达式的操作数位置或者写SQL语句的工作区,现在可以通过如下方式放置宿主表达式(host expression):

… @( abap_expression ) …

宿主表达式abap_expression可以是任何ABAP表达式,可以是一个构造器表达式、表表达式、算术表达式、字符串表达式、bit表达式、内建函数、函数性的方法、或者是方法,它通过括号()包围起来,并且要加上前缀@。Open SQL中的宿主表达式从左到右计算,并且它们的结果会作为宿主变量传递给数据库。事实上,你可以将宿主表达式视为通过ABAP表达式为ABAP帮助变量赋值的简写。以下例子演示了一个表表达式,表达式从内表carriers中读取值,并放置在where条件右端:

SELECTcarrid, connid, cityfrom, citytoFROMspfliWHERE carrid =@( VALUE spfli-carrid( carriers[ KEY name
carrname
= name ]-carrid
OPTIONAL ) )
INTO TABLE @DATA(result)

 

在ABAP中,存在着一条法则:名字不一定代表实际规则(具体可看最近的相关讨论)。

但是如你们所知的,存在着一个很好的例外: 所有涉及到使用CORRESPONDING为结构赋值的关键字的语法形式(偶然地)有着相同的名字..

  • 在ABAP 7.40之前,主要有用MOVE-CORRESPONDING来复制结构组件、Open SQL的SELECT的CORRESPONDING附加字段,以及某些过时的计算语句等。
  • 在ABAP 7.40中,MOVE-CORRESPONDING可以用于操纵带有结构的内表。并且7.40引入了一个新的构造器操作符CORRESPONDING,它允许显式地将结构的组件映射到不同名字的组件上。

还缺了点什么?答案是动态的映射!这个特性在ABAP 7.50中得到了引入。

新的系统类  CL_ABAP_CORRESPONDING允许你适用动态指定的映射规则为结构或内表的组件赋值。

映射规则需要创建在一个映射表中,然后传递给映射对象。

例子如下:

DATA(mapper) =cl_abap_corresponding=>create(

source
=struct1

destination
=struct2

mapping
= VALUE cl_abap_corresponding=>mapping_table(

( level
= 0kind= cl_abap_corresponding=>mapping_component

srcname
=‘…’

dstname
=‘…’ )

( level
= 0kind= cl_abap_corresponding=>mapping_component

srcname
=‘…’

dstname
=‘…’ )

( level
= 0kind= cl_abap_corresponding=>mapping_component

srcname
=‘…’

dstname
= ‘…’ ) ) ).