Sunday, May 10, 2026

OIC - OCI Java function code for RSA Encryption and Decryption

Function Java code:

package com.test.fn;

import java.security.*;

import java.security.spec.*;

import java.util.Base64;

import javax.crypto.Cipher;

import java.util.logging.*;

public class RSAEncryptDecrypt {

    private static final Logger logger = Logger.getLogger(RSAEncryptDecrypt.class.getName());

  public static class Input {

        public String message;

        public String secretKeyBase64;

        public String rsaMode;

        public String actionType; // ENCRYPT or DECRYPT

    }

    public static class Result {

        public String message;

        public String executionInfo;

    }

    public Result handleRequest(Input input) throws Exception {

        logger.log(Level.INFO, "OIC - message:", input.message);

        logger.log(Level.INFO, "OIC - secretKeyBase64:", input.secretKeyBase64);

        logger.log(Level.INFO, "OIC - rsaMode:", input.rsaMode);

        logger.log(Level.INFO, "OIC - actionType:", input.actionType);

        Result result = null;

        if ("DECRYPT".equals(input.actionType)) {

            result = decryptMyMessage(input);

        } else if ("ENCRYPT".equals(input.actionType)) {

            result = encryptMyMessage(input);

        } else {

            result = new Result();

            result.executionInfo = "ERROR: No proper action found , possible value "

                    + "is ENCRYPT or DECRYPT , recieved value:"

                    + input.actionType;

        }

        return result;

    }

// Method to encrypt plaintext using the RSA public key

 public Result encryptMyMessage(Input input) throws Exception {

     Result result = new Result();

     try {

         PublicKey publicKey = loadPublicKey(input.secretKeyBase64);

         Cipher cipher = Cipher.getInstance(input.rsaMode); // RSA encryption scheme

         cipher.init(Cipher.ENCRYPT_MODE, publicKey);

         byte[] encryptedBytes =                cipher.doFinal(input.message.getBytes());

         result.message =                 Base64.getEncoder().encodeToString(encryptedBytes);

         result.executionInfo = "SUCCESS";

     } catch (Exception e) {

         result.executionInfo = e.getMessage();

         logger.log(Level.INFO, "Error Details:", e.getMessage());

     }

     return result; // return as Base64 string

 }

 public Result decryptMyMessage(Input input) throws Exception {

     Result result = new Result();

     try {

         Cipher decryptCipher =

                 Cipher.getInstance(input.rsaMode);

         PrivateKey privateKey =                getPrivateKeyFromString(input.secretKeyBase64);         decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);

         byte[] decryptedBytes =

                 decryptCipher.doFinal(                       Base64.getDecoder().decode(input.message));

         String myDecryptedMsg =

                 new String(decryptedBytes, "UTF-8");

         result.message = myDecryptedMsg;

         result.executionInfo = "SUCCESS";

     } catch (Exception e) {

         result.executionInfo = e.getMessage();

         logger.log(Level.INFO, "Error Details:", e.getMessage());

     }

     return result; // return as Base64 string

 }

// Converts a Base64-encoded public key string to PublicKey object

 public static PublicKey loadPublicKey(String base64PublicKey) throws Exception {

     byte[] keyBytes =            Base64.getDecoder().decode(base64PublicKey);

     X509EncodedKeySpec spec =

             new X509EncodedKeySpec(keyBytes);

     KeyFactory keyFactory =

             KeyFactory.getInstance("RSA");

     return keyFactory.generatePublic(spec);

 }

 // Convert Base64 string to PrivateKey

 public static PrivateKey getPrivateKeyFromString(String base64PrivateKey)

         throws Exception {

     byte[] keyBytes =            Base64.getDecoder().decode(base64PrivateKey);

     PKCS8EncodedKeySpec spec =

             new PKCS8EncodedKeySpec(keyBytes);

     KeyFactory factory =

             KeyFactory.getInstance("RSA");

     return factory.generatePrivate(spec);

 }

}

Java code Screenshots:





Friday, May 8, 2026

OIC - Improving OIC Performance – Avoid Large Payloads in String Variables | String Size Limit Warning Message

While working with large payloads in Oracle Integration Cloud (OIC), especially from BIP report responses, many developers store the complete response inside a string variable for later processing or logging.

This works initially, but when the payload becomes too large, OIC may start showing a warning like:

“String size limit”



This is commonly seen when the string exceeds around 10,000 characters (10K).

OIC Server limit:

If the size of a string variable exceeds 10,000 characters, a warning message is shown in the activity stream. Oracle Integration does not currently impose a limit on the size of string variables. However, this may be subject to change in the future, which could result in a flow execution failing when the limit is exceeded.

Common Scenario

We had a use case where:

OIC was calling a BIP Report

The report response contained a very large XML/Base64 payload

Entire response was stored in a string variable

Integration completed successfully, but OIC generated a warning notification

Typical warning behavior:

Integration still succeeds

Activity stream shows warning

OIC dashboard displays alert notification

Performance may degrade due to heavy in-memory string handling

Why This Happens

OIC internally maintains limits for string handling in memory.

When a very large payload is stored in:

Assign activity variables

String variables

Logger messages

Tracking fields

OIC raises a String Size Limit Warning.

This does not always fail the integration immediately, but it can:

Increase memory usage

Slow down execution

Create unnecessary activity stream overhead

Impact overall integration performance

Real Impact on Performance

