Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions changelog/unreleased/PR#4528-ResponseParser_getContentType.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# (DELETE ALL COMMENTS UP HERE AFTER FILLING THIS IN

# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc

# If the change is minor, don't bother adding a changelog entry.
# For `other` type entries, the threshold to bother with a changelog entry should be even higher.

# title:
# * The audience is end-users and administrators, not committers.
# * Be short and focused on the user impact. Multiple sentences is fine!
# * For technical/geeky details, prefer the commit message instead of changelog.
# * Reference JIRA issues like `SOLR-12345`, or if no JIRA but have a GitHub PR then `PR#12345`.

# type:
# `added` for new features/improvements, opt-in by the user typically documented in the ref guide
# `changed` for improvements; not opt-in
# `fixed` for improvements that are deemed to have fixed buggy behavior
# `deprecated` for marking things deprecated
# `removed` for code removed
# `dependency_update` for updates to dependencies
# `other` for anything else, like large/significant refactorings, build changes,
# test infrastructure, or documentation.
# Most such changes are too small/minor to bother with a changelog entry.

title: >
Simplify SolrJ ResponseParser.getContentType processing. getContentType must now return a Set.
type: other
authors:
- name: David Smiley
links:
- name: PR#4528
url: https://github.com/apache/solr/pull/4528
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.apache.solr.JSONTestUtil;
Expand Down Expand Up @@ -106,9 +105,12 @@ public NamedList<Object> processResponse(InputStream body, String encoding) thro
return new NamedList(m);
}

private static final Set<String> CONTENT_TYPES =
Set.of("application/x-jackson-smile", "application/octet-stream");

