Skip to content

Commit b9b4ad0

Browse files
committed
DEVEXP-469 Optimistic locking failures now throw concrete exceptions
Users no longer need to parse out exception messages. And now `TestOptimisticLocking` doesn't need to either, which allowed me to delete a bunch of code from it in favor of asserting on specific exception classes. This is a non-breaking change as the new exceptions are subclasses of `FailedRequestException` and contain the same error message.
1 parent 091ccad commit b9b4ad0

File tree

4 files changed

+56
-162
lines changed

4 files changed

+56
-162
lines changed

marklogic-client-api-functionaltests/src/test/java/com/marklogic/client/fastfunctest/TestOptimisticLocking.java

Lines changed: 17 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package com.marklogic.client.fastfunctest;
1818

1919
import com.fasterxml.jackson.databind.JsonNode;
20+
import com.marklogic.client.ContentNoVersionException;
21+
import com.marklogic.client.ContentWrongVersionException;
2022
import com.marklogic.client.DatabaseClient;
2123
import com.marklogic.client.FailedRequestException;
2224
import com.marklogic.client.ResourceNotFoundException;
@@ -46,7 +48,7 @@
4648
import java.security.NoSuchAlgorithmException;
4749
import java.time.Instant;
4850
import java.time.temporal.ChronoUnit;
49-
51+
import java.util.concurrent.atomic.AtomicReference;
5052

5153