Large string variables can cause:

1. Increased Memory Consumption

Huge payloads remain loaded in memory during runtime.

2. Slower Assign Activities

Assigning massive strings repeatedly increases processing time.

3. Activity Stream Overhead

OIC tries to maintain activity and debug information.

4. Payload Serialization Cost

Large string conversion operations impact performance.

5. Difficult Debugging

Very large payload logs become hard to analyze.

Recommended Resolution

1. Avoid Storing Full Payload in String Variables

Instead of:

Storing complete BIP response

Storing entire Base64 output

Keeping full XML/JSON in string variables

Store only:

Required nodes

Specific fields

IDs/status values

2. Use Stage File for Large Content

For large payload processing:

Write payload into Stage File

Process file stream-wise

Avoid keeping everything in memory

This is the best approach for:

Large XML

CSV

Base64 documents

Huge BIP outputs

3. Read Only Required Data

Instead of mapping the complete payload:

Extract only needed elements using:

XPath

JSON path

Stage File Read

Example:

Employee Number

Report Status

File Name

Document ID

Avoid unnecessary full payload assignments.

4. Avoid Logging Full Payloads

Do not log:

Entire XML

Complete Base64

Large JSON responses

Instead log:

Record count

Transaction ID

Small status messages

5. Use Attachments/File References When Possible

For document-heavy integrations:

Pass file references

Use attachments

Use opaque/binary handling

Instead of converting everything into strings.

Best Practice Architecture

Recommended flow:

Call BIP Report

Receive large payload

Store in Stage File / Attachment

Read only required fields

Pass file reference downstream

Avoid huge string variables

Key Takeaway

If OIC shows: String Size Limit Warning. it usually means: 

Integration processed a very large string payload

OIC memory threshold warning was triggered

Integration may still succeed

But performance optimization is needed

Reference:

https://community.oracle.com/customerconnect/discussion/926935/oic-string-size-limit-alert?utm_source=chatgpt.com


Thursday, May 7, 2026

OIC - Handling dynamic JSON Payloads in OIC Using Binary JSON Media Type

 In Oracle Integration Cloud (OIC), there are scenarios where the source system sends dynamic or variable JSON payloads through a REST service. Since the structure may change frequently, creating strict schemas becomes difficult.

In our requirement, the incoming JSON payload needs to be passed to the target Communication Cloud service as escaped JSON, while also reading only a few required fields from the payload for validations or processing.

Requirement

Expose a REST API in OIC.

Source system can send any type of JSON structure.

Need to avoid strict request schema dependency.

Read only required fields from the payload.

Pass the complete original JSON payload to Communication Cloud service as escaped JSON.

Solution Approach

1. Configure REST Trigger with Binary JSON Media Type

While creating the REST trigger:

Select Binary as the request payload type.

Set media type as:

Plain text

application/json

This allows OIC to accept any JSON structure dynamically without schema validation.


Benefit

No dependency on fixed JSON schema.

Supports variable or changing payload structures.

Prevents failures due to unexpected fields.

2. Read Required Fields Using Stage File Action

Since the payload is received as binary content:

Use Stage File → Read Entire File

Read the incoming payload as JSON.

From the Stage File schema, extract only the required fields needed for processing.

Example:

JSON

{

  "employeeId": "1001",

  "status": "ACTIVE",

  "dynamicData": {

      ...

  }

}

You may read only: employeeId , status without validating the complete payload structure.



3. Preserve Original JSON Payload

The key advantage of this approach is:

The original payload remains unchanged.

No need to reconstruct JSON again in mapper.

Entire payload can directly be forwarded to downstream systems.

4. Pass Complete Payload to Communication Cloud

The target Communication Cloud service expects escaped JSON.

Since the original payload is already preserved:

Map the complete payload directly to target request.

Use escaped JSON/string format as required by Communication Cloud API.

Example target payload:

JSON

{

  "payload": "{\"employeeId\":\"1001\",\"status\":\"ACTIVE\"}"

}


Architecture Flow

Plain text

  • Source System

      ↓

OIC REST Trigger

(Binary JSON Media Type)

      ↓

Stage File Read

(Read only required fields)

      ↓

Map Original Payload

      ↓

Communication Cloud REST Service

(Escaped JSON)

Advantages of This Approach

  • Supports dynamic JSON structures.
  • No schema maintenance effort.
  • Avoids trigger regeneration issues.
  • Easy handling of changing payloads.
  • Efficient for pass-through integrations.
  • Only required fields are parsed.

Conclusion

Using Binary JSON media type in OIC REST triggers is an effective solution when handling variable JSON payloads. By combining it with Stage File read operations, we can selectively access required fields while still forwarding the complete original payload to downstream systems like Communication Cloud without rebuilding the JSON structure.

Tuesday, May 5, 2026

OIC - Handling Unknown Record Types in OIC (Header / Detail / Footer Detection) | How to validate a string in yyyymmdd is in date format?

๐Ÿ“Œ Problem Statement

In one of our Oracle Integration Cloud (OIC) file-based integrations, the source file structure was unclear.

We were receiving records, but no explicit identifier was present to distinguish:

Header

Detail

Footer

However, we observed one consistent pattern: ๐Ÿ‘‰ Detail records always contain a date in YYYYMMDD format at a fixed position.

๐Ÿ’ก Solution Approach

We used this date pattern as a validation key to identify detail records.

✔️ Logic:

Extract substring from the record (specific position where date exists)

Convert it into proper date format (YYYY-MM-DD)

Compare with original substring

Count matching records

If count = 0 → No detail record → Fail validation

๐Ÿ› ️ OIC Implementation

Step 1: Extract Date from Record

Assume date starts at position 19 in the string:

Xpath

substring(ns30:Data, 19, 8)

Step 2: Convert to Proper Date Format

Xpath

concat(

  substring(ns30:Data, 19, 4), "-",

  substring(ns30:Data, 23, 2), "-",

  substring(ns30:Data, 25, 2)

)

Step 3: Validate Date Format

Xpath

xp20:format-dateTime(

  concat(

    substring(ns30:Data, 19, 4), "-",

    substring(ns30:Data, 23, 2), "-",

    substring(ns30:Data, 25, 2)

  ),

  "[Y0001][M01][D01]"

)

Step 4: Compare with Original Value

Xpath

xp20:format-dateTime(...) = substring(ns30:Data, 19, 8)

๐Ÿ‘‰ If TRUE → Valid date → Detail record

Step 5: Count Detail Records

Xpath

count(

  $ReadRawFile/nsmpr0:ReadResponse/ns30:RawFileRowSet/ns30:RawFileRow[

    xp20:format-dateTime(

      concat(

        substring(ns30:Data, 19, 4), "-",

        substring(ns30:Data, 23, 2), "-",

        substring(ns30:Data, 25, 2)

      ),

      "[Y0001][M01][D01]"

    ) = substring(ns30:Data, 19, 8)

  ]

)

๐Ÿšจ Final Validation Condition

Xpath

count(...) = 0

Meaning:

✅ If count > 0 → Detail records exist → Proceed

❌ If count = 0 → No detail records → Fail Integration

๐ŸŽฏ Key Benefits

No dependency on explicit record type indicators

Works with inconsistent file formats

Lightweight validation using XPath

Prevents downstream processing errors

⚡ Pro Tip

If date position may vary or data is dirty:

Use normalize-space() before substring

Add additional checks (length = 8, numeric check)

๐Ÿงพ Conclusion

When file structure is ambiguous, pattern-based validation (like date detection) is a powerful technique in OIC.

This approach ensures that only valid detail records are processed, improving reliability and 

Wednesday, April 29, 2026

OIC - RSA sign and verify java code for OCI Function

Java code:

package com.test.fn;

import java.security.*;
import java.security.spec.*;
import java.util.Base64;
import java.util.logging.*;
import java.security.MessageDigest;

public class RSASignVerify {

    private static final Logger logger =
        Logger.getLogger(RSASignVerify.class.getName());

    public static class Input {
        public String message;
        public String signatureBase64;
        public String publicKeyBase64;
        public String privateKeyBase64;
        public String hashType;
        public String actionType; //SIGN or VERIFY
        public String messageType; // BASE64 or TEXT or MESSAGE_TO_DIGEST
    }

    public static class Result {
        public boolean verifyResult;
        public String signatureBase64;
        public String executionInfo;
    }
/**
 * Verifies an RSA signature.
 *
 * @param Input
 * The original data that was signed.
 * signatureBase64 The signature in Base64 encoding.
 * publicKeyBase64 The RSA public key in Base64 encoding (X.509 format).
 * HashType Hashing value to Initialize the Signature object for verification, SHA256withRSA.
 *
 * @return true if the signature is valid, false otherwise.
 * @throws Exception on errors during verification.
 */
public Result verifyMessage(Input input) throws Exception {
    Result result = new Result();
    try {

        // Decode the public key
        byte[] publicKeyBytes = Base64.getDecoder().decode(input.publicKeyBase64);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);

        // Decode the signature
        byte[] signatureBytes = Base64.getDecoder().decode(input.signatureBase64);

        // Initialize the Signature object for verification with SHA256withRSA
        Signature signature = Signature.getInstance(input.hashType);
        signature.initVerify(publicKey);
if("BASE64".equals(input.messageType)){
    byte [] messageBytes = Base64.getDecoder().decode(input.message);
    signature.update(messageBytes);
}else if ("MESSAGE_TO_DIGEST".equals(input.messageType)){
    signature.update(getDigestBytes(input.message));
}else{
    signature.update(input.message.getBytes("UTF-8"));
}

// Verify the signature
result.verifyResult = signature.verify(signatureBytes);
result.executionInfo = "SUCCESS";

} catch(Exception e) {
    result.verifyResult = false;
    result.executionInfo = e.getMessage();
    System.out.println("Error Details:" + e.getMessage());
}
return result;
}
public Result signMessage(Input input) throws Exception {
    Result result = new Result();
    try {

        // Decode the private key
        byte[] keyBytes = Base64.getDecoder().decode(input.privateKeyBase64);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey=keyFactory.generatePrivate(spec);

        // Initialize the Signature object for verification with SHA256withRSA
        Signature signature = Signature.getInstance(input.hashType);
        signature.initSign(privateKey);

        //sign message
        if("BASE64".equals(input.messageType)){
            byte [] messageBytes = Base64.getDecoder().decode(input.message);
            signature.update(messageBytes);
        }else{
            signature.update(input.message.getBytes("UTF-8"));
        }

        byte[] signedBytes = signature.sign();

        //generate signature
        result.signatureBase64 = Base64.getEncoder().encodeToString(signedBytes);
        result.executionInfo = "SUCCESS";

} catch (Exception e) {

result.executionInfo = e.getMessage();

System.out.println("Error Details:" + e.getMessage());

}

return result;

}

