<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Vinay's blog]]></title><description><![CDATA[Vinay's blog]]></description><link>https://nexen.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 01 Nov 2026 09:11:23 GMT</lastBuildDate><atom:link href="https://nexen.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[10 Practical SAP CPI Lessons from 3 Years of Integration Work]]></title><description><![CDATA[I have been building integrations on SAP Cloud Integration (CPI, part of SAP Integration Suite) for about three years as a freelancer. Most of what I know…]]></description><link>https://nexen.hashnode.dev/10-practical-sap-cpi-lessons-from-3-years-of-integration-work</link><guid isPermaLink="true">https://nexen.hashnode.dev/10-practical-sap-cpi-lessons-from-3-years-of-integration-work</guid><category><![CDATA[SAP]]></category><category><![CDATA[CPI]]></category><category><![CDATA[integration]]></category><category><![CDATA[groovy]]></category><dc:creator><![CDATA[Vinay Thangellapally]]></dc:creator><pubDate>Mon, 26 Oct 2026 11:50:06 GMT</pubDate><content:encoded><![CDATA[<p>I have been building integrations on SAP Cloud Integration (CPI, part of SAP Integration Suite) for about three years as a freelancer. Most of what I know did not come from the documentation. It came from iFlows that broke in production, payloads that were too large, and tenants that ran out of storage.</p>
<p>Here are 10 lessons I wish someone had told me on day one.</p>
<h2>1. Keep iFlows small and modular</h2>
<p>One giant iFlow that does everything is hard to test, hard to read, and painful to change. Split the logic instead:</p>
<ul>
<li>Use <strong>Local Integration Processes</strong> for reusable steps inside an iFlow</li>
<li>Use the <strong>ProcessDirect</strong> adapter to call one iFlow from another in the same tenant</li>
<li>Keep common logic (logging, error handling, lookups) in shared iFlows</li>
</ul>
<p>A good rule: if you cannot explain an iFlow in two sentences, it is doing too much.</p>
<h2>2. Externalize everything that changes between tenants</h2>
<p>URLs, credential names, file paths, and schedules differ between DEV, QA, and PROD. Hardcode them once and every transport becomes a manual edit.</p>
<p>Use <strong>Externalized Parameters</strong> (<code>{{ReceiverURL}}</code>, <code>{{CredentialName}}</code>) so each tenant can be configured without touching the iFlow design.</p>
<h2>3. Never hardcode secrets</h2>
<p>Store passwords, OAuth clients, and keys in <strong>Monitor &gt; Security Material</strong> (User Credentials, OAuth2 Client Credentials, Secure Parameters, Keystore). Reference them by name in the adapter. Your iFlow export should never contain a password.</p>
<h2>4. Know the difference between headers and properties</h2>
<p>In a Content Modifier this trips up almost everyone at first:</p>
<ul>
<li><strong>Exchange properties</strong> stay inside the iFlow. Use them for internal variables.</li>
<li><strong>Message headers</strong> can be sent to the receiver (for example as HTTP headers).</li>
</ul>
<p>If you put internal values in headers, you may leak them to the target system. Also remember that incoming HTTP headers are only available if they are listed in <strong>Allowed Header(s)</strong> in the iFlow runtime configuration.</p>
<h2>5. Design error handling from the start</h2>
<p>Add an <strong>Exception Subprocess</strong> to every iFlow, not as an afterthought. Inside it:</p>
<ul>
<li>Read the error with <code>${exception.message}</code></li>
<li>Build a clear error payload or notification</li>
<li>Decide explicitly: retry, alert, or end gracefully</li>
</ul>
<p>For reliable delivery, use <strong>JMS queues</strong> (or the Data Store) so failed messages can be retried instead of lost.</p>
<h2>6. Be careful with payload logging</h2>
<p>Attaching full payloads to the message processing log feels helpful in DEV. In PROD it eats tenant storage and can expose sensitive data. Make it switchable:</p>
<pre><code class="language-groovy">import com.sap.gateway.ip.core.customdev.util.Message

