الوحدة في هذا المقال: Integration Flow Helper
اكتشاف الترويسات والخصائص غير المعروفة في SAP CPI قبل أن تفشل بصمت
لماذا يفشل اسم ترويسة أو خاصية تبادل مكتوب خطأً أو مفقود في SAP CPI دون أي خطأ، وما الأسباب المعتادة، وكيف تكتشفها وقت التصميم ووقت التشغيل.

الترويسة التي لا تُضبط أبدًا لا توقف iFlow في SAP CPI. فالتعبير الذي يقرؤها يُرجع قيمة فارغة، ويصبح شرط Router خاطئًا، ويبقى حقل في الحمولة فارغًا، وتمضي الرسالة في طريقها. أما الخطأ، إن ظهر، فيظهر بعد عدة خطوات أو في النظام المستقبِل.
يشرح هذا المقال لماذا تفشل الترويسات وخصائص التبادل المفقودة بصمت، والأسباب التي تتكرر مرة بعد مرة، والفحوص التي تكتشفها قبل أن تكتشفها رسالة.
لماذا لا يُطلق الاسم المفقود أي خطأ
يعامل Apache Camel الترويسة أو الخاصية غير الموجودة على أنها فارغة، لا على أنها خطأ. وهذا مريح للقيم الاختيارية، وهو السبب في أن خطأً إملائيًا قد يعيش في iFlow لأشهر. وما تراه يعتمد على المكان الذي يُقرأ فيه الاسم:
- قيمة في Content Modifier مثل
${property.orderId}تصبح نصًا فارغًا. - شرط في Router أو Filter مثل
${header.orderType} = 'EXPRESS'يُقيَّم إلى false، فتسلك الرسالة مسارًا آخر، وكثيرًا ما يكون المسار الافتراضي. - عنوان مستقبِل مثل
/orders/${property.orderId}يستدعي/orders/، فيردّ النظام المستقبِل بخطأ لا يذكر الخاصية المفقودة. - في سكربت Groovy، يُرجع
message.getHeader("orderId", String)القيمة null، فيفشل السكربت لاحقًا بخطأ null pointer، أو يكتب النص null داخل الحمولة.
الأسباب المعتادة
- خطأ إملائي، أو حالة أحرف خاطئة في اسم خاصية: أسماء خصائص التبادل تميّز بين الأحرف الكبيرة والصغيرة، فـ
orderIDوorderIdخاصيتان مختلفتان. أما أسماء الترويسات فلا تميّز. - مسافة زائدة، مثل
${header.orderId }: الاسم الذي يحتوي على المسافة اسم مختلف. - قيمة تُضبط في مسار واحد فقط من مسارات Router، ثم تُقرأ بعد أن تلتقي المسارات من جديد.
- ترويسة يرسلها المستدعي لكن لا يُسمح لها بالدخول: مرسِل HTTPS لا يمرّر إلا الترويسات المخصصة المدرجة في Allowed Header(s) ضمن Runtime Configuration للـ iFlow.
- خاصية متوقعة من iFlow آخر: خصائص التبادل لا تعبر استدعاء ProcessDirect، وحدها الترويسات تعبره (انظر مقال ProcessDirect وJMS).
- صف ترويسة يقرأ خاصية أُنشئت في Content Modifier نفسه، الذي ينفّذ جدول الترويسات قبل جدول الخصائص.
اجعل القيمة المفقودة تفشل بصوت عالٍ
للقيم التي لا يستطيع التدفق العمل دونها، افشل في النقطة التي تُحتاج فيها بدلًا من ثلاث خطوات لاحقًا. وتكفي خطوة Groovy قصيرة في بداية التدفق:
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
def orderId = message.getProperty("orderId")
if (orderId == null || orderId.toString().trim().isEmpty()) {
throw new IllegalStateException("Exchange property orderId is not set")
}
return message
}عندها تنتهي الرسالة بخطأ بجملة تذكر اسم الخاصية المفقودة، وتظهر في سجل معالجة الرسائل. أما في شروط Router فامنح المسار الافتراضي غرضًا واضحًا: أنهِه بحدث Error End إذا كان يجب أن تطابق كل رسالة أحد المسارات دائمًا، بدلًا من ترك الرسالة تكمل على مسار كان مقصودًا به أن يكون احتياطيًا.
أثناء الاختبار، اضبط مستوى السجل في الـ iFlow على Trace. يعرض التتبع الترويسات وخصائص التبادل عند كل خطوة، فترى بالضبط أين تختفي القيمة.
قائمة تحقق قبل النشر
- اسرد كل ترويسة وخاصية يقرؤها الـ iFlow: في التعبيرات والشروط وحقول المحوّلات والسكربتات.
- لكل منها، ابحث عن الخطوة التي تضبطها، في كل مسار يصل إلى موضع القراءة.
- قارن الكتابة حرفًا بحرف، بما في ذلك حالة الأحرف في الخصائص وأي مسافات.
- للترويسات القادمة من المرسِل، تحقق من أنها مدرجة في Allowed Header(s).
- للقيم المُمرَّرة من iFlow آخر، تحقق من أنها تنتقل كترويسات لا كخصائص.
إجراء ذلك يدويًا يستغرق وقتًا على iFlow كبير، ولهذا فهو أول فحص يستحق الأتمتة.
عادات تسمية تمنع المشكلة
- اختر أسلوبًا واحدًا، مثل camelCase، واستخدمه لكل ترويسة وخاصية في الحزمة.
- اضبط القيم التي يعتمد عليها التدفق كله في Content Modifier واحد قرب البداية، ليكون هناك مكان واحد تبحث فيه.
- اترك البادئتين
SAP_وCamelلـ SAP وApache Camel؛ وامنح أسماءك شكلًا مختلفًا. - استخدم الخصائص للقيم التي يحتاجها هذا الـ iFlow وحده، والترويسات للقيم التي يجب أن تغادره فقط.
ويشرح مقال تعبيرات Camel Simple الصيغة التي تقف وراء كل اسم في هذه القائمة.
كيف يساعدك Kitegra
تنفّذ إضافة المتصفح Kitegra قائمة التحقق هذه داخل مصمم SAP Integration Suite. فلوحة الفحص (lint) فيها تنبّهك، قبل النشر، إلى الترويسات والخصائص التي لا يضبطها شيء في الـ iFlow، وإلى ${ غير المغلق والمسافات الزائدة في التعبيرات.
وعندما تكتب ${ أو $، لا تقترح إلا الأسماء التي يعرّفها الـ iFlow، بما فيها الأسماء المضبوطة في سكربتات Groovy وJavaScript، إضافة إلى الترويسات القياسية في SAP وCamel، فيقلّ احتمال الخطأ الإملائي من الأساس. والاسم الذي يُضبط في بعض المسارات فقط يُعلَّم بعبارة «يُعيَّن في بعض المسارات فقط». ولا تحفظ الإضافة محتوى أي iFlow ولا تنشره ولا تعدّله أبدًا، ولا يتغير المستأجر إلا عندما تنقر أحد أربعة إجراءات محددة بالاسم يمكن إيقافها.
عندما تكون قيمة ما فارغة وقت التشغيل، يعرض تتبّع الرسالة خطوة بخطوة الترويسات والخصائص قبل كل خطوة، وتغطي قائمة مراجعة الـ iFlow أخطاء التصميم التي تقف وراء ذلك.
بلا حساب تعمل الإضافة على 5 iFlows لكل وحدة. وتغطي خطة Free حتى 50، وخطة Starter حتى 100، وخطة Pro حتى 300، أما خطة Business فبلا حد. قارن بين الخطط.
جرّبها في الـ iFlow التالي
تعرّف على ما يفعله Kitegra في مصمم SAP Integration Suite، أو اطّلع عليه مع بقية وحدات Kitegra.
الأسئلة الشائعة
لماذا لا يُطلق SAP CPI خطأً عندما تكون الترويسة مفقودة؟
يُرجع Apache Camel قيمة فارغة للترويسة أو الخاصية غير الموجودة. ولا تظهر المشكلة إلا حيث تسبب تلك القيمة الفارغة ضررًا، وكثيرًا ما يكون ذلك بعد عدة خطوات.
لماذا تكون خاصية التبادل null مع أنني أرى أنها مضبوطة؟
تحقق من حالة الأحرف: أسماء خصائص التبادل تميّز بين الأحرف الكبيرة والصغيرة. وتحقق أيضًا من أن الخطوة التي تضبطها تعمل على المسار الذي سلكته الرسالة، وأن القيمة لم يكن متوقعًا أن تعبر استدعاء ProcessDirect.
لماذا لا تصل إلى الـ iFlow ترويسة أرسلها المستدعي؟
مرسِل HTTPS لا يمرّر إلا الترويسات المخصصة المدرجة في Allowed Header(s) ضمن Runtime Configuration للـ iFlow. أضف اسم الترويسة هناك.
كيف أرى الترويسات والخصائص عند كل خطوة؟
اضبط مستوى السجل في الـ iFlow على Trace وشغّل رسالة. يعرض التتبع في شاشة المراقبة الترويسات وخصائص التبادل لكل خطوة.
كيف أوقف التدفق عندما تكون قيمة مطلوبة مفقودة؟
أضف خطوة سكربت تتحقق من القيمة وتُطلق استثناءً برسالة واضحة، أو وجّه الفرع الافتراضي في Router إلى حدث Error End.
هل يمكن فحص ذلك قبل النشر؟
نعم، بمقارنة كل اسم يقرؤه الـ iFlow بالأسماء التي يضبطها. ولوحة الفحص في Kitegra تفعل ذلك داخل المصمم.