//For FPS

public static byte[] getDigestBytes (String message) throws Exception {

MessageDigest digest = MessageDigest.getInstance("SHA-256");

digest.update (message.getBytes());

byte[] message_digest = digest.digest();

return message_digest;
}

public Result handleRequest (Input input) throws Exception {

logger.log(Level.INFO, "OIC message:", input.message);

logger.log (Level.INFO, "OIC actionType:", input.actionType);

Result result = null;

if ("SIGN".equals(input.actionType)) {

result = signMessage (input);

} else if ("VERIFY".equals(input.actionType)) {

result = verifyMessage(input);

} else {

result = new Result();

result.executionInfo = "ERROR: No proper action found, possible value "

+ "is VERIFY or SIGN recieved value:"

+ input.actionType;
}

return result;

}}

For online testing we can use below code:
public static void main(String[] args) {

    Input input = new Input();
    input.message =  "base64 encrypted message";

    input.actionType = "VERIFY";
    input.messageType = "BASE64";
    input.hashType = "SHA256withRSA";
    input.signatureBase64 = "Base64 encoded signature";

    input.publicKeyBase64 =   "Public key";

    try {
        RSASignVerify service = new RSASignVerify();
        Result result = service.handleRequest(input);

        System.out.println(result.executionInfo);

        System.out.println("Signature: " + result.signatureBase64);
        System.out.println("Verify Result: " + result.verifyResult);
        System.out.println("Execution Info: " + result.executionInfo);
    } catch (Exception e) {
        e.printStackTrace();
    }
}


Code screenshots:







Sunday, April 26, 2026

OIC - OCI function Java code to encrypt and decrypt using AES key

Please find the below working code:

Working Function code:

package com.test .fn;

import javax.crypto.Cipher;

import javax.crypto.spec.IvParameterSpec;

import javax.crypto.spec.SecretKeySpec;

import java.util.Base64;

import java.util.logging.*;

import java.security.SecureRandom;

public class AESEncryptDecrypt {

    private static final Logger logger = Logger.getLogger(AESEncryptDecrypt.class.getName());

    public static class Input {

        public String message;

        public String secretKeyBase64;

        public String ivBase64;

        public String aesMode; // AES/CBC/PKCS5Padding or AES/ECB/PKCS5Padding

        public String actionType; //ENCRYPT or DECRYPT

    }

    public static class Result {

        public String message;

        public String salt;

        public String wechataeskey;

        public String executionInfo;

    }

    public Result handleRequest(Input input) {

        logger.log(Level.INFO, "OIC - message:", input.message);

        logger.log(Level.INFO, "OIC - secretKeyBase64:", input.secretKeyBase64);

        logger.log(Level.INFO, "OIC - ivBase64", input.ivBase64);

        logger.log(Level.INFO, "OIC - aesMode:", input.aesMode);

        logger.log(Level.INFO, "OIC - actionType:", input.actionType);

        Result result = null;

if ("DECRYPT".equals(input.actionType)) {

    result = decryptMyMessage(input);

} else if ("ENCRYPT".equals(input.actionType)) {

    result = encryptMyMessage(input);

} else {

    result = new Result();

    result.executionInfo = "ERROR: No proper action found , possible value is ENCRYPT or DECRYPT , recieved value:" + input.actionType;

}

return result;

}

// Generate random 16-byte IV for AES/CBC

public static IvParameterSpec generateIV() {

    byte[] iv = new byte[16]; // 128-bit IV

    new SecureRandom().nextBytes(iv);

    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

    return ivParameterSpec;

}

public Result encryptMyMessage(Input input) {

    Result result = new Result();

    try {

        byte[] decodedKey = null;

        if (input.secretKeyBase64 == null) {

            // Generate 16-digit random numeric string

            String keyString = generateRandomDigits(16);

            //System.out.println("Generated 16-digit AES key: " + keyString);

            // Convert to byte array (each digit becomes 1 byte, 16 bytes total = 128 bits)

            result.wechataeskey = keyString;

            decodedKey = keyString.getBytes("UTF-8");

        } else {

            // Decode the base64 encoded string

            decodedKey = Base64.getDecoder().decode(input.secretKeyBase64);

        }

byte[] messageBytes = input.message.getBytes("UTF-8");

// Create a SecretKeySpec for the AES key

SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, "AES");

// Create a Cipher instance for AES

Cipher cipher = Cipher.getInstance(input.aesMode);

if (input.aesMode.contains("CBC")) {

    //AES/CBC/PKCS5Padding required IV

    IvParameterSpec ivParameterSpec = generateIV();

    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

    result.salt = Base64.getEncoder().encodeToString(ivParameterSpec.getIV());

} else {

    //AES/ECB/PKCS5Padding do not require IV

    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

}

// Decrypt the message

byte[] originalBytes = cipher.doFinal(messageBytes);

String encodedString = Base64.getEncoder().encodeToString(originalBytes);

result.message = encodedString;

//String originalMessage = =new String(originalBytes);

result.executionInfo = "SUCCESS";

} catch(Exception e) {

    result.executionInfo = e.getMessage();

    logger.log(Level.INFO, "Error Details:", e.getMessage());

}

return result;

}