@Override
public Collection<String> getContentTypes() {
return Set.of("application/x-jackson-smile", "application/octet-stream");
public Set<String> getContentTypes() {
return CONTENT_TYPES;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
Expand All @@ -37,7 +36,6 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
import org.apache.solr.client.api.util.SolrVersion;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
Expand Down Expand Up @@ -161,7 +159,6 @@ protected HttpJettySolrClient(String serverBaseUrl, Builder builder) {
this.listenerFactory = new ArrayList<>(0);
}

updateDefaultMimeTypeForParser();
this.idleTimeoutMillis = builder.getIdleTimeoutMillis();

try {
Expand Down Expand Up @@ -807,31 +804,6 @@ protected boolean isFollowRedirects() {
return httpClient.isFollowRedirects();
}

@Override
protected boolean processorAcceptsMimeType(
Collection<String> processorSupportedContentTypes, String mimeType) {

return processorSupportedContentTypes.stream()
.map(ct -> MimeTypes.getContentTypeWithoutCharset(ct).trim())
.anyMatch(mimeType::equalsIgnoreCase);
}

@Override
protected void updateDefaultMimeTypeForParser() {
defaultParserMimeTypes =
parser.getContentTypes().stream()
.map(ct -> MimeTypes.getContentTypeWithoutCharset(ct).trim().toLowerCase(Locale.ROOT))
.collect(Collectors.toSet());
}

@Override
protected String allProcessorSupportedContentTypesCommaDelimited(
Collection<String> processorSupportedContentTypes) {
return processorSupportedContentTypes.stream()
.map(ct -> MimeTypes.getContentTypeWithoutCharset(ct).trim().toLowerCase(Locale.ROOT))
.collect(Collectors.joining(", "));
}

/**
* An HttpJettySolrClient that doesn't close or cleanup any resources
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
Expand All @@ -46,7 +45,6 @@
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.net.ssl.SSLContext;
import org.apache.solr.client.api.util.SolrVersion;
import org.apache.solr.client.solrj.SolrRequest;
Expand Down Expand Up @@ -139,7 +137,6 @@ protected HttpJdkSolrClient(String serverBaseUrl, HttpJdkSolrClient.Builder buil
ProxySelector.of(new InetSocketAddress(builder.getProxyHost(), builder.getProxyPort())));
}
this.httpClient = b.build();
updateDefaultMimeTypeForParser();

assert ObjectReleaseTracker.track(this);
}
Expand Down Expand Up @@ -537,36 +534,6 @@ protected boolean isFollowRedirects() {
return httpClient.followRedirects() != HttpClient.Redirect.NEVER;
}

@Override
protected boolean processorAcceptsMimeType(
Collection<String> processorSupportedContentTypes, String mimeType) {
return processorSupportedContentTypes.stream()
.map(this::contentTypeToMimeType)
.filter(Objects::nonNull)
.map(String::trim)
.anyMatch(mimeType::equalsIgnoreCase);
}

@Override
protected void updateDefaultMimeTypeForParser() {
defaultParserMimeTypes =
parser.getContentTypes().stream()
.map(this::contentTypeToMimeType)
.filter(Objects::nonNull)
.map(s -> s.toLowerCase(Locale.ROOT).trim())
.collect(Collectors.toSet());
}

@Override
protected String allProcessorSupportedContentTypesCommaDelimited(
Collection<String> processorSupportedContentTypes) {
return processorSupportedContentTypes.stream()
.map(this::contentTypeToMimeType)
.filter(Objects::nonNull)
.map(s -> s.toLowerCase(Locale.ROOT).trim())
.collect(Collectors.joining(", "));
}

@Override
protected BuilderBase<?, ?> toBuilder(String baseUrl) {
return new HttpJdkSolrClient.Builder(baseUrl).withHttpClient(this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collection;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
Expand Down Expand Up @@ -72,11 +73,8 @@ public abstract class HttpSolrClient extends SolrClient {

protected RequestWriter requestWriter = new JavaBinRequestWriter();

// updating parser instance needs to go via the setter to ensure update of defaultParserMimeTypes
protected ResponseParser parser = new JavaBinResponseParser();

protected Set<String> defaultParserMimeTypes;

protected final String basicAuthAuthorizationStr;

protected HttpSolrClient(String serverBaseUrl, BuilderBase<?, ?> builder) {
Expand Down Expand Up @@ -268,12 +266,6 @@ protected boolean wantStream(final ResponseParser processor) {
return processor == null || processor instanceof InputStreamResponseParser;
}

protected abstract boolean processorAcceptsMimeType(
Collection<String> processorSupportedContentTypes, String mimeType);

protected abstract String allProcessorSupportedContentTypesCommaDelimited(
Collection<String> processorSupportedContentTypes);

/**
* Validates that the content type in the response can be processed by the Response Parser. Throws
* a {@code RemoteSolrException} if not.
Expand All @@ -285,19 +277,15 @@ private void checkContentType(
String encoding,
int httpStatus,
String urlExceptionMessage) {
if (mimeType == null
|| (processor == this.parser && defaultParserMimeTypes.contains(mimeType))) {
// Shortcut the default scenario
if (mimeType == null) {
return;
}
final Collection<String> processorSupportedContentTypes = processor.getContentTypes();
if (!processorSupportedContentTypes.isEmpty()) {
boolean processorAcceptsMimeType =
processorAcceptsMimeType(processorSupportedContentTypes, mimeType);
if (!processorAcceptsMimeType) {
final String normalizedMimeType = mimeType.toLowerCase(Locale.ROOT).trim();
if (!processorSupportedContentTypes.contains(normalizedMimeType)) {
// unexpected mime type
final String allSupportedTypes =
allProcessorSupportedContentTypesCommaDelimited(processorSupportedContentTypes);
final String allSupportedTypes = String.join(", ", processorSupportedContentTypes);
String prefix =
"Expected mime type in [" + allSupportedTypes + "] but got " + mimeType + ". ";
String exceptionEncoding = encoding != null ? encoding : FALLBACK_CHARSET.name();
Expand All @@ -324,11 +312,8 @@ protected static String basicAuthCredentialsToAuthorizationString(String user, S

protected void setParser(ResponseParser parser) {
this.parser = parser;
updateDefaultMimeTypeForParser();
}

protected abstract void updateDefaultMimeTypeForParser();

/**
* Executes a SolrRequest using the provided URL to temporarily override any "base URL" currently
* used by this client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Set;
import org.apache.solr.common.util.JavaBinCodec;
import org.apache.solr.common.util.NamedList;
Expand Down Expand Up @@ -52,8 +51,11 @@ protected JavaBinCodec createCodec() {
return new JavaBinCodec(null, stringCache);
}

private static final Set<String> CONTENT_TYPES =
Set.of(JAVABIN_CONTENT_TYPE, JAVABIN_CONTENT_TYPE_V2);

@Override
public Collection<String> getContentTypes() {
return Set.of(JAVABIN_CONTENT_TYPE, JAVABIN_CONTENT_TYPE_V2);
public Set<String> getContentTypes() {
return CONTENT_TYPES;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.Locale;
import java.util.Set;
import org.apache.solr.common.util.NamedList;

/**
Expand All @@ -28,17 +30,40 @@
*/
public abstract class ResponseParser {

protected ResponseParser() {
assert validateContentTypes();
}

private boolean validateContentTypes() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best place for validation is here when instantiating. These are new rules... if someone actually has a custom non-compliant impl, they'll find out.

Collection<String> contentTypes = getContentTypes();
assert contentTypes == getContentTypes()
: getClass().getName() + ".getContentTypes() must return the same instance on every call";
for (String ct : contentTypes) {
assert !ct.contains(";") && ct.equals(ct.toLowerCase(Locale.ROOT))
: getClass().getName()
+ ".getContentTypes() must return lowercase MIME types without semicolons, got: "
+ ct;
}
return true;
}

/** The writer type placed onto the request as the {@code wt} param. */
public abstract String getWriterType(); // for example: wt=XML, JSON, etc

public abstract NamedList<Object> processResponse(InputStream body, String encoding)
throws IOException;

/**
* A well-behaved ResponseParser will return the content-types it supports.
* Returns the MIME types this parser supports. Return an empty set to disable. Implementations
* must:
*
* <ul>
* <li>Returns the same instance (same reference on every call).
* <li>Use only lowercase MIME types without charset or other parameters (no semicolons)
* <li>
* </ul>
*
* @return the content-type values that this parser is capable of parsing. Never null. Empty means
* no enforcement.
* @return the MIME types that this parser is capable of parsing. Never null.
*/
public abstract Collection<String> getContentTypes();
public abstract Set<String> getContentTypes();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a backwards incompatible change... and it it's only caller should be our own code, and I think very few people would have a custom one of these.

}
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@ public String getWriterType() {
return "xml";
}

private static final Set<String> CONTENT_TYPES = Set.of("application/xml");

@Override
public Set<String> getContentTypes() {
return Set.of(XML_CONTENT_TYPE);
return CONTENT_TYPES;
}

public NamedList<Object> processResponse(Reader in) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.client.solrj.request.json.JacksonContentWriter;
import org.apache.solr.client.solrj.response.ResponseParser;
Expand All @@ -47,9 +46,11 @@ public String getWriterType() {
return "json";
}

private static final Set<String> CONTENT_TYPES = Set.of("application/json");

@Override
public Collection<String> getContentTypes() {
return List.of("application/json");
public Set<String> getContentTypes() {
return CONTENT_TYPES;
}

// TODO it'd be nice if the ResponseParser could receive the mime type so it can parse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.apache.solr.client.solrj.response.ResponseParser;
Expand Down Expand Up @@ -55,8 +54,10 @@ public NamedList<Object> processResponse(InputStream body, String encoding) thro
return list;
}

private static final Set<String> CONTENT_TYPES = Set.of("application/json");

@Override
public Collection<String> getContentTypes() {
return Set.of("application/json");
public Set<String> getContentTypes() {
return CONTENT_TYPES;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,12 @@ public String getWriterType() {
return "cbor";
}

private static final Set<String> CONTENT_TYPES =
Set.of("application/cbor", "application/octet-stream");

@Override
public Set<String> getContentTypes() {
return Set.of("application/cbor", "application/octet-stream");
return CONTENT_TYPES;
}

@Override
Expand Down
Loading
Loading