33import java .util .ArrayList ;
44import java .util .List ;
55import java .util .Optional ;
6- import java .util .concurrent .atomic .AtomicInteger ;
76
87import javax .swing .undo .UndoManager ;
98
109import org .jabref .gui .undo .NamedCompound ;
10+ import org .jabref .gui .util .UiTaskExecutor ;
1111import org .jabref .logic .importer .fetcher .MergingIdBasedFetcher ;
1212import org .jabref .logic .l10n .Localization ;
1313import org .jabref .logic .util .BackgroundTask ;
1717import org .slf4j .Logger ;
1818import org .slf4j .LoggerFactory ;
1919
20- /**
21- * A background task that handles fetching and merging of bibliography entries.
22- * This implementation provides improved concurrency handling, better Optional usage,
23- * and more robust error handling.
24- */
25- public class BatchEntryMergeTask extends BackgroundTask <List <String >> {
20+ /// A background task that handles fetching and merging of bibliography entries.
21+ /// This implementation provides improved concurrency handling, better Optional usage,
22+ /// and more robust error handling.
23+ public class BatchEntryMergeTask extends BackgroundTask <Void > {
2624
2725 private static final Logger LOGGER = LoggerFactory .getLogger (BatchEntryMergeTask .class );
2826
2927 private final NamedCompound compoundEdit ;
30- private final AtomicInteger processedEntries ;
31- private final AtomicInteger successfulUpdates ;
3228 private final List <BibEntry > entries ;
3329 private final MergingIdBasedFetcher fetcher ;
3430 private final UndoManager undoManager ;
3531 private final NotificationService notificationService ;
3632
33+ private int processedEntries ;
34+ private int successfulUpdates ;
35+
3736 public BatchEntryMergeTask (List <BibEntry > entries ,
3837 MergingIdBasedFetcher fetcher ,
3938 UndoManager undoManager ,
@@ -44,56 +43,50 @@ public BatchEntryMergeTask(List<BibEntry> entries,
4443 this .notificationService = notificationService ;
4544
4645 this .compoundEdit = new NamedCompound (Localization .lang ("Merge entries" ));
47- this .processedEntries = new AtomicInteger (0 );
48- this .successfulUpdates = new AtomicInteger (0 );
49-
50- configureTask ();
51- }
46+ this .processedEntries = 0 ;
47+ this .successfulUpdates = 0 ;
5248
53- private void configureTask () {
5449 setTitle (Localization .lang ("Fetching and merging entry(s)" ));
5550 withInitialMessage (Localization .lang ("Starting merge operation..." ));
5651 showToUser (true );
5752 }
5853
5954 @ Override
60- public List < String > call () {
55+ public Void call () {
6156 if (isCancelled ()) {
6257 notifyCancellation ();
63- return List . of () ;
58+ return null ;
6459 }
6560
6661 List <String > updatedEntries = processMergeEntries ();
6762
6863 if (isCancelled ()) {
6964 notifyCancellation ();
70- finalizeOperation (updatedEntries );
71- return updatedEntries ;
65+ updateUndoManager (updatedEntries );
66+ return null ;
7267 }
7368
74- finalizeOperation (updatedEntries );
69+ updateUndoManager (updatedEntries );
7570 LOGGER .debug ("Merge operation completed. Processed: {}, Successfully updated: {}" ,
76- processedEntries . get () , successfulUpdates . get () );
77- notifySuccess (successfulUpdates . get () );
78- return updatedEntries ;
71+ processedEntries , successfulUpdates );
72+ notifySuccess (successfulUpdates );
73+ return null ;
7974 }
8075
8176 private void notifyCancellation () {
8277 LOGGER .debug ("Merge operation was cancelled. Processed: {}, Successfully updated: {}" ,
83- processedEntries . get () , successfulUpdates . get () );
78+ processedEntries , successfulUpdates );
8479 notificationService .notify (
85- Localization .lang ("Merge operation cancelled after updating %0 entry(s)" , successfulUpdates . get () ));
80+ Localization .lang ("Merge operation cancelled after updating %0 entry(s)" , successfulUpdates ));
8681 }
8782
8883 private List <String > processMergeEntries () {
89- List <String > updatedEntries = new ArrayList <>();
84+ List <String > updatedEntries = new ArrayList <>(entries . size () );
9085
9186 for (BibEntry entry : entries ) {
92- Optional <String > result = processSingleEntryWithProgress (entry );
93- result .ifPresent (updatedEntries ::add );
94-
87+ processSingleEntryWithProgress (entry ).ifPresent (updatedEntries ::add );
9588 if (isCancelled ()) {
96- LOGGER .debug ("Cancellation requested after processing entry {}" , processedEntries . get () );
89+ LOGGER .debug ("Cancellation requested after processing entry {}" , processedEntries );
9790 break ;
9891 }
9992 }
@@ -102,56 +95,31 @@ private List<String> processMergeEntries() {
10295 }
10396
10497 private Optional <String > processSingleEntryWithProgress (BibEntry entry ) {
105- updateProgress (processedEntries . incrementAndGet () , entries .size ());
98+ updateProgress (++ processedEntries , entries .size ());
10699 updateMessage (Localization .lang ("Processing entry %0 of %1" ,
107- processedEntries . get () ,
100+ processedEntries ,
108101 entries .size ()));
109102 return processSingleEntry (entry );
110103 }
111104
112105 private Optional <String > processSingleEntry (BibEntry entry ) {
113- try {
114- LOGGER .debug ("Processing entry: {}" , entry );
115- return fetcher .fetchEntry (entry )
116- .filter (MergingIdBasedFetcher .FetcherResult ::hasChanges )
117- .flatMap (result -> {
118- boolean changesApplied = applyMerge (entry , result );
119- if (changesApplied ) {
120- successfulUpdates .incrementAndGet ();
121- return entry .getCitationKey ();
122- }
123- return Optional .empty ();
124- });
125- } catch (Exception e ) {
126- handleEntryProcessingError (entry , e );
127- return Optional .empty ();
128- }
106+ LOGGER .debug ("Processing entry: {}" , entry );
107+ return fetcher .fetchEntry (entry )
108+ .filter (MergingIdBasedFetcher .FetcherResult ::hasChanges )
109+ .flatMap (result -> {
110+ boolean changesApplied = MergeEntriesHelper .mergeEntries (result .mergedEntry (), entry , compoundEdit );
111+ if (changesApplied ) {
112+ successfulUpdates ++;
113+ return entry .getCitationKey ();
114+ }
115+ return Optional .empty ();
116+ });
129117 }
130118
131- private boolean applyMerge (BibEntry entry , MergingIdBasedFetcher .FetcherResult result ) {
132- synchronized (compoundEdit ) {
133- try {
134- return MergeEntriesHelper .mergeEntries (result .mergedEntry (), entry , compoundEdit );
135- } catch (Exception e ) {
136- LOGGER .error ("Error during merge operation for entry: {}" , entry , e );
137- return false ;
138- }
139- }
140- }
141-
142- private void handleEntryProcessingError (BibEntry entry , Exception e ) {
143- String citationKey = entry .getCitationKey ().orElse ("unknown" );
144- String message = Localization .lang ("Error processing entry" , citationKey , e .getMessage ());
145- LOGGER .error (message , e );
146- notificationService .notify (message );
147- }
148-
149- private void finalizeOperation (List <String > updatedEntries ) {
119+ private void updateUndoManager (List <String > updatedEntries ) {
150120 if (!updatedEntries .isEmpty ()) {
151- synchronized (compoundEdit ) {
152- compoundEdit .end ();
153- undoManager .addEdit (compoundEdit );
154- }
121+ compoundEdit .end ();
122+ UiTaskExecutor .runInJavaFXThread (() -> undoManager .addEdit (compoundEdit ));
155123 }
156124 }
157125
0 commit comments