def Message processData(Message message) {
    def body = message.getBody(String)
    def messageLog = messageLogFactory.getMessageLog(message)
    if (messageLog != null &amp;&amp; message.getProperty("EnablePayloadLogging") == "true") {
        messageLog.addAttachmentAsString("Payload", body, "text/plain")
    }
    return message
}
</code></pre>
<p>Drive <code>EnablePayloadLogging</code> from an externalized parameter so you can turn it on only when debugging.</p>
<h2>7. Use Trace, but know its limits</h2>
<p>Setting the log level to <strong>Trace</strong> shows the payload at every step, which is the fastest way to debug. It switches back automatically after a short time and the trace data is kept only briefly, so reproduce the issue right after enabling it.</p>
<h2>8. Handle large payloads with streaming</h2>
<p>Reading a big payload with <code>message.getBody(String)</code> loads it all into memory. For large files:</p>
<ul>
<li>Read the body as a stream (<code>message.getBody(java.io.Reader)</code>) in Groovy</li>
<li>Use the <strong>General Splitter</strong> with streaming enabled to process records in chunks</li>
<li>Use <strong>Gather</strong> to recombine results only if you really need one output</li>
</ul>
<h2>9. Declare XML namespaces properly</h2>
<p>XPath conditions in a Router or Content Modifier fail silently when the payload uses namespaces. Add the prefixes in the iFlow <strong>Runtime Configuration &gt; Namespace Mapping</strong> (for example <code>xmlns:ns0=http://example.com/order</code>) and use them in your XPath.</p>
<h2>10. Follow naming and transport discipline</h2>
<ul>
<li>Use a consistent naming pattern for packages and iFlows, such as <code>&lt;Source&gt;_&lt;Target&gt;_&lt;Object&gt;_&lt;Direction&gt;</code></li>
<li>Add a short description to every iFlow and step</li>
<li>Save a new version before every deployment</li>
<li>Move content between tenants with the <strong>Transport Management Service</strong> or CTS+ instead of manual export and import</li>
</ul>
<p>Future you (or the next consultant) will thank you.</p>
<h2>Final thoughts</h2>
<p>CPI is powerful, but most problems come from design shortcuts, not from the platform. Keep iFlows modular, keep configuration outside the design, and plan for failure from the first version.</p>
<p>What is the one CPI lesson you learned the hard way? Share it in the comments.</p>
]]></content:encoded></item><item><title><![CDATA[Your First Open-Source Pull Request: From Issue to Merge]]></title><description><![CDATA[Contributing to open source sounds intimidating the first time. Big codebases, strangers reviewing your code, Git commands you only half remember. The good…]]></description><link>https://nexen.hashnode.dev/your-first-open-source-pull-request-from-issue-to-merge</link><guid isPermaLink="true">https://nexen.hashnode.dev/your-first-open-source-pull-request-from-issue-to-merge</guid><category><![CDATA[Open Source]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[Git]]></category><category><![CDATA[beginners guide]]></category><dc:creator><![CDATA[Vinay Thangellapally]]></dc:creator><pubDate>Mon, 26 Oct 2026 11:39:20 GMT</pubDate><content:encoded><![CDATA[<p>Contributing to open source sounds intimidating the first time. Big codebases, strangers reviewing your code, Git commands you only half remember. The good news: the process is the same almost everywhere, and once you have done it once, it stops being scary.</p>
<p>This guide walks through the full flow, step by step:</p>
<p><strong>Issue → Fork → Clone → Branch → Work → Pull Request → Review → Merge</strong></p>
<h2>1. Find a project and an issue</h2>
<p>Start with a project you actually use or care about. You will understand the context faster and stay motivated.</p>
<p>Then look for an issue that fits a first contribution:</p>
<ul>
<li>Filter issues by labels like <code>good first issue</code>, <code>help wanted</code>, or <code>documentation</code></li>
<li>Read the project's <code>README.md</code> and <code>CONTRIBUTING.md</code> before anything else</li>
<li>Check that the issue is still open and nobody else is already working on it</li>
<li>Leave a short comment such as "I'd like to work on this, can I take it?" and wait for a maintainer to confirm</li>
</ul>
<p>Small is good. A typo fix, a missing test, or a docs improvement is a perfectly valid first PR.</p>
<h2>2. Fork the repository</h2>
<p>You cannot push directly to someone else's repository, so you make your own copy. On GitHub, click <strong>Fork</strong> at the top right of the repository page. You now have <code>github.com/&lt;your-username&gt;/&lt;project&gt;</code>.</p>
<h2>3. Clone your fork</h2>
<pre><code class="language-bash">git clone https://github.com/&lt;your-username&gt;/&lt;project&gt;.git
cd &lt;project&gt;
git remote add upstream https://github.com/&lt;original-owner&gt;/&lt;project&gt;.git
</code></pre>
<p>The <code>upstream</code> remote lets you pull in the latest changes from the original project later.</p>
<h2>4. Create a branch</h2>
<p>Never work directly on <code>main</code>. Create a branch named after the change:</p>
<pre><code class="language-bash">git checkout -b fix/typo-in-install-docs
</code></pre>
<p>One branch per issue keeps your pull requests clean and easy to review.</p>
<h2>5. Do the work</h2>
<ul>
<li>Follow the setup steps in the project docs and make sure the project runs locally</li>
<li>Keep the change focused on the issue, nothing extra</li>
<li>Match the existing code style and naming</li>
<li>Run the tests and linters the project uses before committing</li>
</ul>
<p>Then commit with a clear message:</p>
<pre><code class="language-bash">git add .
git commit -m "docs: fix typo in installation guide"
</code></pre>
<p>Tip: check whether the project uses a commit convention (like Conventional Commits) and follow it.</p>
<h2>6. Sync and push</h2>
<p>Before opening the PR, make sure your branch is up to date with the original project:</p>
<pre><code class="language-bash">git fetch upstream
git rebase upstream/main
git push origin fix/typo-in-install-docs
</code></pre>
<h2>7. Open the pull request</h2>
<p>GitHub will show a <strong>Compare &amp; pull request</strong> button on your fork. A good PR description has:</p>
<ul>
<li><strong>What</strong> changed, in one or two lines</li>
<li><strong>Why</strong>, with a link to the issue (<code>Fixes #123</code> closes it automatically on merge)</li>
<li><strong>How you tested it</strong></li>
<li>Screenshots if the change is visual</li>
</ul>
<p>Fill in the PR template if the project has one.</p>
<h2>8. Handle maintainer feedback</h2>
<p>This is the part that matters most. Maintainers may ask for changes, and that is normal, not a rejection.</p>
<ul>
<li>Reply politely and ask questions if something is unclear</li>
<li>Push fixes to the same branch, and the PR updates automatically</li>
<li>Be patient: maintainers are often volunteers, so a review can take days or weeks</li>
<li>If there is no response after a week or two, a friendly follow-up comment is fine</li>
</ul>
<h2>9. Merge and celebrate</h2>
<p>Once approved, a maintainer merges your PR and your name shows up in the project's history. Clean up afterwards:</p>
<pre><code class="language-bash">git checkout main
git pull upstream main
git branch -d fix/typo-in-install-docs
</code></pre>
<h2>Common mistakes to avoid</h2>
<ul>
<li>Starting work without commenting on the issue first</li>
<li>Opening one giant PR that changes many unrelated things</li>
<li>Ignoring the contributing guidelines or failing tests</li>
<li>Taking review comments personally</li>
<li>Using a work email for commits when the contribution is personal (set <code>git config user.email</code> per repository)</li>
</ul>
<h2>Final thoughts</h2>
<p>Your first pull request does not need to be impressive. It needs to be correct, focused, and respectful of the maintainers' time. Do that once, and the second one gets much easier.</p>
<p>If you are planning your first contribution and get stuck, drop a comment below. Happy contributing!</p>
]]></content:encoded></item></channel></rss>