public Result decryptMyMessage(Input input) {

    Result result = new Result();

    generateIV();

    try {

        // Decode the base64 encoded string

        byte[] decodedKey = Base64.getDecoder().decode(input.secretKeyBase64);

        byte[] encryptedBytes = Base64.getDecoder().decode(input.message);

        // Create a SecretKeySpec for the AES key

        SecretKeySpec secretKeySpec = new SecretKeySpec(decodedKey, "AES");

        // Create a Cipher instance for AES

        Cipher cipher = Cipher.getInstance(input.aesMode);

        if (input.aesMode.contains("CBC")) {

            //AES/CBC/PKCS5Padding required IV

            byte[] decodedIV = Base64.getDecoder().decode(input.ivBase64);

            IvParameterSpec ivParameterSpec = new IvParameterSpec(decodedIV);

            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

        } else {

            //AES/ECB/PKCS5Padding do not require IV

            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);

        }

        // Decrypt the message

        byte[] originalBytes = cipher.doFinal(encryptedBytes);

        String encodedString = Base64.getEncoder().encodeToString(originalBytes);

        result.message = encodedString;

        //String originalMessage = =new String(originalBytes);

        result.executionInfo = "SUCCESS";

    } catch(Exception e) {

        result.executionInfo = e.getMessage();

        logger.log(Level.INFO, "Error Details:", e.getMessage());

    }

    return result;

}

// Wechat, Generate a random string of digits for AES Key

public static String generateRandomDigits(int length) {

    SecureRandom random = new SecureRandom();

    StringBuilder sb = new StringBuilder(length);

    for (int i = 0; i < length; i++) {

        sb.append(random.nextInt(10)); // 0-9

    }

    return sb.toString();

}

public static void main(String[] args) {

    AESEncryptDecrypt service = new AESEncryptDecrypt();

    Input input = new Input();

    input.message = "put encrypted cyper message";

    // Base64 for "1234567890123456"

    input.secretKeyBase64 = "Put base64 encoded secret key";

    input.ivBase64 = "base63 encode salt ot IV";

    input.aesMode = "AES/CBC/PKCS5Padding";

    input.actionType = "DECRYPT";

    Result result = service.handleRequest(input);

    // Print output

    System.out.println("=== RESULT ===");

    System.out.println("Message: " + result.message);

    System.out.println("Salt: " + result.salt);

    System.out.println("WeChat AES Key: " + result.wechataeskey);

    System.out.println("Execution Info: " + result.executionInfo);

}

}

Screenshots:






Test online tool :

https://www.onlinegdb.com/online_java_compiler#



OIC - Secure Payload Handling in OIC using OCI Vault & Functions (AES + RSA) | Message level encryprion/decryption and signing/verification

Work in progress...

Overview

This blog covers a secure and scalable design pattern in Oracle Integration Cloud (OIC) where:

  • Incoming payload is AES encrypted and RSA signed
  • Keys are fetched from OCI Vault
  • Cryptographic operations are handled via OCI Functions
  • Response is encrypted and signed if required before sending back

Architecture

Source
 ↓ (AES Encrypted + RSA Signed)
Main Integration
 ↓
Crypto Integration
   → Fetch keys from OCI Vault
   → Call Function (AES Decrypt)
   → Call Function (RSA Verify)
 ↓
Main Integration
   → Call Target
   ← Response
 ↓
Crypto Integration
   → Call Function (AES Encrypt)
→ Call Function ( RSA Signed) optional ↓ Source (Encrypted and signed Response)

OCI Functions: 
   - Function 1: AES Encrypt/Decrypt
   - Function 2: RSA Sign/Verify

Scenarios:

Scenario 1:  Source data is AES encrypted. In OIC, we decrypt the data and use and later on we encrypt the response and send back to Source.

Scenario 2: Source data is RSA signed. Need to verify request message and sign to send response back


Scenario 3:  source data is in AES encrypted, cipher key = rsa encrypted(aes key), sign key rsa key, Need to verify the message and decrypt cipher key as rsa decryprion to get AES key which to use to decrypt the data/message.

RSA key Encryption Decryption:

AES Key Encryption Decryption:

RSA SIGN Verify:

End-to-End Flow:

Step 1: Receive Request (Main Integration)

  • Expose REST API
  • Input contains:
    • Encrypted payload (Base64)
    • Signature
    • Salt or IV
Why Salt or IV required?
TBD

➡️ Call Crypto Integration for processing


Step 2: Crypto Processing Integrations

This integration acts as a central reusable crypto layer.

2.1 Fetch Keys from OCI Vault

  • Retrieve:
    • AES Secret Key
    • RSA Private/Public Keys
  • Use secure REST call / OCI SDK

Ensures no key is hardcoded in OIC


2.2 Call OCI Function – Decrypt

  • Pass encrypted payload + key reference
  • Function performs:
    • Base64 decode
    • AES decryption

Returns: Plain payload


2.3 Call OCI Function – RSA Verify

  • Pass payload + signature + public key
  • Function validates signature

Condition:

  • Valid → proceed
  • Invalid → throw fault

Step 3: Return Decrypted Data to Main Integration

  • Crypto Integration sends verified plain payload back

Step 4: Business Processing (Main Integration - 1)

  • Transform data
  • Call target system
  • Receive response

Step 5: Encrypt Response

Main Integration again calls Crypto Integration (2)

