gerlowskija commented on code in PR #1119: URL: https://github.com/apache/solr/pull/1119#discussion_r1004311073
########## solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java: ########## @@ -452,6 +454,11 @@ void call() throws Exception { } } + @Override Review Comment: [Q] There are lots of backup APIs - maybe I just got confused about which one you were working on - but I would've expected this new method to appear in ReplicationHandler since that's the backup functionality you're intending to address. What am I missing? ########## solr/core/src/java/org/apache/solr/handler/replication/BackupAPI.java: ########## @@ -0,0 +1,100 @@ +package org.apache.solr.handler.replication; Review Comment: [0] Don't forget your copyright header setup; it's nearly impossible IMO to remember to put the header in yourself on every file you create! ########## solr/core/src/test/org/apache/solr/handler/replication/BackupAPITest.java: ########## @@ -0,0 +1,102 @@ +package org.apache.solr.handler.replication; + +import static org.apache.solr.SolrTestCaseJ4.assumeWorkingMockito; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.inject.Singleton; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.core.SolrCore; +import org.apache.solr.handler.ReplicationHandler; +import org.apache.solr.jersey.InjectionFactories; +import org.apache.solr.jersey.SolrJacksonMapper; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.process.internal.RequestScoped; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.BeforeClass; +import org.junit.Test; + +/** Unit test of v2 endpoints for Replication Handler backup command */ Review Comment: [+1] This is a cool test; I've only experimented with using `JerseyTest` up to this point, but I like what I see so far! [0] You could probably do a javadoc "link", rather than trying to describe the API being tested in words. e.g. ``` /** * Unit tests for {@link BackupAPI} */ ``` ########## solr/core/src/java/org/apache/solr/handler/replication/BackupAPI.java: ########## @@ -0,0 +1,100 @@ +package org.apache.solr.handler.replication; + +import static org.apache.solr.handler.ClusterAPI.wrapParams; +import static org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import org.apache.solr.api.JerseyResource; +import org.apache.solr.common.annotation.JsonProperty; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.handler.ReplicationHandler; +import org.apache.solr.jersey.JacksonReflectMapWriter; +import org.apache.solr.jersey.PermissionName; +import org.apache.solr.jersey.SolrJerseyResponse; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; + +/** V2 endpoint for Backup API used for User-Managed clusters and Single-Node Installation. */ +@Path("/cores/{cores}/replication/backups") +public class BackupAPI extends JerseyResource { Review Comment: [-1] Because Solr has a bunch of different "backup"-related features and APIs, I think we should come up with a more descriptive name here. Maybe "ReplicationBackupAPI", since that's where the functionality initially existed? Maybe "SnapshotBackupAPI", since this triggers the "snapshot" functionality and not a "true" backup? Idk. Any ideas? ########## solr/core/src/java/org/apache/solr/handler/replication/BackupAPI.java: ########## @@ -0,0 +1,100 @@ +package org.apache.solr.handler.replication; + +import static org.apache.solr.handler.ClusterAPI.wrapParams; +import static org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import org.apache.solr.api.JerseyResource; +import org.apache.solr.common.annotation.JsonProperty; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.handler.ReplicationHandler; +import org.apache.solr.jersey.JacksonReflectMapWriter; +import org.apache.solr.jersey.PermissionName; +import org.apache.solr.jersey.SolrJerseyResponse; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; + +/** V2 endpoint for Backup API used for User-Managed clusters and Single-Node Installation. */ +@Path("/cores/{cores}/replication/backups") Review Comment: [0] Personally, I'd make the path-variable singular instead of plural (i.e. "core"), since it's referring to a single specific core. ########## solr/core/src/java/org/apache/solr/handler/replication/BackupAPI.java: ########## @@ -0,0 +1,100 @@ +package org.apache.solr.handler.replication; + +import static org.apache.solr.handler.ClusterAPI.wrapParams; +import static org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import org.apache.solr.api.JerseyResource; +import org.apache.solr.common.annotation.JsonProperty; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.handler.ReplicationHandler; +import org.apache.solr.jersey.JacksonReflectMapWriter; +import org.apache.solr.jersey.PermissionName; +import org.apache.solr.jersey.SolrJerseyResponse; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; + +/** V2 endpoint for Backup API used for User-Managed clusters and Single-Node Installation. */ +@Path("/cores/{cores}/replication/backups") +public class BackupAPI extends JerseyResource { + private final SolrQueryRequest solrQueryRequest; + private final SolrQueryResponse solrQueryResponse; + private final ReplicationHandler replicationHandler; + + @PathParam("cores") + private String coreName; + + @Inject + public BackupAPI( + CoreContainer cc, SolrQueryRequest solrQueryRequest, SolrQueryResponse solrQueryResponse) { + this.replicationHandler = + (ReplicationHandler) cc.getCore(coreName).getRequestHandler(ReplicationHandler.PATH); + this.solrQueryRequest = solrQueryRequest; + this.solrQueryResponse = solrQueryResponse; + } + /** + * This API (POST /api/cores/coreName/replication/backups {...}) is analogous to the v1 + * /solr/coreName/replication?command=backup + */ + @POST + @Produces({MediaType.APPLICATION_JSON}) + @Operation( + summary = "Backup command using ReplicationHandler", + tags = {"cores"}) + @PermissionName(CORE_EDIT_PERM) + public SolrJerseyResponse createBackup( + @RequestBody BackupReplicationPayload backupReplicationPayload) throws Exception { + final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class); + final Map<String, Object> v1Params = backupReplicationPayload.toMap(new HashMap<>()); + v1Params.put(ReplicationHandler.COMMAND, ReplicationHandler.CMD_BACKUP); + replicationHandler.handleRequestBody(wrapParams(solrQueryRequest, v1Params), solrQueryResponse); + return response; + } + + /* POJO for v2 endpoints request body.*/ + public static class BackupReplicationPayload implements JacksonReflectMapWriter { Review Comment: [0] The traditional v2 framework set up the convention of naming these classes "Payloads", so this definitely isn't "wrong". But my personal preference would be to go with "RequestBody" for our JAX-RS APIs (e.g. BackupReplicationRequestBody). If you don't have a strong preference for 'Payload', consider renaming to use 'RequestBody' instead. ########## solr/core/src/java/org/apache/solr/handler/replication/BackupAPI.java: ########## @@ -0,0 +1,100 @@ +package org.apache.solr.handler.replication; + +import static org.apache.solr.handler.ClusterAPI.wrapParams; +import static org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import org.apache.solr.api.JerseyResource; +import org.apache.solr.common.annotation.JsonProperty; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.handler.ReplicationHandler; +import org.apache.solr.jersey.JacksonReflectMapWriter; +import org.apache.solr.jersey.PermissionName; +import org.apache.solr.jersey.SolrJerseyResponse; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; + +/** V2 endpoint for Backup API used for User-Managed clusters and Single-Node Installation. */ +@Path("/cores/{cores}/replication/backups") +public class BackupAPI extends JerseyResource { + private final SolrQueryRequest solrQueryRequest; + private final SolrQueryResponse solrQueryResponse; + private final ReplicationHandler replicationHandler; + + @PathParam("cores") + private String coreName; + + @Inject + public BackupAPI( + CoreContainer cc, SolrQueryRequest solrQueryRequest, SolrQueryResponse solrQueryResponse) { + this.replicationHandler = + (ReplicationHandler) cc.getCore(coreName).getRequestHandler(ReplicationHandler.PATH); Review Comment: [0] I wasn't able to reproduce the injection issue you mentioned - in fact I was having trouble triggering the API at all, but this code here strikes me as a likely culprit for the issue you described. We're using 'coreName' here to look up the SolrCore object, but what value does 'coreName' have at this point? Idk whether it would be set or not when the constructor gets called. I'd guess not: I'm not sure the "instance variable" even exists for the `@PathParam` annotation to give it a value until after the constructor is called. Reflection stuff is weird, so I wouldn't bet on it for sure, but that'd be my guess. Anyway, if 'coreName' is null here, I bet we'd get a null SolrCore and trigger a NPE at this line. ---- Assuming this is the issue (which is a big 'IF', admittedly) - I'd suggest we take the bit of functionality we need from ReplicationHandler and move it to a public method here, instead of trying to reuse ReplicationHandler directly. There are "strategic" reasons that Solr wants to move in this sort of direction, see my comment in JIRA [here](https://issues.apache.org/jira/browse/SOLR-16461?focusedCommentId=17619003&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-17619003) for a bit more context. Happy to help with that if need be, lmk. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: issues-unsubscr...@solr.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: issues-unsubscr...@solr.apache.org For additional commands, e-mail: issues-h...@solr.apache.org