add java pairing test (#23714)

diff --git a/examples/java-matter-controller/java/src/com/matter/controller/Main.java b/examples/java-matter-controller/java/src/com/matter/controller/Main.java
index 52c84f5..5478add 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/Main.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/Main.java
@@ -113,5 +113,6 @@
     } catch (Exception e) {
       System.out.println("Run command failed with exception: " + e.getMessage());
     }
+    controller.shutdownCommissioning();
   }
 }
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java
index 8cc53d2..559c244 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/Argument.java
@@ -112,11 +112,21 @@
         String str = (String) mValue;
         isValidArgument = value.equals(str);
         break;
+      case NUMBER_INT16:
+        AtomicInteger numShort = (AtomicInteger) mValue;
+        numShort.set(Integer.parseInt(value));
+        isValidArgument = (numShort.intValue() >= mMin && numShort.intValue() <= mMax);
+        break;
       case NUMBER_INT32:
         AtomicInteger num = (AtomicInteger) mValue;
         num.set(Integer.parseInt(value));
         isValidArgument = (num.intValue() >= mMin && num.intValue() <= mMax);
         break;
+      case NUMBER_INT64:
+        AtomicLong numLong = (AtomicLong) mValue;
+        numLong.set(Long.parseLong(value));
+        isValidArgument = (numLong.intValue() >= mMin && numLong.intValue() <= mMax);
+        break;
       case ADDRESS:
         try {
           IPAddress ipAddress = (IPAddress) mValue;
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/CommandManager.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/CommandManager.java
index edcc61c..ad6cd68 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/CommandManager.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/CommandManager.java
@@ -89,10 +89,11 @@
       }

     }

 

-    String[] temp = Arrays.copyOfRange(args, 1, args.length);

+    // need skip over binary and command name and only get arguments

+    String[] temp = Arrays.copyOfRange(args, 2, args.length);

 

     try {

-      command.initArguments(args.length - 1, temp);

+      command.initArguments(temp.length, temp);

       command.run();

     } catch (IllegalArgumentException e) {

       System.out.println("Arguments init failed with exception: " + e.getMessage());

diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/IPAddress.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/IPAddress.java
index 814a9c7..d419db4 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/IPAddress.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/IPAddress.java
@@ -17,4 +17,8 @@
   public String toString() {
     return address.toString();
   }
+
+  public String getHostAddress() {
+    return address.getHostAddress();
+  }
 }
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java
index 18f9cec..9aefec5 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/common/MatterCommand.java
@@ -41,6 +41,7 @@
   private final AtomicLong mCommissionerNodeId = new AtomicLong();
   private final AtomicBoolean mUseMaxSizedCerts = new AtomicBoolean();;
   private final AtomicBoolean mOnlyAllowTrustedCdKeys = new AtomicBoolean();;
+  private Optional<String> mTestResult = Optional.empty();
 
   public MatterCommand(
       ChipDeviceController controller, String commandName, CredentialsIssuer credIssuerCmds) {
@@ -56,6 +57,8 @@
     this.mCredIssuerCmds = Optional.ofNullable(credIssuerCmds);
     this.mChipDeviceController = controller;
 
+    // TODO: Add support to enable the below optional arguments
+    /*
     addArgument(
         "paa-trust-store-path",
         mPaaTrustStorePath,
@@ -87,6 +90,7 @@
         mOnlyAllowTrustedCdKeys,
         "Only allow trusted CD verifying keys (disallow test keys). If not provided or 0 (\"false\"), untrusted CD "
             + "verifying keys are allowed. If 1 (\"true\"), test keys are disallowed.");
+    */
   }
 
   // This method returns the commissioner instance to be used for running the command.
@@ -97,9 +101,10 @@
   /////////// Command Interface /////////
   @Override
   public void run() throws Exception {
-    maybeSetUpStack();
+    // TODO: setup chip storage from Java, currently it is using example one from chip-tool
+    // maybeSetUpStack();
     runCommand();
-    maybeTearDownStack();
+    // maybeTearDownStack();
   }
 
   protected abstract void runCommand();
@@ -113,4 +118,40 @@
   private void maybeTearDownStack() {
     // ToDo:We need to call DeviceController::Shutdown()
   }