5.1 Call OCI Function – AES Encrypt

  • Encrypt response payload
  • Base64 encode

No RSA signing required for response


Step 6: Send Response

  • Return encrypted response to source system

Conclusion

This approach provides a clean, secure, and enterprise-ready pattern in OIC by combining:

  • OCI Vault for secure key management
  • OCI Functions for cryptographic operations
  • Reusable integrations for maintainability

A perfect design for handling sensitive real-time integrations at scale.


Thursday, April 23, 2026

OIC File Handling – Removing .pgp and Preserving .csv (Dynamic File Name Logic) | use of ast-index-within-string() function

๐Ÿ“Œ Problem Statement

In Oracle Integration Cloud (OIC), while working with Stage File, we often receive source files like:

a.b.c.csv.pgp ๐Ÿ” (encrypted file)

a.b.c.csv ๐Ÿ“„ (plain file)

๐ŸŽฏ Requirement

If file = a.b.c.csv.pgp → Target should be a.b.c.csv

If file = a.b.c.csv → Keep as a.b.c.csv

⚠️ Challenge

Handling multiple dots (.) in file names:

Simple logic may break

Functions like last-index-of() (or OIC equivalent) may not always behave as expected in mapper

Approach 1: Nested substring-before/after (Working & Stable).

๐Ÿ’ป Code Snippet

XML

fn:concat(

  fn:substring-before($FileName, '.'),

  '.',

  fn:substring-before(fn:substring-after($FileName, '.'), '.'),

  '.',

  fn:substring-before(fn:substring-after(fn:substring-after($FileName, '.'), '.'), '.'),

  '.csv'

)


✔️ Behavior

Extracts each part between dots

Reconstructs filename ending with .csv

๐Ÿ‘ Advantages

Works consistently in OIC mapper

No dependency on special functions

๐Ÿ‘Ž Disadvantages

Not dynamic (hardcoded for 3 segments like a.b.c)

Breaks if file structure changes (e.g., a.b.c.d.csv.pgp)

Approach 2: Using oraext:last-index-within-string (Dynamic but Risky)

๐Ÿ’ป Code Snippet

XML

substring(

  $filename,

  1,

  oraext:last-index-within-string($filename, '.')

)


✔️ Behavior

Dynamically trims extension

Works for any filename length

๐Ÿ‘ Advantages

Fully dynamic

Handles multiple dots easily

๐Ÿ‘Ž Disadvantages

❌ In OIC mapper, sometimes does not evaluate correctly

Can fail depending on context (Stage File / namespaces)

Less predictable compared to substring chaining

๐Ÿง  Recommended Hybrid Logic

๐Ÿ‘‰ Best practical approach:

Use substring logic when:

File pattern is fixed (like a.b.c.csv.pgp)

Use last-index logic when:

File pattern is dynamic

Tested properly in your integration

๐Ÿš€ Pro Tip

If your only goal is to remove .pgp, a simpler and safer approach:

XML

fn:replace($filename, '.pgp', '')

✔️ Works for both cases:

a.b.c.csv.pgp → a.b.c.csv

a.b.c.csv → unchanged

๐Ÿงพ Conclusion

OIC file handling becomes tricky with multiple dots

substring-before → stable but rigid

last-index-within-string → flexible but unreliable in some cases

๐ŸŽฏ Best solution depends on your file pattern stability

OIC CCS Utility Adapter – Misleading “Client ID Wrong” Error (Actual Issue: Catalog Not Configured)

๐Ÿ“Œ Overview

While configuring a CCS (Customer Cloud Service) / Utilities Adapter connection in Oracle Integration Cloud (OIC) using Client Credentials, you might encounter an error stating:

❌ “Client ID is invalid” or “Client credentials are incorrect”

At first glance, this looks like an authentication issue—but that’s not always the case.

This blog explains a real scenario where the credentials were correct, but the actual issue was missing Web Service Catalog configuration in CCS.

⚠️ The Problem Statement

You create an OIC connection using:

Security Policy: OAuth Client Credentials

Correct Client ID & Secret

While testing the connection:

❌ Error: Invalid Client ID / Authentication Failed

Even after rechecking:

Credentials ✔️

Token URL ✔️

Scope ✔️

Still failing.

๐Ÿง  Root Cause (Hidden Issue)

The actual issue was:

๐Ÿšจ Web Service Catalog was NOT configured in the CCS (Utilities) portal

Without this configuration:

OIC cannot discover or invoke backend services

The adapter fails internally

And misleadingly throws authentication-related errors

๐Ÿ“– What is Web Service Catalog?

The Web Service Catalog in Oracle Utilities defines:

Which REST services are exposed

Which services OIC can access via the Utilities Adapter

Without it, even valid credentials won’t help.

๐Ÿ› ️ Fix: Configure Catalog in CCS

Follow these steps:

1️⃣ Login to CCS / Utilities Portal

2️⃣ Navigate to: Admin → Integration / W → Web Service Catalog

3️⃣ Select: REST Web Service Class

4️⃣ Add Required Services:

W1-ServiceCall → Service Call Maintenance

W1-Communication → Communication Maintenance


๐Ÿ‘‰ These are essential inbound services for OIC communication.

๐Ÿ” Retest in OIC

After configuring the catalog:

Go back to OIC Connection

Click Test

✅ Connection should now succeed

๐Ÿ’ก Key Takeaways

❌ Don’t trust error messages blindly in OIC

