17
17
18
18
import java .util .Collection ;
19
19
import java .util .HashSet ;
20
+ import java .util .Objects ;
20
21
import java .util .Set ;
21
22
import java .util .concurrent .locks .Lock ;
22
23
import java .util .concurrent .locks .ReentrantReadWriteLock ;
@@ -48,7 +49,7 @@ public enum ProcessState {
48
49
/**
49
50
* The set of already processed relationships.
50
51
*/
51
- private final Set <RelationshipDescription > processedRelationshipDescriptions = new HashSet <>();
52
+ private final Set <RelationshipDescriptionWithSourceId > processedRelationshipDescriptions = new HashSet <>();
52
53
53
54
/**
54
55
* The set of already processed related objects.
@@ -64,11 +65,11 @@ public NestedRelationshipProcessingStateMachine(Object initialObject) {
64
65
* @param valuesToStore Check whether all the values in the collection have been processed
65
66
* @return The state of things processed
66
67
*/
67
- public ProcessState getStateOf (RelationshipDescription relationshipDescription , @ Nullable Collection <?> valuesToStore ) {
68
+ public ProcessState getStateOf (Object fromId , RelationshipDescription relationshipDescription , @ Nullable Collection <?> valuesToStore ) {
68
69
69
70
try {
70
71
read .lock ();
71
- boolean hasProcessedRelationship = hasProcessed ( relationshipDescription );
72
+ boolean hasProcessedRelationship = hasProcessedRelationship ( fromId , relationshipDescription );
72
73
boolean hasProcessedAllValues = hasProcessedAllOf (valuesToStore );
73
74
if (hasProcessedRelationship && hasProcessedAllValues ) {
74
75
return ProcessState .PROCESSED_BOTH ;
@@ -85,38 +86,97 @@ public ProcessState getStateOf(RelationshipDescription relationshipDescription,
85
86
}
86
87
}
87
88
89
+ /**
90
+ * Combination of relationship description and fromId to differentiate between `equals`-wise equal relationship
91
+ * descriptions by their source identifier. This is needed because sometimes the very same relationship definition
92
+ * can get processed for different objects of the same entity.
93
+ * One could say that this is a Tuple but it has a nicer name.
94
+ */
95
+ private static class RelationshipDescriptionWithSourceId {
96
+ private final Object id ;
97
+ private final RelationshipDescription relationshipDescription ;
98
+
99
+ RelationshipDescriptionWithSourceId (Object id , RelationshipDescription relationshipDescription ) {
100
+ this .id = id ;
101
+ this .relationshipDescription = relationshipDescription ;
102
+ }
103
+
104
+ @ Override
105
+ public boolean equals (Object o ) {
106
+ if (this == o ) {
107
+ return true ;
108
+ }
109
+ if (o == null || getClass () != o .getClass ()) {
110
+ return false ;
111
+ }
112
+ RelationshipDescriptionWithSourceId that = (RelationshipDescriptionWithSourceId ) o ;
113
+ return id .equals (that .id ) && relationshipDescription .equals (that .relationshipDescription );
114
+ }
115
+
116
+ @ Override
117
+ public int hashCode () {
118
+ return Objects .hash (id , relationshipDescription );
119
+ }
120
+ }
121
+
88
122
/**
89
123
* Marks the passed objects as processed
90
124
*
91
125
* @param relationshipDescription To be marked as processed
92
- * @param valuesToStore If not {@literal null}, all non-null values will be marked as processed
93
126
*/
94
- public void markAsProcessed ( RelationshipDescription relationshipDescription , @ Nullable Collection <?> valuesToStore ) {
127
+ public void markRelationshipAsProcessed ( Object fromId , RelationshipDescription relationshipDescription ) {
95
128
96
129
try {
97
130
write .lock ();
98
- this .processedRelationshipDescriptions .add (relationshipDescription );
99
- if (valuesToStore != null ) {
100
- valuesToStore .stream ().filter (v -> v != null ).forEach (processedObjects ::add );
101
- }
131
+ this .processedRelationshipDescriptions .add (new RelationshipDescriptionWithSourceId (fromId , relationshipDescription ));
102
132
} finally {
103
133
write .unlock ();
104
134
}
105
135
}
136
+ /**
137
+ * Marks the passed objects as processed
138
+ *
139
+ * @param valueToStore If not {@literal null}, all non-null values will be marked as processed
140
+ */
141
+ public void markValueAsProcessed (Object valueToStore ) {
106
142
107
- private boolean hasProcessedAllOf (@ Nullable Collection <?> valuesToStore ) {
108
- // there can be null elements in the unified collection of values to store.
109
- if (valuesToStore == null ) {
110
- return false ;
143
+ try {
144
+ write .lock ();
145
+ this .processedObjects .add (valueToStore );
146
+ } finally {
147
+ write .unlock ();
111
148
}
112
- return processedObjects .containsAll (valuesToStore );
113
149
}
114
150
115
- private boolean hasProcessed (RelationshipDescription relationshipDescription ) {
151
+ /**
152
+ * Checks if the value has already been processed.
153
+ *
154
+ * @param value the object that should be looked for in the registry.
155
+ * @return processed yes (true) / no (false)
156
+ */
157
+ public boolean hasProcessedValue (Object value ) {
158
+ return processedObjects .contains (value );
159
+ }
116
160
161
+ /**
162
+ * Checks if the relationship has already been processed.
163
+ *
164
+ * @param relationshipDescription the relationship that should be looked for in the registry.
165
+ * @return processed yes (true) / no (false)
166
+ */
167
+ public boolean hasProcessedRelationship (Object fromId , @ Nullable RelationshipDescription relationshipDescription ) {
117
168
if (relationshipDescription != null ) {
118
- return processedRelationshipDescriptions .contains (relationshipDescription );
169
+ return processedRelationshipDescriptions .contains (new RelationshipDescriptionWithSourceId ( fromId , relationshipDescription ) );
119
170
}
120
171
return false ;
121
172
}
173
+
174
+ private boolean hasProcessedAllOf (@ Nullable Collection <?> valuesToStore ) {
175
+ // there can be null elements in the unified collection of values to store.
176
+ if (valuesToStore == null ) {
177
+ return false ;
178
+ }
179
+ return processedObjects .containsAll (valuesToStore );
180
+ }
181
+
122
182
}
0 commit comments