3
3
import java .util .ArrayList ;
4
4
import java .util .List ;
5
5
import java .util .Optional ;
6
- import java .util .concurrent .atomic .AtomicInteger ;
7
6
8
7
import javax .swing .undo .UndoManager ;
9
8
10
9
import org .jabref .gui .undo .NamedCompound ;
10
+ import org .jabref .gui .util .UiTaskExecutor ;
11
11
import org .jabref .logic .importer .fetcher .MergingIdBasedFetcher ;
12
12
import org .jabref .logic .l10n .Localization ;
13
13
import org .jabref .logic .util .BackgroundTask ;
17
17
import org .slf4j .Logger ;
18
18
import org .slf4j .LoggerFactory ;
19
19
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 > {
26
24
27
25
private static final Logger LOGGER = LoggerFactory .getLogger (BatchEntryMergeTask .class );
28
26
29
27
private final NamedCompound compoundEdit ;
30
- private final AtomicInteger processedEntries ;
31
- private final AtomicInteger successfulUpdates ;
32
28
private final List <BibEntry > entries ;
33
29
private final MergingIdBasedFetcher fetcher ;
34
30
private final UndoManager undoManager ;
35
31
private final NotificationService notificationService ;
36
32
33
+ private int processedEntries ;
34
+ private int successfulUpdates ;
35
+
37
36
public BatchEntryMergeTask (List <BibEntry > entries ,
38
37
MergingIdBasedFetcher fetcher ,
39
38
UndoManager undoManager ,
@@ -44,56 +43,50 @@ public BatchEntryMergeTask(List<BibEntry> entries,
44
43
this .notificationService = notificationService ;
45
44
46
45
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 ;
52
48
53
- private void configureTask () {
54
49
setTitle (Localization .lang ("Fetching and merging entry(s)" ));
55
50
withInitialMessage (Localization .lang ("Starting merge operation..." ));
56
51
showToUser (true );
57
52
}
58
53
59
54
@ Override
60
- public List < String > call () {
55
+ public Void call () {
61
56
if (isCancelled ()) {
62
57
notifyCancellation ();
63
- return List . of () ;
58
+ return null ;
64
59
}
65
60
66
61
List <String > updatedEntries = processMergeEntries ();
67
62
68
63
if (isCancelled ()) {
69
64
notifyCancellation ();
70
- finalizeOperation (updatedEntries );
71
- return updatedEntries ;
65
+ updateUndoManager (updatedEntries );
66
+ return null ;
72
67
}
73
68
74
- finalizeOperation (updatedEntries );
69
+ updateUndoManager (updatedEntries );
75
70
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 ;
79
74
}
80
75
81
76
private void notifyCancellation () {
82
77
LOGGER .debug ("Merge operation was cancelled. Processed: {}, Successfully updated: {}" ,
83
- processedEntries . get () , successfulUpdates . get () );
78
+ processedEntries , successfulUpdates );
84
79
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 ));
86
81
}
87
82
88
83
private List <String > processMergeEntries () {
89
- List <String > updatedEntries = new ArrayList <>();
84
+ List <String > updatedEntries = new ArrayList <>(entries . size () );
90
85
91
86
for (BibEntry entry : entries ) {
92
- Optional <String > result = processSingleEntryWithProgress (entry );
93
- result .ifPresent (updatedEntries ::add );
94
-
87
+ processSingleEntryWithProgress (entry ).ifPresent (updatedEntries ::add );
95
88
if (isCancelled ()) {
96
- LOGGER .debug ("Cancellation requested after processing entry {}" , processedEntries . get () );
89
+ LOGGER .debug ("Cancellation requested after processing entry {}" , processedEntries );
97
90
break ;
98
91
}
99
92
}
@@ -102,56 +95,31 @@ private List<String> processMergeEntries() {
102
95
}
103
96
104
97
private Optional <String > processSingleEntryWithProgress (BibEntry entry ) {
105
- updateProgress (processedEntries . incrementAndGet () , entries .size ());
98
+ updateProgress (++ processedEntries , entries .size ());
106
99
updateMessage (Localization .lang ("Processing entry %0 of %1" ,
107
- processedEntries . get () ,
100
+ processedEntries ,
108
101
entries .size ()));
109
102
return processSingleEntry (entry );
110
103
}
111
104
112
105
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
+ });
129
117
}
130
118
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 ) {
150
120
if (!updatedEntries .isEmpty ()) {
151
- synchronized (compoundEdit ) {
152
- compoundEdit .end ();
153
- undoManager .addEdit (compoundEdit );
154
- }
121
+ compoundEdit .end ();
122
+ UiTaskExecutor .runInJavaFXThread (() -> undoManager .addEdit (compoundEdit ));
155
123
}
156
124
}
157
125
0 commit comments