๐Ÿ” “Invalid Client ID” ≠ Always authentication issue

⚙️ Always verify:

Catalog configuration in CCS

Required REST services availability

๐Ÿš€ Pro Tip

When working with Oracle Utilities Adapter:

Always validate backend readiness (Catalog + Services) before debugging authentication

If error feels misleading → check service exposure first

๐Ÿงพ Conclusion

This issue is a classic example where:

Everything looks like a security problem

But turns out to be a configuration gap in backend

Fixing the Web Service Catalog resolved the issue completely—without changing any credentials.

Reference:

https://docs.oracle.com/en/industries/energy-water/cloud-integrations/24b/ccs-wacs-configuration-guide/CCS-WACS-CONFIGURATION-GUIDE/




Friday, April 17, 2026

OIC XSLT: Execute Only When At Least One Field Has Value and None Are Blank

๐Ÿ”ท OIC XSLT: Validate Fields Before Executing Logic

๐Ÿ”น Requirement

Fields: field1, field2, field3, field4, field5

✔ Execute only when: At least one field has a value

AND no provided field is empty (including spaces)

๐Ÿ”น Final XSLT

XML

<xsl:if test="

(

  string-length(normalize-space(field1)) &gt; 0 or

  string-length(normalize-space(field2)) &gt; 0 or

  string-length(normalize-space(field3)) &gt; 0 or

  string-length(normalize-space(field4)) &gt; 0 or

  string-length(normalize-space(field5)) &gt; 0

)

and

(

  (not(field1) or string-length(normalize-space(field1)) &gt; 0) and

  (not(field2) or string-length(normalize-space(field2)) &gt; 0) and

  (not(field3) or string-length(normalize-space(field3)) &gt; 0) and

  (not(field4) or string-length(normalize-space(field4)) &gt; 0) and

  (not(field5) or string-length(normalize-space(field5)) &gt; 0)

)

">

   <!-- Execute logic -->

</xsl:if>

๐Ÿ”น Key Idea (1 Line)

๐Ÿ‘‰ Run only if:

At least one field has non-space value AND no field is empty/blank

๐Ÿ”น Why normalize-space() Matters

Converts "   " → ""

Prevents false positives from whitespace

Ensures clean validation in OIC payloads

๐Ÿ”น Quick Examples

Input == Result

<root/>❌ Skip

<field1>   </field1> ❌ Skip

<field1>ABC</field1> ✅ Execute

<field1>ABC</field1><field2> </field2> ❌ Skip


Wednesday, April 15, 2026

OIC - Handling Base64 Encoded JSON NXSD Parsing Issue in Oracle Integration Cloud (OIC)

๐Ÿ“Œ Problem Statement

In a Real-Time REST integration in Oracle Integration Cloud, the source system sends Base64 encoded JSON.

Flow:

Receive Base64 payload

Decode using oraext:decodeBase64()

Pass to Stage File → Read as JSON

Issue Faced

After decoding, the JSON becomes invalid because:

The closing curly brace } is missing

This causes NXSD parsing errors in Stage File

๐Ÿ” Root Cause

During decoding or transformation:

Extra whitespace / formatting issues

Improper encoding at source

OIC string handling edge cases

๐Ÿ‘‰ Result: JSON becomes malformed, especially missing }

๐Ÿ’ก Solution Approach

Instead of directly parsing decoded JSON:

✅ Step 1: Decode Base64

✅ Step 2: Clean the JSON string

✅ Step 3: Validate & fix missing closing brace

✅ Step 4: Re-encode to Base64

✅ Step 5: Pass as Opaque to Stage File

๐Ÿ› ️ Implementation (XSLT Logic)

Step 1: Decode Base64

Xslt

<xsl:variable name="decoded"

 select="oraext:decodeBase64(/nssrcmpr:execute/ns16:request-wrapper/ns16:message)"/>

Step 2: Clean unwanted whitespace

Xslt

<xsl:variable name="cleaned"

  select="replace($decoded, '(:\s*&quot;)\s+', '$1')"/>

๐Ÿ‘‰ Removes unnecessary spaces after : in JSON

Step 3: Fix Missing Closing Brace

Xslt

<xsl:variable name="finalJson">

  <xsl:choose>

    <xsl:when test="contains($cleaned, '}')">

      <xsl:value-of select="$cleaned"/>

    </xsl:when>

    <xsl:otherwise>

      <xsl:value-of select="concat($cleaned, '}')"/>

    </xsl:otherwise>

  </xsl:choose>

</xsl:variable>

๐Ÿ‘‰ Ensures JSON is always valid

Step 4: Encode Back to Base64

Xslt

<xsl:value-of select="oraext:encodeBase64($finalJson)"/>

๐Ÿ”„ Integration Flow Design

๐Ÿงฉ OIC Flow Steps

REST Trigger

Stage File (Write File)

Write as Opaque

Use above XSLT

Stage File (Read File)

Now JSON is valid

Parse using NXSD schema

Continue processing…

๐ŸŽฏ Why Opaque Handling Works

Using opaque avoids:

Early validation failures

NXSD parsing errors on invalid JSON

๐Ÿ‘‰ You fix JSON before parsing

⚠️ Best Practices

Always validate decoded payload:

Use contains() or ends-with() for }

Log decoded payload (for debugging)

Avoid direct parsing of decoded Base64 without validation

๐Ÿ Conclusion