+
+  public void setTestResult(String result) {
+    mTestResult = Optional.of(result);
+  }
+
+  public void expectSuccess(long timeout) {
+    expectResult("Success", timeout);
+  }
+
+  private void expectResult(String expectedResult, long timeout) {
+    long start = System.currentTimeMillis();
+    while (!mTestResult.isPresent())
+      try {
+        if (System.currentTimeMillis() > (start + timeout)) {
+          throw new RuntimeException("timeout!");
+        }
+        Thread.sleep(100);
+      } catch (InterruptedException ex) {
+      }
+
+    if (!mTestResult.isPresent()) {
+      throw new RuntimeException("received empty test result");
+    }
+
+    if (!mTestResult.get().equals(expectedResult)) {
+      if (!expectedResult.equals("Success")) {
+        System.out.format(
+            "%s command failed:%n    Expected: %s%n    Got: %s%n",
+            getName(), expectedResult, mTestResult);
+        throw new RuntimeException(getName());
+      } else {
+        System.out.format("%s command failed: %s%n", getName(), mTestResult.get());
+      }
+    }
+    mTestResult = Optional.empty();
+  }
 }
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongCommand.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongCommand.java
index 23c4cb5..928ba95 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongCommand.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongCommand.java
@@ -4,6 +4,8 @@
 import com.matter.controller.commands.common.CredentialsIssuer;
 
 public final class PairOnNetworkLongCommand extends PairingCommand {
+  private static final int MATTER_PORT = 5540;
+
   public PairOnNetworkLongCommand(ChipDeviceController controller, CredentialsIssuer credsIssue) {
     super(
         controller,
@@ -15,5 +17,16 @@
   }
 
   @Override
-  protected void runCommand() {}
+  protected void runCommand() {
+    currentCommissioner()
+        .pairDeviceWithAddress(
+            getNodeId(),
+            getRemoteAddr().getHostAddress(),
+            MATTER_PORT,
+            getDiscriminator(),
+            getSetupPINCode(),
+            null);
+    currentCommissioner().setCompletionListener(this);
+    expectSuccess(getTimeoutMillis());
+  }
 }
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java
index ead0912..323c3bd 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairingCommand.java
@@ -28,14 +28,15 @@
 import java.util.concurrent.atomic.AtomicInteger;

 import java.util.concurrent.atomic.AtomicLong;

 

-public abstract class PairingCommand extends MatterCommand {

+public abstract class PairingCommand extends MatterCommand

+    implements ChipDeviceController.CompletionListener {

   private PairingModeType mPairingMode = PairingModeType.NONE;

   private PairingNetworkType mNetworkType = PairingNetworkType.NONE;

   private DiscoveryFilterType mFilterType = DiscoveryFilterType.NONE;

   private final IPAddress mRemoteAddr;

   private final AtomicLong mNodeId = new AtomicLong();

   private final AtomicLong mDiscoveryFilterCode = new AtomicLong();

-  private final AtomicInteger mTimeout = new AtomicInteger();

+  private final AtomicLong mTimeoutMillis = new AtomicLong();

   private final AtomicBoolean mDiscoverOnce = new AtomicBoolean();

   private final AtomicBoolean mUseOnlyOnNetworkDiscovery = new AtomicBoolean();

   private final AtomicInteger mRemotePort = new AtomicInteger();

@@ -47,6 +48,94 @@
   private final StringBuffer mOnboardingPayload = new StringBuffer();

   private final StringBuffer mDiscoveryFilterInstanceName = new StringBuffer();

 

+  public long getNodeId() {

+    return mNodeId.get();

+  }

+

+  public int getSetupPINCode() {

+    return mSetupPINCode.get();

+  }

+

+  public int getDiscriminator() {

+    return mDiscriminator.get();

+  }

+

+  public long getTimeoutMillis() {

+    return mTimeoutMillis.get();

+  }

+

+  @Override

+  public void onConnectDeviceComplete() {

+    System.out.println("onConnectDeviceComplete");

+  }

+

+  @Override

+  public void onStatusUpdate(int status) {

+    System.out.println("onStatusUpdate with status: " + status);

+  }

+

+  @Override

+  public void onPairingComplete(int errorCode) {

+    System.out.println("onPairingComplete with error code: " + errorCode);

+    if (errorCode != 0) {

+      setTestResult("Failure");

+    }

+  }

+

+  @Override

+  public void onPairingDeleted(int errorCode) {

+    System.out.println("onPairingDeleted with error code: " + errorCode);

+  }

+

+  @Override

+  public void onCommissioningComplete(long nodeId, int errorCode) {

+    System.out.println("onCommissioningComplete with error code: " + errorCode);

+    if (errorCode == 0) {

+      setTestResult("Success");

+    } else {

+      setTestResult("Failure");

+    }

+  }

+

+  @Override

+  public void onReadCommissioningInfo(

+      int vendorId, int productId, int wifiEndpointId, int threadEndpointId) {

+    System.out.println("onReadCommissioningInfo");

+  }

+

+  @Override

+  public void onCommissioningStatusUpdate(long nodeId, String stage, int errorCode) {

+    System.out.println("onCommissioningStatusUpdate");

+  }

+

+  @Override

+  public void onNotifyChipConnectionClosed() {

+    System.out.println("onNotifyChipConnectionClosed");

+  }

+

+  @Override

+  public void onCloseBleComplete() {

+    System.out.println("onCloseBleComplete");

+  }

+

+  @Override

+  public void onError(Throwable error) {

+    setTestResult(error.toString());

+    System.out.println("onError with error: " + error.toString());

+  }

+

+  @Override

+  public void onOpCSRGenerationComplete(byte[] csr) {

+    System.out.println("onOpCSRGenerationComplete");

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

+      System.out.print(csr[i] + " ");

+    }

+  }

+

+  public IPAddress getRemoteAddr() {

+    return mRemoteAddr;

+  }

+

   public PairingCommand(

       ChipDeviceController controller,

       String commandName,

@@ -69,7 +158,7 @@
     this.mFilterType = filterType;

 

     try {

-      this.mRemoteAddr = new IPAddress(InetAddress.getByName("0.0.0.0"));

+      this.mRemoteAddr = new IPAddress(InetAddress.getByName("::1"));

     } catch (UnknownHostException e) {

       throw new RuntimeException(e);

     }

@@ -147,6 +236,6 @@
         break;

     }

 

-    addArgument("timeout", (short) 0, Short.MAX_VALUE, mTimeout, null);

+    addArgument("timeout", (long) 0, Long.MAX_VALUE, mTimeoutMillis, null);

   }

 }

diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp
index 80feffe..e5870f5 100644
--- a/src/controller/java/AndroidDeviceControllerWrapper.cpp
+++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp
@@ -38,8 +38,9 @@
 #include <lib/support/TestGroupData.h>
 #include <lib/support/ThreadOperationalDataset.h>
 #include <platform/KeyValueStoreManager.h>
+#ifndef JAVA_MATTER_CONTROLLER_TEST
 #include <platform/android/CHIPP256KeypairBridge.h>
-
+#endif // JAVA_MATTER_CONTROLLER_TEST
 using namespace chip;
 using namespace chip::Controller;
 using namespace chip::Credentials;
@@ -53,11 +54,13 @@
     }
     mController->Shutdown();
 
+#ifndef JAVA_MATTER_CONTROLLER_TEST
     if (mKeypairBridge != nullptr)
     {
         chip::Platform::Delete(mKeypairBridge);
         mKeypairBridge = nullptr;
     }
+#endif // JAVA_MATTER_CONTROLLER_TEST
 }
 
 void AndroidDeviceControllerWrapper::SetJavaObjectRef(JavaVM * vm, jobject obj)
@@ -75,7 +78,12 @@
 AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
     JavaVM * vm, jobject deviceControllerObj, chip::NodeId nodeId, chip::FabricId fabricId, const chip::CATValues & cats,
     chip::System::Layer * systemLayer, chip::Inet::EndPointManager<Inet::TCPEndPoint> * tcpEndPointManager,
-    chip::Inet::EndPointManager<Inet::UDPEndPoint> * udpEndPointManager, AndroidOperationalCredentialsIssuerPtr opCredsIssuerPtr,
+    chip::Inet::EndPointManager<Inet::UDPEndPoint> * udpEndPointManager,
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+    ExampleOperationalCredentialsIssuerPtr opCredsIssuerPtr,
+#else
+    AndroidOperationalCredentialsIssuerPtr opCredsIssuerPtr,
+#endif
     jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate, jbyteArray nodeOperationalCertificate,
     jbyteArray ipkEpochKey, uint16_t listenPort, uint16_t controllerVendorId, uint16_t failsafeTimerSeconds,
     bool attemptNetworkScanWiFi, bool attemptNetworkScanThread, bool skipCommissioningComplete, CHIP_ERROR * errInfoOnFailure)
