Skip to content

Commit

Permalink
SOLR-16347: Allow JAX-RS v2 API definitions (#975)
Browse files Browse the repository at this point in the history
Converts ListConfigSetsAPI and SchemaNameAPI as examples.
  • Loading branch information
gerlowskija committed Sep 13, 2022
1 parent e087cf2 commit 8efed05
Show file tree
Hide file tree
Showing 118 changed files with 5,813 additions and 1,831 deletions.

This file was deleted.

13 changes: 13 additions & 0 deletions solr/core/build.gradle
Expand Up @@ -81,6 +81,15 @@ dependencies {

implementation 'javax.servlet:javax.servlet-api'

implementation "org.glassfish.jersey.containers:jersey-container-jetty-http"
implementation 'org.glassfish.jersey.inject:jersey-hk2'
implementation 'org.glassfish.jersey.media:jersey-media-json-jackson'
implementation 'org.glassfish.jersey.core:jersey-common'
implementation 'org.glassfish.jersey.core:jersey-server'
implementation 'org.glassfish.hk2:hk2-api'
implementation 'org.glassfish.hk2.external:jakarta.inject'
implementation 'jakarta.ws.rs:jakarta.ws.rs-api'

// Non-API below; although there are exceptions

runtimeOnly "org.apache.lucene:lucene-analysis-kuromoji"
Expand Down Expand Up @@ -183,6 +192,10 @@ dependencies {
testImplementation 'junit:junit'
testImplementation 'org.hamcrest:hamcrest'

testImplementation 'org.glassfish.jersey.test-framework:jersey-test-framework-core'
testImplementation 'org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2'


testImplementation('org.mockito:mockito-core', {
exclude group: "net.bytebuddy", module: "byte-buddy-agent"
})
Expand Down
14 changes: 12 additions & 2 deletions solr/core/src/java/org/apache/solr/api/ApiSupport.java
Expand Up @@ -18,17 +18,27 @@
package org.apache.solr.api;

import java.util.Collection;
import java.util.Collections;

/** The interface that is implemented by a request handler to support the V2 end point */
public interface ApiSupport {

/**
* It is possible to support multiple v2 apis by a single requesthandler
* Returns any (non-JAX-RS annotated) APIs associated with this request handler.
*
* @return the list of v2 api implementations
* @see #getJerseyResources()
*/
Collection<Api> getApis();

/**
* Returns any JAX-RS annotated v2 APIs associated with this request handler.
*
* @see #getApis()
*/
default Collection<Class<? extends JerseyResource>> getJerseyResources() {
return Collections.emptySet();
}

/** Whether this should be made available at the regular legacy path */
default Boolean registerV1() {
return Boolean.TRUE;
Expand Down
98 changes: 98 additions & 0 deletions solr/core/src/java/org/apache/solr/api/JerseyResource.java
@@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.solr.api;

import static org.apache.solr.jersey.RequestContextKeys.SOLR_JERSEY_RESPONSE;

import java.util.function.Supplier;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.core.Context;
import org.apache.solr.jersey.CatchAllExceptionMapper;
import org.apache.solr.jersey.SolrJerseyResponse;
import org.apache.solr.servlet.HttpSolrCall;

/**
* A marker parent type for all Jersey "resource" classes.
*
* <p>"Resources" in Jersey are classes that define one or more API endpoints. As such they're
* analogous to the v1 {@link org.apache.solr.request.SolrRequestHandler} or the v2 {@link Api}.
*/
public class JerseyResource {

@Context public ContainerRequestContext containerRequestContext;

/**
* Create an instance of the {@link SolrJerseyResponse} subclass; registering it with the Jersey
* request-context upon creation.
*
* <p>This utility method primarily exists to allow Jersey resources to return error responses
* that match those returned by Solr's v1 APIs.
*
* <p>When a severe-enough exception halts a v1 request, Solr generates a summary of the error and
* attaches it to the {@link org.apache.solr.response.SolrQueryResponse} given to the request
* handler. This SolrQueryResponse may already hold some portion of the normal "success" response
* for that API.
*
* <p>The JAX-RS framework isn't well suited to mimicking responses of this sort, as the
* "response" from a Jersey resource is its return value (instead of a mutable method parameter
* that gets modified). This utility works around this limitation by attaching the eventual return
* value of a JerseyResource to the context associated with the Jersey request, as soon as its
* created. This allows partially-constructed responses to be accessed later in the case of an
* exception.
*
* <p>In order to instantiate arbitrary SolrJerseyResponse subclasses, this utility uses
* reflection to find and invoke the first (no-arg) constructor for the specified type.
* SolrJerseyResponse subclasses without a no-arg constructor can be instantiated and registered
* using {@link #instantiateJerseyResponse(Supplier)}
*
* @param clazz the SolrJerseyResponse class to instantiate and register
* @see CatchAllExceptionMapper
* @see HttpSolrCall#call()
*/
@SuppressWarnings("unchecked")
protected <T extends SolrJerseyResponse> T instantiateJerseyResponse(Class<T> clazz) {
return instantiateJerseyResponse(
() -> {
try {
return (T) clazz.getConstructors()[0].newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}

/**
* Create an instance of the {@link SolrJerseyResponse} subclass; registering it with the Jersey
* request-context upon creation.
*
* <p>This utility method primarily exists to allow Jersey resources to return responses,
* especially error responses, that match some of the particulars of Solr's traditional/v1 APIs.
* See the companion method {@link #instantiateJerseyResponse(Class)} for more details.
*
* @param instantiator a lambda to create the desired SolrJerseyResponse
* @see CatchAllExceptionMapper
* @see HttpSolrCall#call()
*/
protected <T extends SolrJerseyResponse> T instantiateJerseyResponse(Supplier<T> instantiator) {
final T instance = instantiator.get();
if (containerRequestContext != null) {
containerRequestContext.setProperty(SOLR_JERSEY_RESPONSE, instance);
}
return instance;
}
}

0 comments on commit 8efed05

Please sign in to comment.