最近公司服務器做遷移,原R3 PRE需要遷到另外的地方,遷移后一段時間內,需要兩套PRE環境同時運行,過一段時間后才將傳輸路線切換到新的PRE。在切換前,要求新PRE環境也要正常同步發布請求,但傳輸路線只有一條,這需要在發原PRE時,同時手工發布新PRE,這樣每次手工很麻煩(
手工導入傳輸請求過程參考這篇文章
)。本文就是來通過程序實現這種手工全過程,實現同步自動發布新PRE。實現過程也算簡單,通過一台中間Java Web服務器進行傳輸請求的中轉,將DEV上的傳輸請求文件下載后,上傳到新PRE服務器上,然后在新PRE服務器上導入新的請求即可。這就需要在DEV上寫個遠程RFS接口,將需要傳輸的請求所對應的數據與配置文件下載下來;在新PRE上寫個遠程接口,將從DEV上下載下來的傳輸請求文件上傳到新PRE服務器上,其后通過調用發布函數進行請求發布。代碼涉及到三台機器:SAP DEV ——> Java Web
中轉
服務器
——
> SAP PRE,之間采用JCO進行連接。最新的SAP JCO包請點擊這里下載,Linux上So動態鏈接庫以及Windows的Dll部署請百度
1、DEV遠程接口:




FUNCTION zxg_pre_fuc.
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(REQUESTNO) TYPE STRING
*" EXPORTING
*" VALUE(FILES) TYPE ZXG_PRE_TABLE_TYPE
*" VALUE(REQUESTNOS) TYPE STRING
*"----------------------------------------------------------------------
DATA: result_tab TYPE TABLE OF string WITH HEADER LINE.
"多個請求以逗號分隔
SPLIT requestno AT ',' INTO TABLE result_tab IN CHARACTER MODE.
DATA: lt_data_binary TYPE TABLE OF sdokcntbin WITH HEADER LINE.
DATA: lv_binary_len TYPE i,lv_lines TYPE i,lv_total_len TYPE i.
DATA: v_filename TYPE string.
DATA: lw_files LIKE LINE OF files.
LOOP AT result_tab.
DO 2 TIMES.
CLEAR:lw_files,lv_total_len,lt_data_binary[].
IF sy-index = 1.
"傳輸請求所對應的數據文件
CONCATENATE `/usr/sap/trans/data/R` result_tab+4 `.DEV` INTO v_filename.
ELSE.
"傳輸請求所對應的配置文件
CONCATENATE `/usr/sap/trans/cofiles/K` result_tab+4 `.DEV` INTO v_filename.
ENDIF.
"從服務器上讀取文件
lw_files-filename = v_filename.
OPEN DATASET v_filename FOR INPUT IN BINARY MODE.
DO.
CLEAR: lt_data_binary,lv_binary_len.
READ DATASET v_filename INTO lt_data_binary ACTUAL LENGTH lv_binary_len.
IF lv_binary_len > 0.
lv_total_len = lv_total_len + lv_binary_len.
APPEND lt_data_binary.
lw_files-last_line_size = lv_binary_len.
ELSE.
lw_files-total_size = lv_total_len.
EXIT.
ENDIF.
ENDDO.
CLOSE DATASET v_filename.
lw_files-data = lt_data_binary[].
APPEND lw_files TO files.
ENDDO.
ENDLOOP.
"返回給Java Web服務器
requestnos = requestno.
ENDFUNCTION.
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(REQUESTNO) TYPE STRING
*" EXPORTING
*" VALUE(FILES) TYPE ZXG_PRE_TABLE_TYPE
*" VALUE(REQUESTNOS) TYPE STRING
*"----------------------------------------------------------------------
DATA: result_tab TYPE TABLE OF string WITH HEADER LINE.
"多個請求以逗號分隔
SPLIT requestno AT ',' INTO TABLE result_tab IN CHARACTER MODE.
DATA: lt_data_binary TYPE TABLE OF sdokcntbin WITH HEADER LINE.
DATA: lv_binary_len TYPE i,lv_lines TYPE i,lv_total_len TYPE i.
DATA: v_filename TYPE string.
DATA: lw_files LIKE LINE OF files.
LOOP AT result_tab.
DO 2 TIMES.
CLEAR:lw_files,lv_total_len,lt_data_binary[].
IF sy-index = 1.
"傳輸請求所對應的數據文件
CONCATENATE `/usr/sap/trans/data/R` result_tab+4 `.DEV` INTO v_filename.
ELSE.
"傳輸請求所對應的配置文件
CONCATENATE `/usr/sap/trans/cofiles/K` result_tab+4 `.DEV` INTO v_filename.
ENDIF.
"從服務器上讀取文件
lw_files-filename = v_filename.
OPEN DATASET v_filename FOR INPUT IN BINARY MODE.
DO.
CLEAR: lt_data_binary,lv_binary_len.
READ DATASET v_filename INTO lt_data_binary ACTUAL LENGTH lv_binary_len.
IF lv_binary_len > 0.
lv_total_len = lv_total_len + lv_binary_len.
APPEND lt_data_binary.
lw_files-last_line_size = lv_binary_len.
ELSE.
lw_files-total_size = lv_total_len.
EXIT.
ENDIF.
ENDDO.
CLOSE DATASET v_filename.
lw_files-data = lt_data_binary[].
APPEND lw_files TO files.
ENDDO.
ENDLOOP.
"返回給Java Web服務器
requestnos = requestno.
ENDFUNCTION.
2、新PRE遠程接口:

此服務器上的ZXG_PRE_TABLE_TYPE類型與DEV上是一樣的,這里就不再截圖
FUNCTION zxg_pre_fuc.
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(FILES) TYPE ZXG_PRE_TABLE_TYPE
*" VALUE(REQUESTNOS) TYPE STRING
*"----------------------------------------------------------------------
DATA: lw_files TYPE zxg_pre_strc_type.
DATA: lw_data TYPE sdokcntbin.
DATA: lines TYPE i.
DATA: indx TYPE i .
LOOP AT files INTO lw_files .
indx = 0.
OPEN DATASET lw_files-filename FOR OUTPUT IN BINARY MODE.
DESCRIBE TABLE lw_files-data LINES lines.
LOOP AT lw_files-data INTO lw_data.
indx = indx + 1.
IF indx <> lines.
TRANSFER lw_data-line TO lw_files-filename.
ELSE.
TRANSFER lw_data-line+(lw_files-last_line_size) TO lw_files-filename.
ENDIF.
ENDLOOP.
CLOSE DATASET lw_files-filename.
ENDLOOP.
DATA: result_tab TYPE TABLE OF string WITH HEADER LINE.
SPLIT requestnos AT ',' INTO TABLE result_tab IN CHARACTER MODE.
DATA: req TYPE tmsbuffer-trkorr.
LOOP AT result_tab.
req = result_tab.
PERFORM frm_stms USING req.
ENDLOOP.
ENDFUNCTION.
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(FILES) TYPE ZXG_PRE_TABLE_TYPE
*" VALUE(REQUESTNOS) TYPE STRING
*"----------------------------------------------------------------------
DATA: lw_files TYPE zxg_pre_strc_type.
DATA: lw_data TYPE sdokcntbin.
DATA: lines TYPE i.
DATA: indx TYPE i .
LOOP AT files INTO lw_files .
indx = 0.
OPEN DATASET lw_files-filename FOR OUTPUT IN BINARY MODE.
DESCRIBE TABLE lw_files-data LINES lines.
LOOP AT lw_files-data INTO lw_data.
indx = indx + 1.
IF indx <> lines.
TRANSFER lw_data-line TO lw_files-filename.
ELSE.
TRANSFER lw_data-line+(lw_files-last_line_size) TO lw_files-filename.
ENDIF.
ENDLOOP.
CLOSE DATASET lw_files-filename.
ENDLOOP.
DATA: result_tab TYPE TABLE OF string WITH HEADER LINE.
SPLIT requestnos AT ',' INTO TABLE result_tab IN CHARACTER MODE.
DATA: req TYPE tmsbuffer-trkorr.
LOOP AT result_tab.
req = result_tab.
PERFORM frm_stms USING req.
ENDLOOP.
ENDFUNCTION.
FORM frm_stms USING requestno TYPE tmsbuffer-trkorr.
CALL FUNCTION 'TMS_MGR_FORWARD_TR_REQUEST'
EXPORTING
iv_request = requestno
iv_target = 'PRE'
iv_tardom = 'DOMAIN_PRE'.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
CALL FUNCTION 'TMS_MGR_IMPORT_TR_REQUEST'
EXPORTING
iv_system = 'PRE'
iv_domain = 'DOMAIN_PRE'
iv_request = requestno.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.
CALL FUNCTION 'TMS_MGR_FORWARD_TR_REQUEST'
EXPORTING
iv_request = requestno
iv_target = 'PRE'
iv_tardom = 'DOMAIN_PRE'.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
CALL FUNCTION 'TMS_MGR_IMPORT_TR_REQUEST'
EXPORTING
iv_system = 'PRE'
iv_domain = 'DOMAIN_PRE'
iv_request = requestno.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
ENDFORM.
3、Java Web
import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sap.conn.jco.AbapException;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoParameterList;
import com.sap.conn.jco.JCoTable;
import com.sap.conn.jco.ext.DestinationDataProvider;
public class ConnectPooled {// 連接池
private static Log log = LogFactory.getLog(ConnectPooled.class);
static String ABAP_AS_POOLED_XG_PRE = "ABAP_AS_POOLED_XG_PRE";
static String ABAP_AS_POOLED_R3_DEV = "ABAP_AS_POOLED_R3_DEV";
static {
config("192.168.118.xx");// dev
config("10.242.6.xxx");// pre
}
private static void config(String ip) {
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, ip);
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "00");
connectProperties
.setProperty(DestinationDataProvider.JCO_CLIENT, "200");
connectProperties.setProperty(DestinationDataProvider.JCO_USER,
"1504xxxx");
// 注:密碼是區分大小寫的,要注意大小寫
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD,
"axxxxxx");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "en");
// *********連接池方式與直接不同的是設置了下面兩個連接屬性
// JCO_PEAK_LIMIT - 同時可創建的最大活動連接數,0表示無限制,默認為JCO_POOL_CAPACITY的值
// 如果小於JCO_POOL_CAPACITY的值,則自動設置為該值,在沒有設置JCO_POOL_CAPACITY的情況下為0
connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT,
"10");
// JCO_POOL_CAPACITY - 空閑連接數,如果為0,則沒有連接池效果,默認為1
connectProperties.setProperty(
DestinationDataProvider.JCO_POOL_CAPACITY, "3");
createDataFile(ABAP_AS_POOLED_XG_PRE, "jcoDestination",
connectProperties);
}
static void createDataFile(String name, String suffix, Properties properties) {
File cfg = new File(name + "." + suffix);
if (!cfg.exists()) {
try {
FileOutputStream fos = new FileOutputStream(cfg, false);
properties.store(fos, "for tests only !");
fos.close();
} catch (Exception e) {
log.error("", e);
}
}
}
/**
* 根據輸入的傳輸請求號,從DEV上獲取傳輸請求所對應的傳輸文件
* @param REQUESTNO
* @return
* @throws JCoException
*/
public static JCoTable getTransRequestFiles(String REQUESTNO)
throws JCoException {
JCoDestination destination = JCoDestinationManager
.getDestination(ABAP_AS_POOLED_R3_DEV);
JCoFunction function = destination.getRepository().getFunction(
"ZXG_PRE_FUC");// 從對象倉庫中獲取 RFM 函數
if (function == null)
throw new RuntimeException("ZXG_PRE_FUC not found in SAP.");
JCoParameterList jpl = function.getImportParameterList();
jpl.setValue("REQUESTNO", REQUESTNO);
try {
function.execute(destination);
} catch (AbapException e) {
log.error("", e);
return null;
}
jpl = function.getExportParameterList();
JCoTable jt = jpl.getTable("FILES");
return jt;
}
/**
* 將DEV上的傳輸請求文件上傳到PRE上去,並實現后繼的自動發布過程
* @param jt
* @param req
* @throws JCoException
*/
public static void sendTransReqFiles2xgpre(JCoTable jt, String req)
throws JCoException {
JCoDestination destination = JCoDestinationManager
.getDestination(ABAP_AS_POOLED_XG_PRE);
JCoFunction function = destination.getRepository().getFunction(
"ZXG_PRE_FUC");// 從對象倉庫中獲取 RFM 函數
if (function == null)
throw new RuntimeException("ZXG_PRE_FUC not found in SAP.");
function.getImportParameterList().setValue("FILES", jt);
function.getImportParameterList().setValue("REQUESTNOS", req);
try {
function.execute(destination);
} catch (AbapException e) {
log.error("", e);
}
}
}
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.sap.conn.jco.JCoException;
@Controller
@RequestMapping("/xgpresync")
public class XGPRECtrl {
private static Log log = LogFactory.getLog(XGPRECtrl.class);
@RequestMapping("/gettransreq")
public void gettransreq(HttpServletRequest request,
HttpServletResponse response, String transreq) throws JCoException {
log.info("reqs:" + transreq);
try {
ConnectPooled.sendTransReqFiles2xgpre(
ConnectPooled.getTransRequestFiles(transreq), transreq);
JsonPrintUtil.printJson(response, true, "", "");
} catch (Exception e) {
log.error("", e);
JsonPrintUtil.printJson(response, false, e.getMessage(), "");
}
}
}
然后再將該鏈接集成到我司發布平台上去,實現自動發布
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">
附件列表