Handling Base64 JSON in OIC can be tricky due to:

Encoding inconsistencies

Transformation side effects

๐Ÿ‘‰ The decode → clean → fix → re-encode → stage as opaque pattern is a reliable solution.

Code screenshots:

Stage write:




Code xslt:
Read json:




Code snippet:

<xsl:template match="/" xml:id="id_11">

  <nstrgmpr:Write xml:id="id_12">

    <ns31:opaqueElement>

      <!-- Step 1: Decode -->

      <xsl:variable name="decoded"     select="oraext:decodeBase64(/nssrcmpr:execute/ns16:request-wrapper/ns16:message)"/>

      <!-- Step 2: Clean whitespace after ":" -->

      <xsl:variable name="cleaned"

        select="replace($decoded, '(:\s*&quot;)\s+', '$1')"/>

      <!-- Step 3: Check and fix closing brace -->

      <xsl:variable name="finalJson">

        <xsl:choose>

          <xsl:when test="contains($cleaned, '}')">

            <xsl:value-of select="$cleaned"/>

          </xsl:when>

          <xsl:otherwise>

            <xsl:value-of select="concat($cleaned, '}')"/>

          </xsl:otherwise>

        </xsl:choose>

      </xsl:variable>

      <!-- Step 4: Encode back -->

      <xsl:value-of select="oraext:encodeBase64($finalJson)"/>

    </ns31:opaqueElement>

  </nstrgmpr:Write>

</xsl:template>


Monday, April 13, 2026

OIC - Handling Multiple Stub & Payment Matching in XSLT (OIC Optimization)

๐Ÿš€ Handling Multiple Stub & Payment Matching in XSLT (OIC Optimization)

๐Ÿ“Œ Problem Context

We receive:

Multiple StubRecords

Multiple PaymentRecords

Same Transaction Number across records

๐Ÿ‘‰ Goal:

Correctly match multiple stubs with multiple payments

Ensure accurate mapping

Avoid 120 sec XSLT timeout

⚠️ Issue with Traditional Matching

XML

//ns25:PaymentRecord[ns25:TransactionNumber = $txn]

❌ Fetches all records

❌ Incorrect matching

❌ Slow → Timeout

✅ Optimized Steps Using xsl:key

๐Ÿ”‘ Step 1: Define Keys

XML

<xsl:key name="stubKey"

         match="ns25:StubRecord"

         use="concat(ns25:TransactionNumber,'|',ns25:OperatorID)"/>


<xsl:key name="payKey"

         match="ns25:PaymentRecord"

         use="concat(ns25:TransactionNumber,'|',normalize-space(ns25:Filler3))"/>


<xsl:key name="payKeyExact"

         match="ns25:PaymentRecord"

         use="concat(ns25:TransactionNumber,'|',normalize-space(ns25:Filler3),'|',ns25:PaymentAmount)"/>

๐Ÿ”„ Step 2: Loop Through Stub Records

XML

<xsl:for-each select="$ReadSourceFile/.../ns25:StubRecord">

๐Ÿงฎ Step 3: Extract Values

XML

<xsl:variable name="txn" select="ns25:TransactionNumber"/>

<xsl:variable name="op" select="ns25:OperatorID"/>

<xsl:variable name="amt" select="ns25:PaidAmount"/>

๐Ÿ”— Step 4: Build Composite Keys

XML

<xsl:variable name="stubKeyVal" select="concat($txn,'|',$op)"/>

<xsl:variable name="payKeyVal" select="concat($txn,'|',$op)"/>

<xsl:variable name="payKeyExactVal" select="concat($txn,'|',$op,'|',$amt)"/>

Step 5: Fetch Using Key

XML

<xsl:variable name="sameStub" select="key('stubKey',$stubKeyVal)"/>

<xsl:variable name="payments" select="key('payKey',$payKeyVal)"/>

<xsl:variable name="paymentsExact" select="key('payKeyExact',$payKeyExactVal)"/>

๐Ÿ” Step 6: Handle Multiple Stub Records

XML

<xsl:if test="count($sameStub) > 1">

๐Ÿ‘‰ Ensures:

Only process when multiple stubs exist for same transaction + operator

Avoid incorrect or duplicate mapping

๐ŸŽฏ Step 7: Choose Best Payment Match

XML

<xsl:variable name="finalPayments"

    select="if (exists($paymentsExact)) then $paymentsExact else $payments"/>

๐Ÿ‘‰ Prefer:

Exact match (txn + operator + amount)

Else fallback

๐Ÿ”„ Step 8: Map & Merge Data

XML

<xsl:value-of select="normalize-space(ns25:StubAccountNumber)"/>


<xsl:value-of select="oraext:create-delimited-string($finalPayments/ns25:ChequeNumber,'|')"/>

๐Ÿ“ค Step 9: Generate Output

๐Ÿ‘‰ One output per valid stub, enriched with matched payments

๐ŸŽฏ Final One-Line Summary

๐Ÿ‘‰ “Use xsl:key with composite keys to accurately match multiple stub and payment records for the same transaction, handle multi-stub scenarios using count logic, and ensure optimized performance to avoid XSLT timeout in OIC.”

Code Screenshots:





Featured Post

OIC - OCI Java function code for RSA Encryption and Decryption

Function Java code: package com.test.fn; import java.security.*; import java.security.spec.*; import java.util.Base64; import javax.crypto.C...