@@ -124,11 +132,22 @@
     std::unique_ptr<AndroidDeviceControllerWrapper> wrapper(
         new AndroidDeviceControllerWrapper(std::move(controller), std::move(opCredsIssuerPtr)));
 
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+    if (wrapper->mExampleStorage.Init() != CHIP_NO_ERROR)
+    {
+        ChipLogError(Controller, "Init Storage failure");
+        return nullptr;
+    }
+    chip::PersistentStorageDelegate * wrapperStorage = &wrapper->mExampleStorage;
+    wrapper->SetJavaObjectRef(vm, deviceControllerObj);
+    chip::Controller::ExampleOperationalCredentialsIssuer * opCredsIssuer = wrapper->mOpCredsIssuer.get();
+#else
     chip::PersistentStorageDelegate * wrapperStorage = wrapper.get();
 
     wrapper->SetJavaObjectRef(vm, deviceControllerObj);
 
     chip::Controller::AndroidOperationalCredentialsIssuer * opCredsIssuer = wrapper->mOpCredsIssuer.get();
+#endif
 
     // Initialize device attestation verifier
     // TODO: Replace testingRootStore with a AttestationTrustStore that has the necessary official PAA roots available
@@ -177,9 +196,12 @@
         return nullptr;
     }
     initParams.opCertStore = &wrapper->mOpCertStore;
-
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+    opCredsIssuer->Initialize(wrapper->mExampleStorage);
+#else
     // TODO: Init IPK Epoch Key in opcreds issuer, so that commissionees get the right IPK
     opCredsIssuer->Initialize(*wrapper.get(), &wrapper->mAutoCommissioner, wrapper.get()->mJavaObjectRef);
+#endif
 
     Platform::ScopedMemoryBuffer<uint8_t> noc;
     if (!noc.Alloc(kMaxCHIPDERCertLength))
@@ -208,7 +230,7 @@
 
     // The lifetime of the ephemeralKey variable must be kept until SetupParams is saved.
     Crypto::P256Keypair ephemeralKey;
-
+#ifndef JAVA_MATTER_CONTROLLER_TEST
     if (rootCertificate != nullptr && nodeOperationalCertificate != nullptr && keypairDelegate != nullptr)
     {
         CHIPP256KeypairBridge * nativeKeypairBridge = wrapper->GetP256KeypairBridge();
@@ -245,6 +267,7 @@
         setupParams.controllerNOC  = chip::ByteSpan(wrapper->mNocCertificate.data(), wrapper->mNocCertificate.size());
     }
     else
