3636import jakarta .mail .BodyPart ;
3737import jakarta .mail .Header ;
3838import jakarta .mail .MessagingException ;
39- import jakarta .mail .internet .ContentDisposition ;
4039import jakarta .mail .internet .MimeMultipart ;
41- import jakarta .mail .internet .ParseException ;
4240import jakarta .mail .util .ByteArrayDataSource ;
4341import jakarta .xml .bind .DatatypeConverter ;
4442import okhttp3 .*;
6866import java .util .stream .Collectors ;
6967import 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" })
7284public 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