in

SAP Java Entegrasyonu: OData, RFC/JCo, IDoc ve CPI Rehberi

Java uygulamanızın SAP ile konuşması gerektiğinde dört yol var: OData, RFC/BAPI (JCo), IDoc ve SAP Integration Suite (CPI). Hangisinin ne zaman doğru olduğunu, S/4HANA OData API'sine Spring ile okuma-yazma (CSRF akışı dahil), JCo ile BAPI çağrısı, ana veri senkronizasyonu ve sahada gördüğümüz tuzakları anlatıyoruz.

Java uygulaması ile SAP S/4HANA arasındaki OData, RFC/JCo, IDoc ve CPI entegrasyon yollarını gösteren şema

Kurumsal Java uygulamalarının çoğu er ya da geç SAP ile konuşmak zorunda kalır: siparişi SAP'de oluşturmak, stoğu ve fiyatı SAP'den okumak, müşteri ve malzeme ana verisini eşitlemek, sevkiyat ve fatura belgelerini karşılıklı aktarmak. Bunun için dört ana yol var ve yanlış yolun seçildiği entegrasyonlar sahada aynı şekilde biter: kırılgan, yavaş ve SAP tarafındaki her değişiklikte yeniden yazılan.

Bu yazıda OData, RFC/BAPI (JCo), IDoc ve SAP Integration Suite (CPI) seçeneklerini karşılaştırıyor; S/4HANA OData API'sine Spring ile okuma ve yazmayı (CSRF akışı dahil), JCo ile BAPI çağrısını, ana veri senkronizasyonunu, ortak mimari kuralları ve sahada gördüğümüz tuzakları anlatıyoruz. Genel ERP entegrasyon mimarisi için ERP entegrasyonu yazımız temel oluşturur.

Dört yol

Yol

Protokol / araç

Senkron mu?

Uygun olduğu yer

Dezavantajı

OData

HTTP/JSON, S/4HANA Gateway; yayımlanmış API'ler (API Business Accelerator Hub)

Senkron

S/4HANA ile modern okuma/yazma; bulut ve on-premise; Java tarafında ek kütüphane yok

ECC'de sınırlı; büyük hacimli okuma yavaş; API kapsamı yayımlanmış servislerle sınırlı

RFC / BAPI (JCo)

SAP'nin native protokolü; Java Connector 3.x

Senkron

ECC ve S/4HANA; standart ve özel (Z) fonksiyonlar; yüksek performans

Native kütüphane, dağıtım kısıtı, SAP'ye sıkı bağlılık

IDoc

SAP'nin belge formatı (ORDERS05, DESADV, INVOIC…); JCo IDoc ya da CPI üzerinden

Asenkron

Toplu belge alışverişi, EDI benzeri akışlar, sipariş/sevkiyat/fatura

Yapı karmaşık, hata takibi SAP tarafında (WE02), gecikmeli

SAP Integration Suite (CPI)

SAP'nin bulut ara katmanı; iFlow, eşleme, izleme

İkisi de

Birden çok sistem, dönüşüm ve izleme merkezi; SAP ekosistemine yakın ekipler

Lisans ve gecikme; her çağrı bir katman daha; Java ekibi için ayrı uzmanlık

Olaylar

SAP Event Mesh / Advanced Event Mesh; iş olayları

Asenkron

"Sipariş oluşturuldu" gibi olaylarla tepki veren mimariler

Olay kapsamı sınırlı; olay + OData okuma birlikte gerekir

Pratik karar: S/4HANA ile yeni entegrasyonda önce OData; OData'nın karşılamadığı özel iş mantığı ve ECC için JCo; belge tabanlı toplu akışlarda IDoc; üçten fazla sistem ve dönüşüm ihtiyacında CPI. Tek bir yüksek hacimli Java–SAP entegrasyonu için CPI'yı araya koymak gecikme ve maliyet ekler.

OData: Spring ile okuma ve yazma

S/4HANA'nın yayımlanmış API'leri (örneğin API_SALES_ORDER_SRV) standart OData v2/v4 servisleridir: $filter, $select, $expand, $top/$skip ve toplu işlemler için $batch. Yazma işlemlerinde SAP Gateway CSRF token ister: önce X-CSRF-Token: Fetch başlığıyla bir GET, gelen token ve çerezlerle POST.

@Component
public class SapSiparisOdataAdaptoru implements SiparisErpPort {      // uygulamanın kendi port'u; SAP dili burada kalır
    private final RestClient client;                                    // temel URL: /sap/opu/odata/sap/API_SALES_ORDER_SRV