5254
public class TestOptimisticLocking extends AbstractFunctionalTest {
@@ -109,24 +111,10 @@ public void testRequired() throws KeyManagementException, NoSuchAlgorithmExcepti
109111

110112
// create document descriptor
111113
DocumentDescriptor desc = docMgr.newDescriptor(docId);
114+
AtomicReference<DocumentDescriptor> descRef = new AtomicReference<>(desc);
112115

113116
desc.setVersion(badVersion);
114-
115-
String exception = "";
116-
String expectedException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to write document. Server Message: RESTAPI-CONTENTWRONGVERSION: (err:FOER0000) Content version mismatch: uri /optimistic-locking/xml-original.xml doesn't match if-match: 1111";
117-
118-
// CREATE
119-
// write document with bad version
120-
try
121-
{
122-
docMgr.write(desc, handle);
123-
} catch (FailedRequestException e) {
124-
exception = e.toString();
125-
}
126-
127-
boolean isExceptionThrown = exception.contains(expectedException);
128-
assertTrue( isExceptionThrown);
129-
System.out.println(exception);
117+
assertThrows(ContentWrongVersionException.class, () -> docMgr.write(descRef.get(), handle));
130118

131119
// write document with unknown version
132120
desc.setVersion(DocumentDescriptor.UNKNOWN_VERSION);
@@ -151,36 +139,14 @@ public void testRequired() throws KeyManagementException, NoSuchAlgorithmExcepti
151139

152140
// update with bad version
153141
desc.setVersion(badVersion);
154-
155-
String updateException = "";
156-
String expectedUpdateException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to write document. Server Message: RESTAPI-CONTENTWRONGVERSION: (err:FOER0000) Content version mismatch: uri /optimistic-locking/xml-original.xml has current version";
157-
158-
try {
159-
docMgr.write(desc, updateHandle);
160-
} catch (FailedRequestException e) {
161-
updateException = e.toString();
162-
}
163-
System.out.println(updateException);
164-
boolean isUpdateExceptionThrown = updateException.contains(expectedUpdateException);
165-
assertTrue( isUpdateExceptionThrown);
142+
assertThrows(ContentWrongVersionException.class, () -> docMgr.write(descRef.get(), updateHandle));
166143

167144
// update with unknown version
168145
desc.setVersion(DocumentDescriptor.UNKNOWN_VERSION);
169-
170-
String updateUnknownException = "";
171-
String expectedUpdateUnknownException = "com.marklogic.client.FailedRequestException: Local message: Content version required to write document. Server Message: RESTAPI-CONTENTNOVERSION: (err:FOER0000) No content version supplied: uri /optimistic-locking/xml-original.xml";
172-
173-
try {
174-
docMgr.write(desc, updateHandle);
175-
} catch (FailedRequestException e) {
176-
updateUnknownException = e.toString();
177-
}
178-
179-
boolean isUpdateUnknownExceptionThrown = updateUnknownException.contains(expectedUpdateUnknownException);
180-
System.out.println(updateUnknownException);
181-
assertTrue( isUpdateUnknownExceptionThrown);
146+
assertThrows(ContentNoVersionException.class, () -> docMgr.write(descRef.get(), updateHandle));
182147

183148
desc = docMgr.exists(docId);
149+
descRef.set(desc);
184150
goodVersion = desc.getVersion();
185151

186152
System.out.println("version before update: " + goodVersion);
@@ -197,35 +163,11 @@ public void testRequired() throws KeyManagementException, NoSuchAlgorithmExcepti
197163
// DELETE
198164
// delete using bad version
199165
desc.setVersion(badVersion);
200-
201-
String deleteException = "";
202-
String expectedDeleteException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to delete document. Server Message: RESTAPI-CONTENTWRONGVERSION: (err:FOER0000) Content version mismatch: uri /optimistic-locking/xml-original.xml has current version";
203-
204-
try {
205-
docMgr.delete(desc);
206-
} catch (FailedRequestException e) {
207-
deleteException = e.toString();
208-
}
209-
210-
boolean isDeleteExceptionThrown = deleteException.contains(expectedDeleteException);
211-
System.out.println("Delete exception" + deleteException);
212-
assertTrue( isDeleteExceptionThrown);
166+
assertThrows(ContentWrongVersionException.class, () -> docMgr.delete(descRef.get()));
213167

214168
// delete using unknown version
215169
desc.setVersion(DocumentDescriptor.UNKNOWN_VERSION);
216-
217-
String deleteUnknownException = "";
218-
String expectedDeleteUnknownException = "com.marklogic.client.FailedRequestException: Local message: Content version required to delete document. Server Message: RESTAPI-CONTENTNOVERSION: (err:FOER0000) No content version supplied: uri /optimistic-locking/xml-original.xml";
219-
220-
try {
221-
docMgr.delete(desc);
222-
} catch (FailedRequestException e) {
223-
deleteUnknownException = e.toString();
224-
}
225-
226-
boolean isDeleteUnknownExceptionThrown = deleteUnknownException.contains(expectedDeleteUnknownException);
227-
System.out.println("Delete exception" + deleteUnknownException);
228-
assertTrue( isDeleteUnknownExceptionThrown);
170+
assertThrows(ContentNoVersionException.class, () -> docMgr.delete(descRef.get()));
229171

230172
// delete using good version
231173
desc = docMgr.exists(docId);
@@ -291,20 +233,7 @@ public void testOptionalWithUnknownVersion() throws KeyManagementException, NoSu
291233
DocumentDescriptor desc = docMgr.newDescriptor(docId);
292234

293235
desc.setVersion(badVersion);
294-
295-
String exception = "";
296-
String expectedException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to write document. Server Message: RESTAPI-CONTENTWRONGVERSION";
297-
298-
// CREATE
299-
// write document with bad version
300-
try {
301-
docMgr.write(desc, handle);
302-
} catch (FailedRequestException e) {
303-
exception = e.toString();
304-
}
305-
306-
boolean isExceptionThrown = exception.contains(expectedException);
307-
assertTrue( isExceptionThrown);
236+
assertThrows(ContentWrongVersionException.class, () -> docMgr.write(desc, handle));
308237

309238
// write document with unknown version
310239
desc.setVersion(DocumentDescriptor.UNKNOWN_VERSION);
@@ -329,18 +258,7 @@ public void testOptionalWithUnknownVersion() throws KeyManagementException, NoSu
329258

330259
// update with bad version
331260
desc.setVersion(badVersion);
332-
333-
String updateException = "";
334-
String expectedUpdateException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to write document. Server Message: RESTAPI-CONTENTWRONGVERSION";
335-
336-
try {
337-
docMgr.write(desc, updateHandle);
338-
} catch (FailedRequestException e) {
339-
updateException = e.toString();
340-
}
341-
342-
boolean isUpdateExceptionThrown = updateException.contains(expectedUpdateException);
343-
assertTrue( isUpdateExceptionThrown);
261+
assertThrows(ContentWrongVersionException.class, () -> docMgr.write(desc, updateHandle));
344262

345263
// update with unknown version
346264
desc.setVersion(DocumentDescriptor.UNKNOWN_VERSION);
@@ -366,18 +284,7 @@ public void testOptionalWithUnknownVersion() throws KeyManagementException, NoSu
366284
// DELETE
367285
// delete using bad version
368286
desc.setVersion(badVersion);
369-
370-
String deleteException = "";
371-
String expectedDeleteException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to delete document";
372-
373-
try {
374-
docMgr.delete(desc);
375-
} catch (FailedRequestException e) {
376-
deleteException = e.toString();
377-
}
378-
379-
boolean isDeleteExceptionThrown = deleteException.contains(expectedDeleteException);
380-
assertTrue( isDeleteExceptionThrown);
287+
assertThrows(ContentWrongVersionException.class, () -> docMgr.delete(desc));
381288

382289
// delete using unknown version
383290
desc.setVersion(DocumentDescriptor.UNKNOWN_VERSION);
@@ -441,21 +348,10 @@ public void testOptionalWithGoodVersion() throws KeyManagementException, NoSuchA
441348
// create document descriptor
442349
DocumentDescriptor desc = docMgr.newDescriptor(docId);
443350

444-
desc.setVersion(badVersion);
445-
446-
String exception = "";
447-
String expectedException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to write document. Server Message: RESTAPI-CONTENTWRONGVERSION";
448-
449351
// CREATE
450352
// write document with bad version
451-
try {
452-
docMgr.write(desc, handle);
453-
} catch (FailedRequestException e) {
454-
exception = e.toString();
455-
}
456-
457-
boolean isExceptionThrown = exception.contains(expectedException);
458-
assertTrue( isExceptionThrown);
353+
desc.setVersion(badVersion);
354+
assertThrows(ContentWrongVersionException.class, () -> docMgr.write(desc, handle));
459355

460356
// write document with unknown version
461357
desc.setVersion(DocumentDescriptor.UNKNOWN_VERSION);
@@ -480,18 +376,7 @@ public void testOptionalWithGoodVersion() throws KeyManagementException, NoSuchA
480376

481377
// update with bad version
482378
desc.setVersion(badVersion);
483-
484-
String updateException = "";
485-
String expectedUpdateException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to write document. Server Message: RESTAPI-CONTENTWRONGVERSION";
486-
487-
try {
488-
docMgr.write(desc, updateHandle);
489-
} catch (FailedRequestException e) {
490-
updateException = e.toString();
491-
}
492-
493-
boolean isUpdateExceptionThrown = updateException.contains(expectedUpdateException);
494-
assertTrue( isUpdateExceptionThrown);
379+
assertThrows(ContentWrongVersionException.class, () -> docMgr.write(desc, updateHandle));
495380

496381
// update with good version
497382
desc.setVersion(goodVersion);
@@ -517,18 +402,7 @@ public void testOptionalWithGoodVersion() throws KeyManagementException, NoSuchA
517402
// DELETE
518403
// delete using bad version
519404
desc.setVersion(badVersion);
520-
521-
String deleteException = "";
522-
String expectedDeleteException = "com.marklogic.client.FailedRequestException: Local message: Content version must match to delete document";
523-
524-
try {
525-
docMgr.delete(desc);
526-
} catch (FailedRequestException e) {
527-
deleteException = e.toString();
528-
}
529-
530-
boolean isDeleteExceptionThrown = deleteException.contains(expectedDeleteException);
531-
assertTrue( isDeleteExceptionThrown);
405+
assertThrows(ContentWrongVersionException.class, () -> docMgr.delete(desc));
532406

533407
// delete using good version
534408
desc.setVersion(goodVersion);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.marklogic.client;
2+
3+
import com.marklogic.client.impl.FailedRequest;
4+
5+
/**
6+
* Represents a "RESTAPI-CONTENTNOVERSION" error from the REST API that can occur when using optimistic locking.
7+
*
8+
* @since 6.3.0
9+
*/
10+
public class ContentNoVersionException extends FailedRequestException {
11+
12+
public ContentNoVersionException(String message, FailedRequest failedRequest) {
13+
super(message, failedRequest);
14+
}
15+
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.marklogic.client;
2+
3+
import com.marklogic.client.impl.FailedRequest;
4+
5+
/**
6+
* Represents a "RESTAPI-CONTENTWRONGVERSION" error from the REST API that can occur when using optimistic locking.
7+
*
8+
* @since 6.3.0
9+
*/
10+
public class ContentWrongVersionException extends FailedRequestException {
11+
12+
public ContentWrongVersionException(String message, FailedRequest failedRequest) {
13+
super(message, failedRequest);
14+
}
15+
16+
}

marklogic-client-api/src/main/java/com/marklogic/client/impl/OkHttpServices.java

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,7 @@
1818
import com.fasterxml.jackson.databind.ObjectMapper;
1919
import com.marklogic.client.*;
2020
import com.marklogic.client.DatabaseClient.ConnectionResult;
21-
import com.marklogic.client.DatabaseClientFactory.BasicAuthContext;
22-
import com.marklogic.client.DatabaseClientFactory.CertificateAuthContext;
2321
import com.marklogic.client.DatabaseClientFactory.DigestAuthContext;
24-
import com.marklogic.client.DatabaseClientFactory.KerberosAuthContext;
25-
import com.marklogic.client.DatabaseClientFactory.MarkLogicCloudAuthContext;
26-
import com.marklogic.client.DatabaseClientFactory.SAMLAuthContext;
27-
import com.marklogic.client.DatabaseClientFactory.SSLHostnameVerifier;
2822
import com.marklogic.client.DatabaseClientFactory.SecurityContext;
2923
import com.marklogic.client.bitemporal.TemporalDescriptor;
3024
import com.marklogic.client.bitemporal.TemporalDocumentManager.ProtectionLevel;
@@ -437,7 +431,7 @@ public Response apply(Request.Builder funcBuilder) {
437431
if (status == STATUS_PRECONDITION_REQUIRED) {
438432
FailedRequest failure = extractErrorFields(response);
439433
if (failure.getMessageCode().equals("RESTAPI-CONTENTNOVERSION")) {
440-
throw new FailedRequestException(
434+
throw new ContentNoVersionException(
441435
"Content version required to delete document", failure);
442436
}
443437
throw new FailedRequestException(
@@ -450,9 +444,7 @@ public Response apply(Request.Builder funcBuilder) {
450444
if (status == STATUS_PRECONDITION_FAILED) {
451445
FailedRequest failure = extractErrorFields(response);
452446
if (failure.getMessageCode().equals("RESTAPI-CONTENTWRONGVERSION")) {
453-
throw new FailedRequestException(
454-
"Content version must match to delete document",
455-
failure);
447+
throw new ContentWrongVersionException("Content version must match to delete document", failure);
456448
} else if (failure.getMessageCode().equals("RESTAPI-EMPTYBODY")) {
457449
throw new FailedRequestException(
458450
"Empty request body sent to server", failure);
@@ -1308,8 +1300,7 @@ private TemporalDescriptor putPostDocumentImpl(RequestLogger reqlog, String meth
13081300
if (status == STATUS_PRECONDITION_REQUIRED) {
13091301
FailedRequest failure = extractErrorFields(response);
13101302
if (failure.getMessageCode().equals("RESTAPI-CONTENTNOVERSION")) {
1311-
throw new FailedRequestException(
1312-
"Content version required to write document", failure);
1303+
throw new ContentNoVersionException("Content version required to write document", failure);
13131304
}
13141305
throw new FailedRequestException(
13151306
"Precondition required to write document", failure);
@@ -1321,8 +1312,7 @@ private TemporalDescriptor putPostDocumentImpl(RequestLogger reqlog, String meth
13211312
if (status == STATUS_PRECONDITION_FAILED) {
13221313
FailedRequest failure = extractErrorFields(response);
13231314
if (failure.getMessageCode().equals("RESTAPI-CONTENTWRONGVERSION")) {
1324-
throw new FailedRequestException(
1325-
"Content version must match to write document", failure);
1315+
throw new ContentWrongVersionException("Content version must match to write document", failure);
13261316
} else if (failure.getMessageCode().equals("RESTAPI-EMPTYBODY")) {
13271317
throw new FailedRequestException(
13281318
"Empty request body sent to server", failure);
@@ -1453,8 +1443,7 @@ private TemporalDescriptor putPostDocumentImpl(RequestLogger reqlog, String meth
14531443
if (status == STATUS_PRECONDITION_REQUIRED) {
14541444
FailedRequest failure = extractErrorFields(response);
14551445
if (failure.getMessageCode().equals("RESTAPI-CONTENTNOVERSION")) {
1456-
throw new FailedRequestException(
1457-
"Content version required to write document", failure);
1446+
throw new ContentNoVersionException("Content version required to write document", failure);
14581447
}
14591448
throw new FailedRequestException(
14601449
"Precondition required to write document", failure);
@@ -1466,8 +1455,7 @@ private TemporalDescriptor putPostDocumentImpl(RequestLogger reqlog, String meth
14661455
if (status == STATUS_PRECONDITION_FAILED) {
14671456
FailedRequest failure = extractErrorFields(response);
14681457
if (failure.getMessageCode().equals("RESTAPI-CONTENTWRONGVERSION")) {
1469-
throw new FailedRequestException(
1470-
"Content version must match to write document", failure);
1458+
throw new ContentWrongVersionException("Content version must match to write document", failure);
14711459
} else if (failure.getMessageCode().equals("RESTAPI-EMPTYBODY")) {
14721460
throw new FailedRequestException(
14731461
"Empty request body sent to server", failure);
@@ -4398,7 +4386,7 @@ private void checkStatus(Response response, int status, String operation, String
43984386
failure);
43994387
}
44004388
if ("RESTAPI-CONTENTNOVERSION".equals(failure.getMessageCode())) {
4401-
throw new FailedRequestException("Content version required to " +
4389+
throw new ContentNoVersionException("Content version required to " +
44024390
operation + " " + entityType + " at " + path, failure);
44034391
} else if (status == STATUS_FORBIDDEN) {
44044392
throw new ForbiddenUserException("User is not allowed to "

0 commit comments

Comments
 (0)