@@ -53,6 +53,8 @@ public static class Builder {
5353 private String [] jsonExclusions ;
5454 private String [] xmlExclusions ;
5555 private Map <String , String > xmlNamespaces ;
56+ private String schemaName ;
57+ private String viewName ;
5658
5759 /**
5860 * @param keyName the name of the MarkLogic metadata key that will hold the hash value; defaults to "incrementalWriteHash".
@@ -128,13 +130,43 @@ public Builder xmlNamespaces(Map<String, String> namespaces) {
128130 return this ;
129131 }
130132
133+ /**
134+ * Configures the filter to use a TDE view for retrieving hash values instead of field range indexes.
135+ * This approach requires a TDE template to be deployed that extracts the URI and hash metadata.
136+ *
137+ * @param schemaName the schema name of the TDE view
138+ * @param viewName the view name of the TDE view
139+ * @return this builder
140+ */
141+ public Builder fromView (String schemaName , String viewName ) {
142+ boolean schemaEmpty = schemaName == null || schemaName .trim ().isEmpty ();
143+ boolean viewEmpty = viewName == null || viewName .trim ().isEmpty ();
144+
145+ if (schemaEmpty && !viewEmpty ) {
146+ throw new IllegalArgumentException ("Schema name cannot be null or empty when view name is provided" );
147+ }
148+ if (!schemaEmpty && viewEmpty ) {
149+ throw new IllegalArgumentException ("View name cannot be null or empty when schema name is provided" );
150+ }
151+
152+ this .schemaName = schemaName ;
153+ this .viewName = viewName ;
154+ return this ;
155+ }
156+
131157 public IncrementalWriteFilter build () {
132158 validateJsonExclusions ();
133159 validateXmlExclusions ();
160+ IncrementalWriteConfig config = new IncrementalWriteConfig (hashKeyName , timestampKeyName , canonicalizeJson ,
161+ skippedDocumentsConsumer , jsonExclusions , xmlExclusions , xmlNamespaces , schemaName , viewName );
162+
163+ if (schemaName != null && viewName != null ) {
164+ return new IncrementalWriteViewFilter (config );
165+ }
134166 if (useEvalQuery ) {
135- return new IncrementalWriteEvalFilter (hashKeyName , timestampKeyName , canonicalizeJson , skippedDocumentsConsumer , jsonExclusions , xmlExclusions , xmlNamespaces );
167+ return new IncrementalWriteEvalFilter (config );
136168 }
137- return new IncrementalWriteOpticFilter (hashKeyName , timestampKeyName , canonicalizeJson , skippedDocumentsConsumer , jsonExclusions , xmlExclusions , xmlNamespaces );
169+ return new IncrementalWriteOpticFilter (config );
138170 }
139171
140172 private void validateJsonExclusions () {
@@ -181,26 +213,18 @@ private void validateXmlExclusions() {
181213 }
182214 }
183215
184- protected final String hashKeyName ;
185- private final String timestampKeyName ;
186- private final boolean canonicalizeJson ;
187- private final Consumer <DocumentWriteOperation []> skippedDocumentsConsumer ;
188- private final String [] jsonExclusions ;
189- private final String [] xmlExclusions ;
190- private final Map <String , String > xmlNamespaces ;
216+ private final IncrementalWriteConfig config ;
191217
192218 // Hardcoding this for now, with a good general purpose hashing function.
193219 // See https://xxhash.com for benchmarks.
194220 private final LongHashFunction hashFunction = LongHashFunction .xx3 ();
195221
196- public IncrementalWriteFilter (String hashKeyName , String timestampKeyName , boolean canonicalizeJson , Consumer <DocumentWriteOperation []> skippedDocumentsConsumer , String [] jsonExclusions , String [] xmlExclusions , Map <String , String > xmlNamespaces ) {
197- this .hashKeyName = hashKeyName ;
198- this .timestampKeyName = timestampKeyName ;
199- this .canonicalizeJson = canonicalizeJson ;
200- this .skippedDocumentsConsumer = skippedDocumentsConsumer ;
201- this .jsonExclusions = jsonExclusions ;
202- this .xmlExclusions = xmlExclusions ;
203- this .xmlNamespaces = xmlNamespaces ;
222+ public IncrementalWriteFilter (IncrementalWriteConfig config ) {
223+ this .config = config ;
224+ }
225+
226+ public IncrementalWriteConfig getConfig () {
227+ return config ;
204228 }
205229
206230 protected final DocumentWriteSet filterDocuments (Context context , Function <String , String > hashRetriever ) {
@@ -230,19 +254,19 @@ protected final DocumentWriteSet filterDocuments(Context context, Function<Strin
230254
231255 if (existingHash != null ) {
232256 if (!existingHash .equals (contentHash )) {
233- newWriteSet .add (addHashToMetadata (doc , hashKeyName , contentHash , timestampKeyName , timestamp ));
234- } else if (skippedDocumentsConsumer != null ) {
257+ newWriteSet .add (addHashToMetadata (doc , config . getHashKeyName () , contentHash , config . getTimestampKeyName () , timestamp ));
258+ } else if (config . getSkippedDocumentsConsumer () != null ) {
235259 skippedDocuments .add (doc );
236260 } else {
237261 // No consumer, so skip the document silently.
238262 }
239263 } else {
240- newWriteSet .add (addHashToMetadata (doc , hashKeyName , contentHash , timestampKeyName , timestamp ));
264+ newWriteSet .add (addHashToMetadata (doc , config . getHashKeyName () , contentHash , config . getTimestampKeyName () , timestamp ));
241265 }
242266 }
243267
244- if (!skippedDocuments .isEmpty () && skippedDocumentsConsumer != null ) {
245- skippedDocumentsConsumer .accept (skippedDocuments .toArray (new DocumentWriteOperation [0 ]));
268+ if (!skippedDocuments .isEmpty () && config . getSkippedDocumentsConsumer () != null ) {
269+ config . getSkippedDocumentsConsumer () .accept (skippedDocuments .toArray (new DocumentWriteOperation [0 ]));
246270 }
247271
248272 return newWriteSet ;
@@ -259,11 +283,11 @@ private String serializeContent(DocumentWriteOperation doc) {
259283 format = baseHandle .getFormat ();
260284 }
261285
262- if (canonicalizeJson && (Format .JSON .equals (format ) || isPossiblyJsonContent (content ))) {
286+ if (config . isCanonicalizeJson () && (Format .JSON .equals (format ) || isPossiblyJsonContent (content ))) {
263287 JsonCanonicalizer jc ;
264288 try {
265- if (jsonExclusions != null && jsonExclusions .length > 0 ) {
266- content = ContentExclusionUtil .applyJsonExclusions (doc .getUri (), content , jsonExclusions );
289+ if (config . getJsonExclusions () != null && config . getJsonExclusions () .length > 0 ) {
290+ content = ContentExclusionUtil .applyJsonExclusions (doc .getUri (), content , config . getJsonExclusions () );
267291 }
268292 jc = new JsonCanonicalizer (content );
269293 return jc .getEncodedString ();
@@ -274,9 +298,9 @@ private String serializeContent(DocumentWriteOperation doc) {
274298 logger .warn ("Unable to canonicalize JSON content for URI {}, using original content for hashing; cause: {}" ,
275299 doc .getUri (), e .getMessage ());
276300 }
277- } else if (xmlExclusions != null && xmlExclusions .length > 0 ) {
301+ } else if (config . getXmlExclusions () != null && config . getXmlExclusions () .length > 0 ) {
278302 try {
279- content = ContentExclusionUtil .applyXmlExclusions (doc .getUri (), content , xmlNamespaces , xmlExclusions );
303+ content = ContentExclusionUtil .applyXmlExclusions (doc .getUri (), content , config . getXmlNamespaces (), config . getXmlExclusions () );
280304 } catch (Exception e ) {
281305 logger .warn ("Unable to apply XML exclusions for URI {}, using original content for hashing; cause: {}" ,
282306 doc .getUri (), e .getMessage ());
@@ -316,4 +340,6 @@ protected static DocumentWriteOperation addHashToMetadata(DocumentWriteOperation
316340
317341 return new DocumentWriteOperationImpl (op .getUri (), newMetadata , op .getContent (), op .getTemporalDocumentURI ());
318342 }
343+
344+
319345}
0 commit comments