290.14. SAP 示例
290.14.1. 示例 1:从 SAP 读取数据
概述
本例展示了从 SAP 读取 FlightCustomer 业务对象数据的路由。路由调用 FlightCustomer BAPI 方法 BAPI_FLCUST_GETLIST,使用 SAP 同步 RFC 目标端点来检索数据。
用于路由的 Java DSL
示例路由的 Java DSL 如下:
from("direct:getFlightCustomerInfo")
.to("bean:createFlightCustomerGetListRequest")
.to("sap-srfc-destination:nplDest:BAPI_FLCUST_GETLIST")
.to("bean:returnFlightCustomerInfo");路由的 XML DSL
同一路由的 Spring DSL 如下:
<route>
<from uri="direct:getFlightCustomerInfo"/>
<to uri="bean:createFlightCustomerGetListRequest"/>
<to uri="sap-srfc-destination:nplDest:BAPI_FLCUST_GETLIST"/>
<to uri="bean:returnFlightCustomerInfo"/>
</route>createFlightCustomerGetListRequest bean
createFlightCustomerGetListRequest bean 负责在后续 SAP 端点的 RFC 调用中使用的交换方法中构建 SAP 请求对象。以下代码片段演示了构建请求对象的操作序列:
public void create(Exchange exchange) throws Exception {
// Get SAP Endpoint to be called from context.
SapSynchronousRfcDestinationEndpoint endpoint =
exchange.getContext().getEndpoint("sap-srfc-destination:nplDest:BAPI_FLCUST_GETLIST",
SapSynchronousRfcDestinationEndpoint.class);
// Retrieve bean from message containing Flight Customer name to
// look up.
BookFlightRequest bookFlightRequest =
exchange.getIn().getBody(BookFlightRequest.class);
// Create SAP Request object from target endpoint.
Structure request = endpoint.getRequest();
// Add Customer Name to request if set
if (bookFlightRequest.getCustomerName() != null &&
bookFlightRequest.getCustomerName().length() > 0) {
request.put("CUSTOMER_NAME",
bookFlightRequest.getCustomerName());
}
} else {
throw new Exception("No Customer Name");
}
// Put request object into body of exchange message.
exchange.getIn().setBody(request);
}returnFlightCustomerInfo bean
returnFlightCustomerInfo bean 负责从 SAP 响应对象提取数据,在其从以前的 SAP 端点接收的交换方法中提取数据。以下代码片段演示了从响应对象中提取数据的操作序列:
public void createFlightCustomerInfo(Exchange exchange) throws Exception {
// Retrieve SAP response object from body of exchange message.
Structure flightCustomerGetListResponse =
exchange.getIn().getBody(Structure.class);
if (flightCustomerGetListResponse == null) {
throw new Exception("No Flight Customer Get List Response");
}
// Check BAPI return parameter for errors
@SuppressWarnings("unchecked")
Table<Structure> bapiReturn =
flightCustomerGetListResponse.get("RETURN", Table.class);
Structure bapiReturnEntry = bapiReturn.get(0);
if (bapiReturnEntry.get("TYPE", String.class) != "S") {
String message = bapiReturnEntry.get("MESSAGE", String.class);
throw new Exception("BAPI call failed: " + message);
}
// Get customer list table from response object.
@SuppressWarnings("unchecked")
Table<? extends Structure> customerList =
flightCustomerGetListResponse.get("CUSTOMER_LIST", Table.class);
if (customerList == null || customerList.size() == 0) {
throw new Exception("No Customer Info.");
}
// Get Flight Customer data from first row of table.
Structure customer = customerList.get(0);
// Create bean to hold Flight Customer data.
FlightCustomerInfo flightCustomerInfo = new FlightCustomerInfo();
// Get customer id from Flight Customer data and add to bean.
String customerId = customer.get("CUSTOMERID", String.class);
if (customerId != null) {
flightCustomerInfo.setCustomerNumber(customerId);
}
...
// Put bean into body of exchange message.
exchange.getIn().setHeader("flightCustomerInfo", flightCustomerInfo);
}290.14.2. 示例 2:将数据写入 SAP
概述
本例演示了在 SAP 中创建 FlightTrip 业务对象实例的路由。路由调用 FlightTrip BAPI 方法 BAPI_FLTRIP_CREATE,使用目标端点来创建对象。
用于路由的 Java DSL
示例路由的 Java DSL 如下:
from("direct:createFlightTrip")
.to("bean:createFlightTripRequest")
.to("sap-srfc-destination:nplDest:BAPI_FLTRIP_CREATE?transacted=true")
.to("bean:returnFlightTripResponse");路由的 XML DSL
同一路由的 Spring DSL 如下:
<route>
<from uri="direct:createFlightTrip"/>
<to uri="bean:createFlightTripRequest"/>
<to uri="sap-srfc-destination:nplDest:BAPI_FLTRIP_CREATE?transacted=true"/>
<to uri="bean:returnFlightTripResponse"/>
</route>事务支持
SAP 端点的 URL 将 transacted 选项设置为 true。如 第 290.11 节 “事务支持” 所述,当启用此选项时,端点可确保在调用 RFC 调用前启动 SAP 事务会话。由于此端点的 RFC 在 SAP 中创建新数据,因此此选项需要在 SAP 中永久进行路由更改。
填充请求参数
createFlightTripRequest 和 returnFlightTripResponse beans 负责将请求参数填充到 SAP 请求中,并根据上例中所示的相同操作序列来提取响应参数。
290.14.3. 示例 3:处理 SAP 的请求
概述
本例演示了处理从 SAP 请求到 BOOK_FLIGHT RFC (由路由实施)的路由。此外,它演示了组件的 XML 序列化支持,使用 JAXB 到 unmarshal 和 marshal SAP 请求对象,并将对象响应到自定义 Bean。
此路由代表旅行代理 FlightCustomer 创建 FlightTrip 业务对象。路由首先将 SAP 服务器端点收到的 SAP 请求对象加载到自定义 JAXB bean 中。然后,这个自定义 Bean 在交换中被多播到三个子路由,它会收集创建动态行程所需的旅行代理、flight 连接和乘客信息。最后的子路由会在 SAP 中创建 flight trip 对象,如上例中所示。最终的子路由还会创建并返回自定义 JAXB bean,该 Bean 会被 marshaled 到 SAP 响应对象,并由服务器端点返回。
用于路由的 Java DSL
示例路由的 Java DSL 如下:
DataFormat jaxb = new JaxbDataFormat("org.fusesource.sap.example.jaxb");
from("sap-srfc-server:nplserver:BOOK_FLIGHT")
.unmarshal(jaxb)
.multicast()
.to("direct:getFlightConnectionInfo",
"direct:getFlightCustomerInfo",
"direct:getPassengerInfo")
.end()
.to("direct:createFlightTrip")
.marshal(jaxb);路由的 XML DSL
同一路由的 XML DSL 如下:
<route>
<from uri="sap-srfc-server:nplserver:BOOK_FLIGHT"/>
<unmarshal>
<jaxb contextPath="org.fusesource.sap.example.jaxb"/>
</unmarshal>
<multicast>
<to uri="direct:getFlightConnectionInfo"/>
<to uri="direct:getFlightCustomerInfo"/>
<to uri="direct:getPassengerInfo"/>
</multicast>
<to uri="direct:createFlightTrip"/>
<marshal>
<jaxb contextPath="org.fusesource.sap.example.jaxb"/>
</marshal>
</route>BookFlightRequest bean
以下列表演示了一个 JAXB bean,它来自 SAP BOOK_FLIGHT 请求对象的序列化形式:
@XmlRootElement(name="Request", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT")
@XmlAccessorType(XmlAccessType.FIELD)
public class BookFlightRequest {
@XmlAttribute(name="CUSTNAME")
private String customerName;
@XmlAttribute(name="FLIGHTDATE")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date flightDate;
@XmlAttribute(name="TRAVELAGENCYNUMBER")
private String travelAgencyNumber;
@XmlAttribute(name="DESTINATION_FROM")
private String startAirportCode;
@XmlAttribute(name="DESTINATION_TO")
private String endAirportCode;
@XmlAttribute(name="PASSFORM")
private String passengerFormOfAddress;
@XmlAttribute(name="PASSNAME")
private String passengerName;
@XmlAttribute(name="PASSBIRTH")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date passengerDateOfBirth;
@XmlAttribute(name="CLASS")
private String flightClass;
...
}BookFlightResponse bean
以下列表演示了一个 JAXB bean,它被处理到 SAP BOOK_FLIGHT 响应对象的序列化形式:
@XmlRootElement(name="Response", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT")
@XmlAccessorType(XmlAccessType.FIELD)
public class BookFlightResponse {
@XmlAttribute(name="TRIPNUMBER")
private String tripNumber;
@XmlAttribute(name="TICKET_PRICE")
private BigDecimal ticketPrice;
@XmlAttribute(name="TICKET_TAX")
private BigDecimal ticketTax;
@XmlAttribute(name="CURRENCY")
private String currency;
@XmlAttribute(name="PASSFORM")
private String passengerFormOfAddress;
@XmlAttribute(name="PASSNAME")
private String passengerName;
@XmlAttribute(name="PASSBIRTH")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date passengerDateOfBirth;
@XmlElement(name="FLTINFO")
private FlightInfo flightInfo;
@XmlElement(name="CONNINFO")
private ConnectionInfoTable connectionInfo;
...
}响应对象的复杂参数字段被序列化为响应的子元素。
FlightInfo bean
以下列表演示了一个 JAXB bean,它被处理到复杂结构参数 FLTINFO 的序列化形式:
@XmlRootElement(name="FLTINFO", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT")
@XmlAccessorType(XmlAccessType.FIELD)
public class FlightInfo {
@XmlAttribute(name="FLIGHTTIME")
private String flightTime;
@XmlAttribute(name="CITYFROM")
private String cityFrom;
@XmlAttribute(name="DEPDATE")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date departureDate;
@XmlAttribute(name="DEPTIME")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date departureTime;
@XmlAttribute(name="CITYTO")
private String cityTo;
@XmlAttribute(name="ARRDATE")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date arrivalDate;
@XmlAttribute(name="ARRTIME")
@XmlJavaTypeAdapter(DateAdapter.class)
private Date arrivalTime;
...
}ConnectionInfoTable bean
以下列表演示了一个 JAXB bean,它将对复杂表参数 CONNINFO 的序列化形式 marshals。
JAXB bean 的 root 元素类型的名称对应于带有 _TABLE 后缀的行结构类型的名称,bean 包含行元素列表。
@XmlRootElement(name="CONNINFO_TABLE", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT")
@XmlAccessorType(XmlAccessType.FIELD)
public class ConnectionInfoTable {
@XmlElement(name="row")
List<ConnectionInfo> rows;
...
}ConnectionInfo bean
以下列表演示了一个 JAXB bean,它被处理到上述表行元素的序列化形式:
@XmlRootElement(name="CONNINFO", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT")
@XmlAccessorType(XmlAccessType.FIELD)
public class ConnectionInfo {
@XmlAttribute(name="CONNID")
String connectionId;
@XmlAttribute(name="AIRLINE")
String airline;
@XmlAttribute(name="PLANETYPE")
String planeType;
@XmlAttribute(name="CITYFROM")
String cityFrom;
@XmlAttribute(name="DEPDATE")
@XmlJavaTypeAdapter(DateAdapter.class)
Date departureDate;
@XmlAttribute(name="DEPTIME")
@XmlJavaTypeAdapter(DateAdapter.class)
Date departureTime;
@XmlAttribute(name="CITYTO")
String cityTo;
@XmlAttribute(name="ARRDATE")
@XmlJavaTypeAdapter(DateAdapter.class)
Date arrivalDate;
@XmlAttribute(name="ARRTIME")
@XmlJavaTypeAdapter(DateAdapter.class)
Date arrivalTime;
...
}