+#endif // JAVA_MATTER_CONTROLLER_TEST
     {
         ChipLogProgress(Controller,
                         "No existing credentials provided: generating ephemeral local NOC chain with OperationalCredentialsIssuer");
diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h
index c142186..518596b 100644
--- a/src/controller/java/AndroidDeviceControllerWrapper.h
+++ b/src/controller/java/AndroidDeviceControllerWrapper.h
@@ -29,10 +29,16 @@
 #include <credentials/PersistentStorageOpCertStore.h>
 #include <credentials/attestation_verifier/DacOnlyPartialAttestationVerifier.h>
 #include <lib/support/TimeUtils.h>
-#include <platform/android/CHIPP256KeypairBridge.h>
 #include <platform/internal/DeviceNetworkInfo.h>
 
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+#include <controller/ExampleOperationalCredentialsIssuer.h>
+#include <controller/ExamplePersistentStorage.h>
+#else
 #include "AndroidOperationalCredentialsIssuer.h"
+#include <platform/android/AndroidChipPlatform-JNI.h>
+#include <platform/android/CHIPP256KeypairBridge.h>
+#endif // JAVA_MATTER_CONTROLLER_TEST
 
 /**
  * This class contains all relevant information for the JNI view of CHIPDeviceController
@@ -50,6 +56,7 @@
     jobject JavaObjectRef() { return mJavaObjectRef; }
     jlong ToJNIHandle();
 
+#ifndef JAVA_MATTER_CONTROLLER_TEST
     /**
      * Returns a CHIPP256KeypairBridge which can be used to delegate signing operations
      * to a KeypairDelegate in the Java layer. Note that this will always return a pointer
@@ -63,6 +70,7 @@
         }
         return mKeypairBridge;
     }
+#endif // JAVA_MATTER_CONTROLLER_TEST
 
     void CallJavaMethod(const char * methodName, jint argument);
     CHIP_ERROR InitializeOperationalCredentialsIssuer();
@@ -108,7 +116,11 @@
         return reinterpret_cast<AndroidDeviceControllerWrapper *>(handle);
     }
 
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+    using ExampleOperationalCredentialsIssuerPtr = std::unique_ptr<chip::Controller::ExampleOperationalCredentialsIssuer>;
+#else
     using AndroidOperationalCredentialsIssuerPtr = std::unique_ptr<chip::Controller::AndroidOperationalCredentialsIssuer>;
+#endif
 
     /**
      * Initializes a new CHIPDeviceController using the given parameters, and returns a pointer to the
@@ -147,12 +159,21 @@
                 const chip::CATValues & cats, chip::System::Layer * systemLayer,
                 chip::Inet::EndPointManager<chip::Inet::TCPEndPoint> * tcpEndPointManager,
                 chip::Inet::EndPointManager<chip::Inet::UDPEndPoint> * udpEndPointManager,
-                AndroidOperationalCredentialsIssuerPtr opCredsIssuer, jobject keypairDelegate, jbyteArray rootCertificate,
-                jbyteArray intermediateCertificate, jbyteArray nodeOperationalCertificate, jbyteArray ipkEpochKey,
-                uint16_t listenPort, uint16_t controllerVendorId, uint16_t failsafeTimerSeconds, bool attemptNetworkScanWiFi,
-                bool attemptNetworkScanThread, bool skipCommissioningComplete, CHIP_ERROR * errInfoOnFailure);
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+                ExampleOperationalCredentialsIssuerPtr opCredsIssuer,
+#else
+                AndroidOperationalCredentialsIssuerPtr opCredsIssuer,
+#endif
+                jobject keypairDelegate, jbyteArray rootCertificate, jbyteArray intermediateCertificate,
+                jbyteArray nodeOperationalCertificate, jbyteArray ipkEpochKey, uint16_t listenPort, uint16_t controllerVendorId,
+                uint16_t failsafeTimerSeconds, bool attemptNetworkScanWiFi, bool attemptNetworkScanThread,
+                bool skipCommissioningComplete, CHIP_ERROR * errInfoOnFailure);
 
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+    chip::Controller::ExampleOperationalCredentialsIssuer * GetAndroidOperationalCredentialsIssuer()
+#else
     chip::Controller::AndroidOperationalCredentialsIssuer * GetAndroidOperationalCredentialsIssuer()
+#endif
     {
         return mOpCredsIssuer.get();
     }
@@ -161,15 +182,21 @@
     using ChipDeviceControllerPtr = std::unique_ptr<chip::Controller::DeviceCommissioner>;
 
     ChipDeviceControllerPtr mController;
-    AndroidOperationalCredentialsIssuerPtr mOpCredsIssuer;
+
     // TODO: This may need to be injected as a GroupDataProvider*
     chip::Credentials::GroupDataProviderImpl mGroupDataProvider;
     // TODO: This may need to be injected as an OperationalCertificateStore *
     chip::Credentials::PersistentStorageOpCertStore mOpCertStore;
 
-    JavaVM * mJavaVM                       = nullptr;
-    jobject mJavaObjectRef                 = nullptr;
+    JavaVM * mJavaVM       = nullptr;
+    jobject mJavaObjectRef = nullptr;
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+    ExampleOperationalCredentialsIssuerPtr mOpCredsIssuer;
+    PersistentStorage mExampleStorage;
+#else
+    AndroidOperationalCredentialsIssuerPtr mOpCredsIssuer;
     CHIPP256KeypairBridge * mKeypairBridge = nullptr;
+#endif // JAVA_MATTER_CONTROLLER_TEST
 
     // These fields allow us to release the string/byte array memory later.
     jstring ssidStr                    = nullptr;
@@ -187,8 +214,15 @@
 
     chip::Credentials::PartialDACVerifier mPartialDACVerifier;
 
-    AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller, AndroidOperationalCredentialsIssuerPtr opCredsIssuer) :
-        mController(std::move(controller)), mOpCredsIssuer(std::move(opCredsIssuer))
+    AndroidDeviceControllerWrapper(ChipDeviceControllerPtr controller,
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+                                   ExampleOperationalCredentialsIssuerPtr opCredsIssuer
+#else
+                                   AndroidOperationalCredentialsIssuerPtr opCredsIssuer
+#endif
+                                   ) :
+        mController(std::move(controller)),
+        mOpCredsIssuer(std::move(opCredsIssuer))
     {}
 };
 
diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp
index 6fbebe0..bed3ffd 100644
--- a/src/controller/java/CHIPDeviceController-JNI.cpp
+++ b/src/controller/java/CHIPDeviceController-JNI.cpp
@@ -52,7 +52,11 @@
 #include <system/SystemClock.h>
 #include <vector>
 
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+#include <controller/ExampleOperationalCredentialsIssuer.h>
+#else
 #include <platform/android/AndroidChipPlatform-JNI.h>
+#endif
 
 // Choose an approximation of PTHREAD_NULL if pthread.h doesn't define one.
 #ifndef PTHREAD_NULL
@@ -122,8 +126,10 @@
     SuccessOrExit(err);
     ChipLogProgress(Controller, "Java class references loaded.");
 
+#ifndef JAVA_MATTER_CONTROLLER_TEST
     err = AndroidChipPlatformJNI_OnLoad(jvm, reserved);
     SuccessOrExit(err);
+#endif // JAVA_MATTER_CONTROLLER_TEST
 
 exit:
     if (err != CHIP_NO_ERROR)
@@ -237,6 +243,7 @@
     JniByteArray jByteArrayIcac(env, intermediateCertificate);
     JniByteArray jByteArrayNoc(env, operationalCertificate);
 
+#ifndef JAVA_MATTER_CONTROLLER_TEST
     err = wrapper->GetAndroidOperationalCredentialsIssuer()->NOCChainGenerated(CHIP_NO_ERROR, jByteArrayNoc.byteSpan(),
                                                                                jByteArrayIcac.byteSpan(), jByteArrayRcac.byteSpan(),
                                                                                ipkOptional, adminSubjectOptional);
@@ -245,6 +252,7 @@
     {
         ChipLogError(Controller, "Failed to SetNocChain for the device: %" CHIP_ERROR_FORMAT, err.Format());
     }
+#endif // JAVA_MATTER_CONTROLLER_TEST
     return err.AsInteger();
 }
 
@@ -338,8 +346,13 @@
         bool skipCommissioningComplete     = env->CallBooleanMethod(controllerParams, getSkipCommissioningComplete);
         uint64_t adminSubject              = env->CallLongMethod(controllerParams, getAdminSubject);
 
+#ifdef JAVA_MATTER_CONTROLLER_TEST
+        std::unique_ptr<chip::Controller::ExampleOperationalCredentialsIssuer> opCredsIssuer(
+            new chip::Controller::ExampleOperationalCredentialsIssuer());
+#else
         std::unique_ptr<chip::Controller::AndroidOperationalCredentialsIssuer> opCredsIssuer(
             new chip::Controller::AndroidOperationalCredentialsIssuer());
+#endif
         wrapper = AndroidDeviceControllerWrapper::AllocateNew(
             sJVM, self, kLocalDeviceId, fabricId, chip::kUndefinedCATs, &DeviceLayer::SystemLayer(),
             DeviceLayer::TCPEndPointManager(), DeviceLayer::UDPEndPointManager(), std::move(opCredsIssuer), keypairDelegate,
@@ -572,7 +585,9 @@
     chip::DeviceLayer::StackLock lock;
     AndroidDeviceControllerWrapper * wrapper = AndroidDeviceControllerWrapper::FromJNIHandle(handle);
 
+#ifndef JAVA_MATTER_CONTROLLER_TEST
     wrapper->GetAndroidOperationalCredentialsIssuer()->SetUseJavaCallbackForNOCRequest(useCallback);
+#endif
 
     if (useCallback)
     {