-
Notifications
You must be signed in to change notification settings - Fork 213
[MOSIP] SDK-based biometric quality evaluation with SBI fallback #784
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package io.mosip.registration.dto.biometric; | ||
|
|
||
| /** | ||
| * Holds the outcome of a biometric quality evaluation, including the score, | ||
| * the source that produced it (SDK or SBI), and whether a fallback occurred. | ||
| */ | ||
| public class QualityEvaluationResult { | ||
|
|
||
| private final double score; | ||
| private final String source; | ||
| private final boolean fallback; | ||
|
|
||
| public QualityEvaluationResult(double score, String source, boolean fallback) { | ||
| this.score = score; | ||
| this.source = source; | ||
| this.fallback = fallback; | ||
| } | ||
|
|
||
| public double getScore() { | ||
| return score; | ||
| } | ||
|
|
||
| public String getSource() { | ||
| return source; | ||
| } | ||
|
|
||
| public boolean isFallback() { | ||
| return fallback; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "QualityEvaluationResult{score=" + score + ", source='" + source + "', fallback=" + fallback + "}"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,6 +91,11 @@ public enum RegistrationExceptionConstants { | |
| REG_FINGERPRINT_SCANNING_ERROR(RegistrationConstants.USER_REG_FINGERPRINT_CAPTURE_EXP_CODE+"FCS-002", "Exception while scanning fingerprints of the individual"), | ||
| REG_BIOMETRIC_QUALITY_CHECK_ERROR("REG-BQC-001", "Exception while evaluating the biometrics quality with SDK"), | ||
| REG_BIOMETRIC_QUALITY_SCORE_RANGE_ERROR("REG-BQC-002", "Exception while evaluating the biometrics quality score"), | ||
| REG_SDK_TIMEOUT("REG-BQC-003", "Biometric quality evaluation timed out. Please re-capture biometrics."), | ||
| REG_SDK_NULL_RESPONSE("REG-BQC-004", "Invalid biometric quality score received from SDK."), | ||
| REG_SDK_RUNTIME_ERROR("REG-BQC-005", "Error occurred during SDK-based quality evaluation. Please retry capture."), | ||
| REG_SBI_SCORE_MISSING("REG-BQC-006", "Default biometric quality score unavailable."), | ||
| REG_NO_QUALITY_SOURCE("REG-BQC-007", "Biometric quality evaluation is not configured. Registration cannot proceed."), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Verify REG_NO_QUALITY_SOURCE is never referenced outside its declaration
# Expect: only the declaration line in RegistrationExceptionConstants.java
rg -n --type=java "REG_NO_QUALITY_SOURCE"Repository: mosip/registration-client Length of output: 308 Remove the unused The constant 🤖 Prompt for AI Agents |
||
| REG_OTP_VALIDATION("REG-OV-001","Erroe while validating the otp"), | ||
| REG_PACKET_DATE_PARSER_CODE(PACKET_CREATION_EXP_CODE + "TGE-001", "Exception while parsing the date to display in acknowledgement receipt"), | ||
| REG_PACKET_JSON_VALIDATOR_ERROR_CODE(PACKET_CREATION_EXP_CODE + "PCS-003", "Exception while validating ID json file"), | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |||||||||||||||||||||||||||||||
| import java.io.InputStream; | ||||||||||||||||||||||||||||||||
| import java.time.temporal.ValueRange; | ||||||||||||||||||||||||||||||||
| import java.util.*; | ||||||||||||||||||||||||||||||||
| import java.util.concurrent.*; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import io.mosip.registration.dto.schema.UiFieldDTO; | ||||||||||||||||||||||||||||||||
| import io.mosip.registration.enums.Modality; | ||||||||||||||||||||||||||||||||
|
|
@@ -29,6 +30,7 @@ | |||||||||||||||||||||||||||||||
| import io.mosip.registration.context.ApplicationContext; | ||||||||||||||||||||||||||||||||
| import io.mosip.registration.context.SessionContext; | ||||||||||||||||||||||||||||||||
| import io.mosip.registration.dto.RegistrationDTO; | ||||||||||||||||||||||||||||||||
| import io.mosip.registration.dto.biometric.QualityEvaluationResult; | ||||||||||||||||||||||||||||||||
| import io.mosip.registration.dto.packetmanager.BiometricsDto; | ||||||||||||||||||||||||||||||||
| import io.mosip.registration.exception.RegBaseCheckedException; | ||||||||||||||||||||||||||||||||
| import io.mosip.registration.exception.RegistrationExceptionConstants; | ||||||||||||||||||||||||||||||||
|
|
@@ -68,6 +70,8 @@ public class BioServiceImpl extends BaseService implements BioService { | |||||||||||||||||||||||||||||||
| @Autowired | ||||||||||||||||||||||||||||||||
| private BIRBuilder birBuilder; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| private final ExecutorService sdkExecutor = Executors.newSingleThreadExecutor(); | ||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🛡️ Proposed fix — add `@PreDestroy`+import javax.annotation.PreDestroy;
`@Service`
public class BioServiceImpl extends BaseService implements BioService {
private final ExecutorService sdkExecutor = Executors.newSingleThreadExecutor();
+
+ `@PreDestroy`
+ public void shutdownSdkExecutor() {
+ sdkExecutor.shutdownNow();
+ }As per coding guidelines: "Flag use of ThreadLocal without guaranteed removal (memory leak risk)" — the same principle applies to any managed resource that holds threads. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSingle-thread executor can be permanently degraded by an unresponsive SDK.
Consider replacing with a cached thread pool or a per-call thread, so each invocation gets a fresh thread and a stalled SDK call only affects its own biometric, not all future captures: -private final ExecutorService sdkExecutor = Executors.newSingleThreadExecutor();
+// Each evaluation gets its own thread; stalled threads cannot block future evaluations.
+private final ExecutorService sdkExecutor = Executors.newCachedThreadPool();Note: With a cached pool, a consistently misbehaving SDK would keep spawning threads. Add a bounded semaphore or thread factory with a sensible cap if needed for a production hardening pass. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Gets the registration DTO from session. | ||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||
|
|
@@ -97,16 +101,11 @@ public List<BiometricsDto> captureModality(MDMRequestDto mdmRequestDto) throws R | |||||||||||||||||||||||||||||||
| throw new RegBaseCheckedException(RegistrationExceptionConstants.REG_BIOMETRIC_QUALITY_SCORE_RANGE_ERROR.getErrorCode(), | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_BIOMETRIC_QUALITY_SCORE_RANGE_ERROR.getErrorMessage()); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (RegistrationConstants.ENABLE.equalsIgnoreCase((String) ApplicationContext.map() | ||||||||||||||||||||||||||||||||
| .getOrDefault(RegistrationConstants.QUALITY_CHECK_WITH_SDK, RegistrationConstants.DISABLE))) { | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| biometricsDto.setSdkScore(getSDKScore(biometricsDto)); | ||||||||||||||||||||||||||||||||
| } catch (BiometricException e) { | ||||||||||||||||||||||||||||||||
| LOGGER.error("Unable to fetch SDK Score ", e); | ||||||||||||||||||||||||||||||||
| throw new RegBaseCheckedException(RegistrationExceptionConstants.REG_BIOMETRIC_QUALITY_CHECK_ERROR.getErrorCode(), | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_BIOMETRIC_QUALITY_CHECK_ERROR.getErrorMessage()); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| QualityEvaluationResult result = evaluateQuality(biometricsDto); | ||||||||||||||||||||||||||||||||
| biometricsDto.setSdkScore(result.getScore()); | ||||||||||||||||||||||||||||||||
| biometricsDto.setQualitySource(result.getSource()); | ||||||||||||||||||||||||||||||||
| LOGGER.info("Quality evaluation complete: score={}, source={}, fallback={}", | ||||||||||||||||||||||||||||||||
| result.getScore(), result.getSource(), result.isFallback()); | ||||||||||||||||||||||||||||||||
| list.add(biometricsDto); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } catch (RegBaseCheckedException e) { | ||||||||||||||||||||||||||||||||
|
|
@@ -161,6 +160,111 @@ public InputStream getStream(MdmBioDevice mdmBioDevice, String modality) throws | |||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.MDS_BIODEVICE_NOT_FOUND.getErrorMessage()); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Orchestrates biometric quality evaluation across SDK and SBI sources. | ||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||
| * Decision rules: | ||||||||||||||||||||||||||||||||
| * - SDK disabled in config: use SBI score (AS-03) | ||||||||||||||||||||||||||||||||
| * - SDK enabled but provider unbound: fall back to SBI score (AS-02) | ||||||||||||||||||||||||||||||||
| * - SDK enabled, provider bound, call fails (timeout/null/exception): block, no fallback | ||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||
| private QualityEvaluationResult evaluateQuality(BiometricsDto biometricsDto) throws RegBaseCheckedException { | ||||||||||||||||||||||||||||||||
| boolean sdkEnabled = RegistrationConstants.ENABLE.equalsIgnoreCase( | ||||||||||||||||||||||||||||||||
| (String) ApplicationContext.map().getOrDefault( | ||||||||||||||||||||||||||||||||
| RegistrationConstants.QUALITY_CHECK_WITH_SDK, RegistrationConstants.DISABLE)); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!sdkEnabled) { | ||||||||||||||||||||||||||||||||
| LOGGER.info("SDK quality evaluation disabled, using SBI score for {}", biometricsDto.getBioAttribute()); | ||||||||||||||||||||||||||||||||
| return new QualityEvaluationResult(biometricsDto.getQualityScore(), "SBI", false); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| BiometricType biometricType = BiometricType | ||||||||||||||||||||||||||||||||
| .fromValue(io.mosip.commons.packet.constants.Biometric | ||||||||||||||||||||||||||||||||
| .getSingleTypeByAttribute(biometricsDto.getBioAttribute()).name()); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Check provider availability before committing to SDK path | ||||||||||||||||||||||||||||||||
| Object provider = null; | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| provider = bioAPIFactory.getBioProvider(biometricType, BiometricFunction.QUALITY_CHECK); | ||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||
| LOGGER.warn("SDK provider not available for {}, falling back to SBI", biometricType); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (provider == null) { | ||||||||||||||||||||||||||||||||
| LOGGER.info("SDK provider unbound, falling back to SBI score for {}", biometricsDto.getBioAttribute()); | ||||||||||||||||||||||||||||||||
| double sbiScore = biometricsDto.getQualityScore(); | ||||||||||||||||||||||||||||||||
| if (sbiScore <= 0) { | ||||||||||||||||||||||||||||||||
| LOGGER.error("SBI score also unavailable for {}", biometricsDto.getBioAttribute()); | ||||||||||||||||||||||||||||||||
| throw new RegBaseCheckedException( | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SBI_SCORE_MISSING.getErrorCode(), | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SBI_SCORE_MISSING.getErrorMessage()); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| return new QualityEvaluationResult(sbiScore, "SBI", true); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // SDK provider is bound - call with timeout. Any failure here blocks registration. | ||||||||||||||||||||||||||||||||
| long timeoutMs = getSdkTimeoutMs(); | ||||||||||||||||||||||||||||||||
| BIR bir = birBuilder.buildBir(biometricsDto, ProcessedLevelType.RAW); | ||||||||||||||||||||||||||||||||
| BIR[] birList = new BIR[]{bir}; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Future<Double> future = sdkExecutor.submit(() -> { | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| Map<BiometricType, Float> scoreMap = bioAPIFactory | ||||||||||||||||||||||||||||||||
| .getBioProvider(biometricType, BiometricFunction.QUALITY_CHECK) | ||||||||||||||||||||||||||||||||
| .getModalityQuality(birList, null); | ||||||||||||||||||||||||||||||||
| return (scoreMap != null && scoreMap.get(biometricType) != null) | ||||||||||||||||||||||||||||||||
| ? scoreMap.get(biometricType).doubleValue() | ||||||||||||||||||||||||||||||||
| : null; | ||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||
| LOGGER.error("SDK provider threw during quality check", e); | ||||||||||||||||||||||||||||||||
| throw new RuntimeException(e); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
Comment on lines
+186
to
+222
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TOCTOU: At line 188 the provider is fetched and stored as
Use the acquired reference in the lambda to eliminate both problems: ♻️ Proposed fix- Object provider = null;
+ // Use var (Java 10+) or the concrete return type of getBioProvider
+ var provider = (Object) null;
try {
- provider = bioAPIFactory.getBioProvider(biometricType, BiometricFunction.QUALITY_CHECK);
+ provider = bioAPIFactory.getBioProvider(biometricType, BiometricFunction.QUALITY_CHECK);
} catch (Exception e) {
LOGGER.warn("SDK provider not available for {}, falling back to SBI", biometricType);
}
if (provider == null) { ... }
+ final var boundProvider = bioAPIFactory.getBioProvider(biometricType, BiometricFunction.QUALITY_CHECK);
Future<Double> future = sdkExecutor.submit(() -> {
try {
- Map<BiometricType, Float> scoreMap = bioAPIFactory
- .getBioProvider(biometricType, BiometricFunction.QUALITY_CHECK)
- .getModalityQuality(birList, null);
+ Map<BiometricType, Float> scoreMap = boundProvider.getModalityQuality(birList, null);Or, simpler — capture the result of the first 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| Double score = future.get(timeoutMs, TimeUnit.MILLISECONDS); | ||||||||||||||||||||||||||||||||
| if (score == null) { | ||||||||||||||||||||||||||||||||
| LOGGER.error("SDK returned null quality score for {}", biometricsDto.getBioAttribute()); | ||||||||||||||||||||||||||||||||
| throw new RegBaseCheckedException( | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_NULL_RESPONSE.getErrorCode(), | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_NULL_RESPONSE.getErrorMessage()); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| LOGGER.info("SDK quality score {} received for {}", score, biometricsDto.getBioAttribute()); | ||||||||||||||||||||||||||||||||
| return new QualityEvaluationResult(score, "SDK", false); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| } catch (TimeoutException e) { | ||||||||||||||||||||||||||||||||
| future.cancel(true); | ||||||||||||||||||||||||||||||||
| LOGGER.error("SDK quality evaluation timed out after {}ms for {}", timeoutMs, biometricsDto.getBioAttribute()); | ||||||||||||||||||||||||||||||||
| throw new RegBaseCheckedException( | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_TIMEOUT.getErrorCode(), | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_TIMEOUT.getErrorMessage()); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| } catch (ExecutionException e) { | ||||||||||||||||||||||||||||||||
| LOGGER.error("SDK runtime error during quality evaluation for {}", biometricsDto.getBioAttribute(), e); | ||||||||||||||||||||||||||||||||
| throw new RegBaseCheckedException( | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_RUNTIME_ERROR.getErrorCode(), | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_RUNTIME_ERROR.getErrorMessage()); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| } catch (RegBaseCheckedException e) { | ||||||||||||||||||||||||||||||||
| throw e; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||
| LOGGER.error("Unexpected error during SDK quality evaluation", e); | ||||||||||||||||||||||||||||||||
| throw new RegBaseCheckedException( | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_RUNTIME_ERROR.getErrorCode(), | ||||||||||||||||||||||||||||||||
| RegistrationExceptionConstants.REG_SDK_RUNTIME_ERROR.getErrorMessage()); | ||||||||||||||||||||||||||||||||
|
Comment on lines
+235
to
+255
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🛡️ Proposed fix — add an explicit `InterruptedException` catch+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // restore interrupt status
+ future.cancel(true);
+ throw new RegBaseCheckedException(
+ RegistrationExceptionConstants.REG_SDK_RUNTIME_ERROR.getErrorCode(),
+ RegistrationExceptionConstants.REG_SDK_RUNTIME_ERROR.getErrorMessage());
} catch (TimeoutException e) {
future.cancel(true);🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| private long getSdkTimeoutMs() { | ||||||||||||||||||||||||||||||||
| String configured = getGlobalConfigValueOf(RegistrationConstants.SDK_QUALITY_TIMEOUT); | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| return configured != null ? Long.parseLong(configured) : RegistrationConstants.SDK_QUALITY_TIMEOUT_DEFAULT_MS; | ||||||||||||||||||||||||||||||||
| } catch (NumberFormatException e) { | ||||||||||||||||||||||||||||||||
| return RegistrationConstants.SDK_QUALITY_TIMEOUT_DEFAULT_MS; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
Comment on lines
+163
to
+266
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Description: Verify whether any of the new SDK audit events are fired elsewhere,
# and confirm the audit helper method name on BaseService.
# Check for any usage of the new audit event constants
rg -n --type=java "SDK_QUALITY_SUCCESS|SDK_QUALITY_FAILED|SDK_FALLBACK_TO_SBI|SDK_QUALITY_DISABLED|NO_VALID_QUALITY_SCORE"
# Check what audit helper methods BaseService exposes
ast-grep --pattern 'class BaseService {
$$$
public $_ audit($$$) {
$$$
}
$$$
}'Repository: mosip/registration-client Length of output: 1283 🏁 Script executed: # Find BioServiceImpl class and its parent
rg -n --type=java "class BioServiceImpl" -A 3
# Search for audit() method calls in service classes to understand the pattern
rg -n --type=java "audit\(" | head -30
# Check if BioServiceImpl has access to auditFactory or similar
rg -n --type=java "auditFactory|AuditFactory" registration/registration-services/src/main/java/io/mosip/registration/service/bio/impl/BioServiceImpl.java
# Search for existing audit calls in BaseService or other bio service methods
fd BioServiceImpl.java --exec cat -n {} \;Repository: mosip/registration-client Length of output: 27177 🏁 Script executed: # Find BaseService and check for auditFactory
fd BaseService.java --exec head -100 {} \;
# Also search for how auditFactory is provided
rg -n --type=java "protected.*auditFactory|private.*auditFactory|@Autowired.*auditFactory" -A 2 | head -30Repository: mosip/registration-client Length of output: 7770 🏁 Script executed: # Search entire BaseService for auditFactory
rg -n "auditFactory" registration/registration-services/src/main/java/io/mosip/registration/service/BaseService.java
# Or find the file and check its full length
wc -l registration/registration-services/src/main/java/io/mosip/registration/service/BaseService.javaRepository: mosip/registration-client Length of output: 169 🏁 Script executed: # Search for auditFactory declaration in BaseService
grep -n "auditFactory" registration/registration-services/src/main/java/io/mosip/registration/service/BaseService.javaRepository: mosip/registration-client Length of output: 51 🏁 Script executed: # Search for how audit is done across service classes - look for audit pattern
rg -n "audit\(" registration/registration-services/src/main/java/io/mosip/registration/service/bio/ -B 2 -A 2
# Find where AuditEvent is imported and used
rg -n "import.*AuditEvent" registration/registration-services/src/main/java/io/mosip/registration/service/
# Check a service that uses auditFactory to see how it's imported/injected
rg -n "auditFactory" registration/registration-services/src/main/java/io/mosip/registration/service/login/impl/LoginServiceImpl.java -B 5 -A 2 | head -40Repository: mosip/registration-client Length of output: 2693 🏁 Script executed: # Check if BioServiceImpl imports AuditEvent
grep -n "import.*AuditEvent\|import.*AuditManagerService\|import.*Components" registration/registration-services/src/main/java/io/mosip/registration/service/bio/impl/BioServiceImpl.java
# Find BaseService's auditFactory field
sed -n '70,120p' registration/registration-services/src/main/java/io/mosip/registration/service/BaseService.javaRepository: mosip/registration-client Length of output: 1815 🏁 Script executed: # Search for auditFactory field in BaseService
sed -n '1,200p' registration/registration-services/src/main/java/io/mosip/registration/service/BaseService.java | grep -n "auditFactory" -A 2 -B 2
# Also check around line 100-150
sed -n '100,150p' registration/registration-services/src/main/java/io/mosip/registration/service/BaseService.javaRepository: mosip/registration-client Length of output: 1455 🏁 Script executed: # Continue searching for auditFactory in BaseService - it might be further down
grep -n "auditFactory\|AuditManagerService\|AuditEvent" registration/registration-services/src/main/java/io/mosip/registration/service/BaseService.java
# If not found, check if child classes need to define it themselves
rg -n "@Autowired.*auditFactory" registration/registration-services/src/main/java/io/mosip/registration/service/ -B 1Repository: mosip/registration-client Length of output: 51 🏁 Script executed: # Confirm BioServiceImpl has no auditFactory field or AuditEvent imports
head -50 registration/registration-services/src/main/java/io/mosip/registration/service/bio/impl/BioServiceImpl.java | grep -i "audit"
# Check if evaluateQuality is called from multiple places
rg -n "evaluateQuality" registration/registration-services/src/main/java/io/mosip/registration/service/bio/Repository: mosip/registration-client Length of output: 473 Audit events defined but never emitted in quality evaluation
Add
See how other service classes (e.g., 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||
| public double getSDKScore(BiometricsDto biometricsDto) throws BiometricException { | ||||||||||||||||||||||||||||||||
| BiometricType biometricType = BiometricType | ||||||||||||||||||||||||||||||||
|
|
@@ -196,7 +300,15 @@ public Map<String, Boolean> getCapturedBiometrics(@NonNull UiFieldDTO fieldDto, | |||||||||||||||||||||||||||||||
| capturedContext.put(attribute, true); | ||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| quality = quality + biometricsDto.getQualityScore(); | ||||||||||||||||||||||||||||||||
| double effectiveScore = (biometricsDto.getSdkScore() > 0) | ||||||||||||||||||||||||||||||||
| ? biometricsDto.getSdkScore() | ||||||||||||||||||||||||||||||||
| : biometricsDto.getQualityScore(); | ||||||||||||||||||||||||||||||||
| if (effectiveScore <= 0) { | ||||||||||||||||||||||||||||||||
| LOGGER.warn("No valid quality score available for attribute {}", attribute); | ||||||||||||||||||||||||||||||||
| capturedContext.put(attribute, false); | ||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| quality = quality + effectiveScore; | ||||||||||||||||||||||||||||||||
| capturedAttributes.add(attribute); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| //if some attributes are captured, determine capture status based on threshold check | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
sourceshould be an enum or constant — rawStringliterals"SDK"/"SBI"are not type-safe.BioServiceImplhardcodes"SDK"and"SBI"at call sites. A new source type, a typo, or a refactor won't be caught at compile time. Introduce a small enum or reuse constants:♻️ Proposed refactor
Then in
BioServiceImpl:🤖 Prompt for AI Agents