    @Override
    public ErpSiparisNo olustur(Siparis siparis) {
        // 1) CSRF token ve oturum çerezleri
        ResponseEntity<Void> fetch = client.get().uri("/A_SalesOrder?$top=1")
            .header("X-CSRF-Token", "Fetch").retrieve().toBodilessEntity();
        String token = fetch.getHeaders().getFirst("X-CSRF-Token");
        List<String> cerezler = fetch.getHeaders().get(HttpHeaders.SET_COOKIE);

        // 2) Yazma: SAP alan adlarına eşleme adaptörde
        Map<String, Object> govde = SapSiparisEsleme.toOdata(siparis);  // SoldToParty, SalesOrderType, to_Item[]…
        JsonNode yanit = client.post().uri("/A_SalesOrder")
            .header("X-CSRF-Token", token)
            .header(HttpHeaders.COOKIE, String.join("; ", cerezler))
            .contentType(MediaType.APPLICATION_JSON)
            .body(govde).retrieve().body(JsonNode.class);
        return new ErpSiparisNo(yanit.at("/d/SalesOrder").asText());
    }

    @Override
    public List<StokDurumu> stok(List<UrunKodu> urunler, DepoKodu depo) {
        String filtre = urunler.stream().map(u -> "Material eq '" + u.value() + "'").collect(Collectors.joining(" or "));
        // $select ile yalnızca gereken alanlar; büyük listelerde $batch ya da sayfalama ($skiptoken)
        ...
    }
}

Üç ayrıntı: (1) SAP'nin tarih ve sayı biçimleri (/Date(…)/, ondalık string) adaptörde dönüştürülür; (2) yazma sonrası ETag alınır ve güncellemede If-Match ile gönderilir, aksi hâlde eşzamanlı değişiklikler ezilir; (3) kimlik doğrulama on-premise'de teknik kullanıcıyla basic/X.509, BTP üzerinden OAuth 2.0 — teknik kullanıcının yetki nesneleri yalnızca gereken servislerle sınırlı olmalıdır.

RFC/BAPI: JCo ile çağrı

JCo (SAP Java Connector), SAP'nin native RFC protokolüyle konuşur; ECC ve S/4HANA'daki standart BAPI'leri ve özel Z fonksiyon modüllerini doğrudan çağırır. Bedeli: sapjco3.jar ve platforma özel native kütüphane (libsapjco3.so) SAP Support Portal'dan indirilir, yeniden dağıtılamaz, konteyner imajına lisanslı biçimde eklenir.

public ErpSiparisNo bapiIleOlustur(Siparis siparis) throws JCoException {
    JCoDestination hedef = JCoDestinationManager.getDestination("S4_PRD");     // bağlantı havuzu ve kimlik bilgileri destination dosyasında
    JCoFunction bapi = hedef.getRepository().getFunction("BAPI_SALESORDER_CREATEFROMDAT2");

    JCoStructure baslik = bapi.getImportParameterList().getStructure("ORDER_HEADER_IN");
    baslik.setValue("DOC_TYPE", "TA");
    baslik.setValue("SALES_ORG", siparis.satisOrg().value());
    JCoTable kalemler = bapi.getTableParameterList().getTable("ORDER_ITEMS_IN");
    for (Kalem k : siparis.kalemler()) {
        kalemler.appendRow();
        kalemler.setValue("MATERIAL", k.urun().value());
        kalemler.setValue("TARGET_QTY", k.miktar().value());
    }

    JCoContext.begin(hedef);                                                   // aynı oturumda BAPI + COMMIT
    try {
        bapi.execute(hedef);
        JCoTable donus = bapi.getTableParameterList().getTable("RETURN");
        if (SapDonus.hataVar(donus)) throw new SapIsHatasi(SapDonus.mesajlar(donus));   // TYPE = 'E' / 'A'
        JCoFunction commit = hedef.getRepository().getFunction("BAPI_TRANSACTION_COMMIT");
        commit.getImportParameterList().setValue("WAIT", "X");
        commit.execute(hedef);
        return new ErpSiparisNo(bapi.getExportParameterList().getString("SALESDOCUMENT"));
    } finally {
        JCoContext.end(hedef);
    }
}

JCo'da en sık yapılan hata BAPI_TRANSACTION_COMMIT'i unutmak ya da ayrı bağlantıda çağırmaktır: BAPI "başarılı" döner, belge SAP'de yoktur. İkinci hata, RETURN tablosunu kontrol etmemek: BAPI istisna fırlatmaz, hatayı tabloya yazar. Üçüncüsü, JCo'nun havuzunu ve zaman aşımlarını varsayılanda bırakmak; havuz boyutu SAP tarafındaki dialog süreç sayısıyla uyumlu olmalıdır.

IDoc: belge tabanlı asenkron akış

Sipariş (ORDERS05), sevkiyat bildirimi (DESADV) ve fatura (INVOIC) gibi belge akışlarında SAP'nin doğal dili IDoc'tur. Java tarafı ya bir JCo sunucusu olarak SAP'den gelen IDoc'ları dinler ya da CPI üzerinden HTTP/JSON'a dönüştürülmüş halini alır. Kurallar: her IDoc'un numarası idempotency anahtarıdır (aynı IDoc iki kez işlenmez); işleme durumu SAP tarafında da (WE02/WE05) izlenebilir olmalıdır; büyük IDoc'lar parçalanarak kuyruğa alınır; şema değişiklikleri (uzantı segmentleri) SAP'nin taşıma süreciyle koordine edilir.

Ana veri senkronizasyonu

