Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- @Override
- public User verifyStudentFingerprint(Long scheduleId, MultipartFile scannedFingerprintImage) throws IOException {
- // Cache the scanned template first to avoid redundant conversions
- byte[] scannedFingerprintImageBytes = scannedFingerprintImage.getBytes();
- FingerprintTemplate probeTemplate = new FingerprintTemplate(
- new FingerprintImage(scannedFingerprintImageBytes)
- );
- // Fetch schedule and students in parallel using CompletableFuture
- CompletableFuture<Schedule> scheduleFuture = CompletableFuture.supplyAsync(() ->
- scheduleRepository.findById(scheduleId).orElse(null)
- );
- CompletableFuture<List<ScheduleStudent>> studentsFuture = scheduleFuture.thenApplyAsync(schedule ->
- schedule != null ? scheduleStudentRepository.findByScheduleId(schedule.getId()) : Collections.emptyList()
- );
- // Wait for both futures to complete
- Schedule schedule = scheduleFuture.join();
- List<ScheduleStudent> students = studentsFuture.join();
- if (schedule == null || students.isEmpty()) return null;
- // Extract student IDs and fetch fingerprints
- List<Long> studentIds = students.stream()
- .map(s -> s.getStudent().getId())
- .collect(Collectors.toList());
- // Use batch fetching for fingerprints
- List<Fingerprint> fingerprints = fingerprintRepository.getOneFingerprintPerUser(studentIds);
- if (fingerprints.isEmpty()) return null;
- // Create a thread pool with the number of available processors
- int processors = Runtime.getRuntime().availableProcessors();
- ExecutorService executorService = Executors.newFixedThreadPool(processors);
- try {
- // Process fingerprints in batches
- int batchSize = Math.max(1, fingerprints.size() / processors);
- List<List<Fingerprint>> batches = partitionList(fingerprints, batchSize);
- // Create tasks for parallel processing
- List<CompletableFuture<Optional<Map.Entry<Fingerprint, Double>>>> futures = batches.stream()
- .map(batch -> CompletableFuture.supplyAsync(() -> processFingerprintBatch(batch, probeTemplate), executorService))
- .toList();
- // Find the best match across all batches
- Optional<Map.Entry<Fingerprint, Double>> bestMatch = futures.stream()
- .map(CompletableFuture::join)
- .filter(Optional::isPresent)
- .map(Optional::get)
- .max(Map.Entry.comparingByValue());
- if (bestMatch.isEmpty() || bestMatch.get().getValue() < threshold) {
- return null;
- }
- // Update attendance status
- Fingerprint matchedFingerprint = bestMatch.get().getKey();
- ScheduleStudent matchedStudent = students.stream()
- .filter(s -> s.getStudent().getId().equals(matchedFingerprint.getUser().getId()))
- .findFirst()
- .orElse(null);
- if (matchedStudent != null) {
- matchedStudent.setHasLogged(true);
- scheduleStudentRepository.save(matchedStudent);
- return matchedFingerprint.getUser();
- }
- return null;
- } finally {
- executorService.shutdown();
- }
- }
- private <T> List<List<T>> partitionList(List<T> list, int batchSize) {
- if (batchSize <= 0) throw new IllegalArgumentException("Batch size must be positive");
- int numBatches = (list.size() + batchSize - 1) / batchSize;
- return IntStream.range(0, numBatches)
- .mapToObj(i -> list.subList(
- i * batchSize,
- Math.min((i + 1) * batchSize, list.size())
- ))
- .collect(Collectors.toList());
- }
- private Optional<Map.Entry<Fingerprint, Double>> processFingerprintBatch(
- List<Fingerprint> batch,
- FingerprintTemplate probeTemplate
- ) {
- FingerprintMatcher matcher = new FingerprintMatcher(probeTemplate);
- return batch.parallelStream()
- .map(fingerprint -> {
- FingerprintTemplate template = new FingerprintTemplate(
- new FingerprintImage(fingerprint.getFingerprint())
- );
- return Map.entry(fingerprint, matcher.match(template));
- })
- .filter(entry -> entry.getValue() >= threshold)
- .max(Map.Entry.comparingByValue());
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement