Skip to content

Commit 421b3d6

Browse files
author
Ryan Dew
committed
MLE-29883 (GH #1938) Include document version in bulk reads
1 parent 0c45494 commit 421b3d6

3 files changed

Lines changed: 261 additions & 213 deletions

File tree

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

Lines changed: 27 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@
3636
import jakarta.mail.BodyPart;
3737
import jakarta.mail.Header;
3838
import jakarta.mail.MessagingException;
39-
import jakarta.mail.internet.ContentDisposition;
4039
import jakarta.mail.internet.MimeMultipart;
41-
import jakarta.mail.internet.ParseException;
4240
import jakarta.mail.util.ByteArrayDataSource;
4341
import jakarta.xml.bind.DatatypeConverter;
4442
import okhttp3.*;
@@ -68,6 +66,20 @@
6866
import java.util.stream.Collectors;
6967
import java.util.stream.Stream;
7068

69+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.copyDescriptor;
70+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.getHeader;
71+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.getHeaderFormat;
72+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.getHeaderLength;
73+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.getHeaderMimetype;
74+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.getHeaderUri;
75+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.getHeaderVersion;
76+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.updateDescriptor;
77+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.updateFormat;
78+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.updateLength;
79+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.updateMimetype;
80+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.updateServerTimestamp;
81+
import static com.marklogic.client.impl.okhttp.OkHttpUtil.updateVersion;
82+
7183
@SuppressWarnings({"unchecked", "rawtypes"})
7284
public class OkHttpServices implements RESTServices {
7385

@@ -1641,18 +1653,7 @@ static private boolean isExternalDescriptor(ContentDescriptor desc) {
16411653
&& !((DocumentDescriptorImpl) desc).isInternal();
16421654
}
16431655

1644-
static private void updateDescriptor(ContentDescriptor desc,
1645-
Headers headers) {
1646-
if (desc == null || headers == null) return;
1647-
1648-
updateFormat(desc, headers);
1649-
updateMimetype(desc, headers);
1650-
updateLength(desc, headers);
1651-
updateServerTimestamp(desc, headers);
1652-
}
1653-
1654-
static private TemporalDescriptor updateTemporalSystemTime(DocumentDescriptor desc,
1655-
Headers headers) {
1656+
static private TemporalDescriptor updateTemporalSystemTime(DocumentDescriptor desc, Headers headers) {
16561657
if (headers == null) return null;
16571658

16581659
DocumentDescriptorImpl temporalDescriptor;
@@ -1665,194 +1666,6 @@ static private TemporalDescriptor updateTemporalSystemTime(DocumentDescriptor de
16651666
return temporalDescriptor;
16661667
}
16671668

1668-
static private void copyDescriptor(DocumentDescriptor desc,
1669-
HandleImplementation handleBase) {
1670-
if (handleBase == null) return;
1671-
1672-
if (desc.getFormat() != null) handleBase.setFormat(desc.getFormat());
1673-
if (desc.getMimetype() != null) handleBase.setMimetype(desc.getMimetype());
1674-
handleBase.setByteLength(desc.getByteLength());
1675-
}
1676-
1677-
static private void updateFormat(ContentDescriptor descriptor,
1678-
Headers headers) {
1679-
updateFormat(descriptor, getHeaderFormat(headers));
1680-
}
1681-
1682-
static private void updateFormat(ContentDescriptor descriptor, Format format) {
1683-
if (format != null) {
1684-
descriptor.setFormat(format);
1685-
}
1686-
}
1687-
1688-
static private Format getHeaderFormat(Headers headers) {
1689-
String format = headers.get(HEADER_VND_MARKLOGIC_DOCUMENT_FORMAT);
1690-
if (format != null && format.length() > 0) {
1691-
return Format.valueOf(format.toUpperCase());
1692-
}
1693-
String contentType = headers.get(HEADER_CONTENT_TYPE);
1694-
if (contentType != null && contentType.length() > 0) {
1695-
return Format.getFromMimetype(contentType);
1696-
}
1697-
return null;
1698-
}
1699-
1700-
static private Format getHeaderFormat(BodyPart part) {
1701-
String contentDisposition = getHeader(part, HEADER_CONTENT_DISPOSITION);
1702-
String formatRegex = ".* format=(text|binary|xml|json).*";
1703-
String format = getHeader(part, HEADER_VND_MARKLOGIC_DOCUMENT_FORMAT);
1704-
String contentType = getHeader(part, HEADER_CONTENT_TYPE);
1705-
if (format != null && format.length() > 0) {
1706-
return Format.valueOf(format.toUpperCase());
1707-
} else if (contentDisposition != null && contentDisposition.matches(formatRegex)) {
1708-
format = contentDisposition.replaceFirst("^.*" + formatRegex + ".*$", "$1");
1709-
return Format.valueOf(format.toUpperCase());
1710-
} else if (contentType != null && contentType.length() > 0) {
1711-
return Format.getFromMimetype(contentType);
1712-
}
1713-
return null;
1714-
}
1715-
1716-
static private void updateMimetype(ContentDescriptor descriptor,
1717-
Headers headers) {
1718-
updateMimetype(descriptor, getHeaderMimetype(headers.get(HEADER_CONTENT_TYPE)));
1719-
}
1720-
1721-
static private void updateMimetype(ContentDescriptor descriptor, String mimetype) {
1722-
if (mimetype != null) {
1723-
descriptor.setMimetype(mimetype);
1724-
}
1725-
}
1726-
1727-
static private String getHeader(Map<String, List<String>> headers, String name) {
1728-
List<String> values = headers.get(name);
1729-
if (values != null && values.size() > 0) {
1730-
return values.get(0);
1731-
}
1732-
return null;
1733-
}
1734-
1735-
static private String getHeader(BodyPart part, String name) {
1736-
if (part == null) throw new MarkLogicInternalException("part must not be null");
1737-
try {
1738-
String[] values = part.getHeader(name);
1739-
if (values != null && values.length > 0) {
1740-
return values[0];
1741-
}
1742-
return null;
1743-
} catch (MessagingException e) {
1744-
throw new MarkLogicIOException(e);
1745-
}
1746-
}
1747-
1748-
static private String getHeaderMimetype(String contentType) {
1749-
if (contentType != null) {
1750-
int offset = contentType.indexOf(";");
1751-
String mimetype = (offset == -1) ? contentType : contentType.substring(0, offset);
1752-
// TODO: if "; charset=foo" set character set
1753-
if (mimetype != null && mimetype.length() > 0) {
1754-
return mimetype;
1755-
}
1756-
}
1757-
return null;
1758-
}
1759-
1760-
static private void updateLength(ContentDescriptor descriptor,
1761-
Headers headers) {
1762-
updateLength(descriptor, getHeaderLength(headers.get(HEADER_CONTENT_LENGTH)));
1763-
}
1764-
1765-
static private void updateLength(ContentDescriptor descriptor, long length) {
1766-
descriptor.setByteLength(length);
1767-
}
1768-
1769-
static private void updateServerTimestamp(ContentDescriptor descriptor,
1770-
Headers headers) {
1771-
updateServerTimestamp(descriptor, getHeaderServerTimestamp(headers));
1772-
}
1773-
1774-
static private long getHeaderServerTimestamp(Headers headers) {
1775-
return Utilities.parseLong(headers.get(HEADER_ML_EFFECTIVE_TIMESTAMP));
1776-
}
1777-
1778-
static private void updateServerTimestamp(ContentDescriptor descriptor, long timestamp) {
1779-
if (descriptor instanceof HandleImplementation) {
1780-
if (descriptor != null && timestamp != -1) {
1781-
((HandleImplementation) descriptor).setResponseServerTimestamp(timestamp);
1782-
}
1783-
}
1784-
}
1785-
1786-
static private long getHeaderLength(String length) {
1787-
return Utilities.parseLong(length, ContentDescriptor.UNKNOWN_LENGTH);
1788-
}
1789-
1790-
static private String getHeaderUri(BodyPart part) {
1791-
try {
1792-
if (part == null) {
1793-
return null;
1794-
}
1795-
1796-
try {
1797-
String filename = part.getFileName();
1798-
if (filename != null) {
1799-
return filename;
1800-
}
1801-
} catch (ParseException e) {
1802-
// Jakarta Mail's parser failed due to malformed Content-Disposition header.
1803-
// Check if MarkLogic sent a malformed "format=" parameter at the end, which violates RFC 2183.
1804-
String contentDisposition = getHeader(part, "Content-Disposition");
1805-
if (contentDisposition != null && contentDisposition.matches(".*;\\s*format\\s*=\\s*$")) {
1806-
// Remove the trailing "; format=" to fix the malformed header
1807-
String cleaned = contentDisposition.replaceFirst(";\\s*format\\s*=\\s*$", "").trim();
1808-
logger.debug("Removed trailing 'format=' from malformed Content-Disposition header: {} -> {}", contentDisposition, cleaned);
1809-
return extractFilenameFromContentDisposition(cleaned);
1810-
}
1811-
throw e;
1812-
}
1813-
1814-
return null;
1815-
} catch (MessagingException e) {
1816-
throw new MarkLogicIOException(e);
1817-
}
1818-
}
1819-
1820-
static private String extractFilenameFromContentDisposition(String contentDisposition) {
1821-
if (contentDisposition == null) {
1822-
return null;
1823-
}
1824-
try {
1825-
// Use Jakarta Mail's ContentDisposition parser to extract the filename parameter. This is the class
1826-
// that throws an error when "format=" exists in the value, but that has been removed already.
1827-
ContentDisposition cd = new ContentDisposition(contentDisposition);
1828-
return cd.getParameter("filename");
1829-
} catch (ParseException e) {
1830-
logger.warn("Failed to parse cleaned Content-Disposition header: {}; cause: {}",
1831-
contentDisposition, e.getMessage());
1832-
return null;
1833-
}
1834-
}
1835-
1836-
static private void updateVersion(DocumentDescriptor descriptor, Headers headers) {
1837-
updateVersion(descriptor, extractVersion(headers.get(HEADER_ETAG)));
1838-
}
1839-
1840-
static private void updateVersion(DocumentDescriptor descriptor, String header) {
1841-
updateVersion(descriptor, extractVersion(header));
1842-
}
1843-
1844-
static private void updateVersion(DocumentDescriptor descriptor, long version) {
1845-
descriptor.setVersion(version);
1846-
}
1847-
1848-
static private long extractVersion(String header) {
1849-
if (header != null && header.length() > 0) {
1850-
// trim the double quotes
1851-
return Long.parseLong(header.substring(1, header.length() - 1));
1852-
}
1853-
return DocumentDescriptor.UNKNOWN_VERSION;
1854-
}
1855-
18561669
static private Request.Builder addVersionHeader(DocumentDescriptor desc, Request.Builder requestBldr, String name) {
18571670
if (desc != null &&
18581671
desc instanceof DocumentDescriptorImpl &&
@@ -1869,8 +1682,8 @@ static private <R extends AbstractReadHandle> R updateHandle(BodyPart part, R ha
18691682
HandleImplementation handleBase = HandleAccessor.as(handle);
18701683

18711684
updateFormat(handleBase, getHeaderFormat(part));
1872-
updateMimetype(handleBase, getHeaderMimetype(OkHttpServices.getHeader(part, HEADER_CONTENT_TYPE)));
1873-
updateLength(handleBase, getHeaderLength(OkHttpServices.getHeader(part, HEADER_CONTENT_LENGTH)));
1685+
updateMimetype(handleBase, getHeaderMimetype(getHeader(part, HEADER_CONTENT_TYPE)));
1686+
updateLength(handleBase, getHeaderLength(getHeader(part, HEADER_CONTENT_LENGTH)));
18741687
handleBase.receiveContent(getEntity(part, handleBase.receiveAs()));
18751688

18761689
return handle;
@@ -4436,6 +4249,7 @@ static class OkHttpResult {
44364249
private Format format;
44374250
private String mimetype;
44384251
private long length;
4252+
private long version = DocumentDescriptor.UNKNOWN_VERSION;
44394253

44404254
OkHttpResult(RequestLogger reqlog, BodyPart part) {
44414255
this.reqlog = reqlog;
@@ -4490,6 +4304,11 @@ public long getLength() {
44904304
return length;
44914305
}
44924306

4307+
public long getVersion() {
4308+
extractHeaders();
4309+
return version;
4310+
}
4311+
44934312
public String getHeader(String name) {
44944313
extractHeaders();
44954314
List<String> values = headers.get(name);
@@ -4512,9 +4331,10 @@ private void extractHeaders() {
45124331
headers.put(header.getName(), header.getValue());
45134332
}
45144333
format = getHeaderFormat(part);
4515-
mimetype = getHeaderMimetype(OkHttpServices.getHeader(part, HEADER_CONTENT_TYPE));
4516-
length = getHeaderLength(OkHttpServices.getHeader(part, HEADER_CONTENT_LENGTH));
4334+
mimetype = getHeaderMimetype(OkHttpUtil.getHeader(part, HEADER_CONTENT_TYPE));
4335+
length = getHeaderLength(OkHttpUtil.getHeader(part, HEADER_CONTENT_LENGTH));
45174336
uri = getHeaderUri(part);
4337+
version = getHeaderVersion(part);
45184338
extractedHeaders = true;
45194339
} catch (MessagingException e) {
45204340
throw new MarkLogicIOException(e);
@@ -4688,7 +4508,7 @@ public DocumentDescriptor getDescriptor() {
46884508
updateFormat(descriptor, getFormat());
46894509
updateMimetype(descriptor, getMimetype());
46904510
updateLength(descriptor, getLength());
4691-
updateVersion(descriptor, content.getHeader(HEADER_ETAG));
4511+
updateVersion(descriptor, content.getVersion());
46924512
return descriptor;
46934513
}
46944514

0 commit comments

Comments
 (0)