Malzeme, müşteri ve fiyat listesi gibi ana veriler her istekte SAP'den okunmaz; Java tarafında bir kopya tutulur ve delta ile güncellenir. Üç yöntem: (1) gece toplu çekim (OData $filter=LastChangeDate ge …), (2) SAP değişiklik işaretçileri (change pointers) ile IDoc/olay, (3) BTP olayları. Hangisi olursa olsun bir kimlik eşleme tablosu şarttır: SAP müşteri numarası ↔ uygulama müşteri kimliği; SAP'nin başında sıfırlı, 10 haneli anahtarları uygulamanın domain modeline sızmaz.

Ortak mimari kurallar

  • Anti-corruption katmanı: SAP alan adları (KUNNR, MATNR, VBELN), tipleri ve hata kodları adaptörde kalır; domain modeli SAP'yi bilmez. SAP'den başka bir ERP'ye ya da ECC'den S/4HANA'ya geçiş, adaptör değişimidir.

  • Dayanıklılık: Her SAP çağrısı zaman aşımı, sınırlı retry (yalnızca idempotent okumalarda) ve devre kesici arkasında; SAP'nin bakım penceresi ya da yavaşlığı uygulamayı düşürmez (bkz. Resilience4j).

  • Yazmalar outbox'tan: SAP'ye giden sipariş, iş transaction'ında outbox'a yazılır; gönderici iş SAP'ye iletir ve SAP belge numarasını geri yazar.

  • Ortamlar ve taşıma: DEV/QAS/PRD üçlüsü Java tarafında da yansıtılır; SAP tarafındaki geliştirmeler (Z fonksiyon, CDS view, yetki) taşıma isteğiyle birlikte planlanır — Java sürümü SAP taşımasından önce çıkarsa entegrasyon kırılır.

  • Clean core: S/4HANA'da SAP çekirdeğini değiştirmek yerine yayımlanmış API'ler ve yan yana (side-by-side) uzantı; özel Z kodu yalnızca gerçekten gerektiğinde ve yayımlanmış arayüzler üzerinden.

  • Yetki: Teknik kullanıcı, yalnızca kullanılan servis ve fonksiyonlara yetkili; şifre döndürme ve günlük izleme.

Sahada sık yapılan hatalar

  1. Her ekranda SAP'ye canlı sorgu: Ürün listesi her açılışta 3 saniye; ana veri kopyası ve önbellek gerekir.

  2. RFC_READ_TABLE ile tablo okumak: Hızlı prototip, üretimde yavaş ve kırılgan; yayımlanmış API ya da CDS view kullanın.

  3. SAP'nin hata mesajını kullanıcıya göstermek: "VBAK-KUNNR için giriş yok" cümlesi kullanıcıya bir şey söylemez; adaptör iş diline çevirir.

  4. Commit unutmak, RETURN okumamak: Yukarıda anlatıldı; en pahalı iki hata.

  5. JCo native kütüphanesini konteynerde unutmak: Yerelde çalışan uygulama Kubernetes'te "no sapjco3 in java.library.path" ile düşer; imaj sürecinde açık adım.

  6. Test ortamı verisiyle üretim planlamak: QAS'taki 10 bin malzeme ile PRD'deki 2 milyon malzeme farklı sayfalama ve süre demektir.

Sık sorulan sorular

SAP Cloud SDK kullanmalı mıyız?

BTP üzerinde Java geliştiriyorsanız Cloud SDK, destination yönetimi, kimlik doğrulama ve OData istemcisini standartlaştırır ve iyi bir seçimdir. Kendi altyapınızdaki Spring Boot uygulaması için Spring'in RestClient'ı ile ince bir OData istemcisi çoğu zaman yeterli ve daha kontrol edilebilirdir.

ECC'den S/4HANA'ya geçiş entegrasyonu nasıl etkiler?

JCo/BAPI çağrılarının büyük kısmı S/4HANA'da da çalışır, ancak bazı BAPI'ler ve tablo yapıları değişir (müşteri/tedarikçi → iş ortağı gibi). Anti-corruption katmanı varsa geçiş adaptör güncellemesidir; yoksa uygulama genelinde değişiklik.

Gerçek zamanlı stok bilgisi mümkün mü?

OData ile saniyeler içinde; ama her sepet görüntülemesinde SAP'ye gitmek yerine kısa TTL'li önbellek (30–60 sn) ve kritik anlarda (sipariş onayı) canlı sorgu doğru dengedir.

Sonuç

SAP–Java entegrasyonunda yol seçimi (OData, JCo, IDoc, CPI) önemlidir ama belirleyici değildir; belirleyici olan SAP'nin dilini adaptörde tutan anti-corruption katmanı, ana veri kopyası ve kimlik eşlemesi, outbox'tan yazma, dayanıklılık ve SAP taşıma süreciyle koordineli sürüm planıdır. Bu kurallarla kurulan entegrasyon, ECC'den S/4HANA'ya geçişte bile ayakta kalır.

Java uygulamalarınızı SAP ile entegre etmek ya da mevcut entegrasyonu S/4HANA'ya taşımak için SAP danışmanlığı ve entegrasyon ve otomasyon hizmetlerimize göz atabilirsiniz.