Skip to content

Commit

Permalink
Add API v2
Browse files Browse the repository at this point in the history
Add v2 REST endpoints.

Add java client implementation for v2 REST API.

Since namespaces are treated as ordinary content objects in API v2
the old java client API for dealing with namespaces is implemented
on the client side on top of v2 "get entries" and "commit" APIs.

Run in-memory REST server tests for both v1 and v2 APIs.

REST test using persistent backend only use v2 API.

Resteasy test remain on v1 API since they construct REST requests
according to Nessie API v1 specs.

OpenAPI YAML is built and published only for v2. OpenAPI for v1
should be obtained from older Nessie publications.

This is the main contribution towards projectnessie#5112
  • Loading branch information
dimas-b committed Nov 22, 2022
1 parent 572d21e commit 6028226
Show file tree
Hide file tree
Showing 73 changed files with 4,320 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class MultiVersionApiTest implements MultiEnvTestExtension, ExecutionCond
public static final String API_VERSION_SEGMENT_TYPE = "nessie-api";

// API version to be used for tests not annotated with `@ForNessieApiVersions`
private static final NessieApiVersion DEFAULT_API_VERSION = NessieApiVersion.V1;
private static final NessieApiVersion DEFAULT_API_VERSION = NessieApiVersion.V2;

@Override
public String segmentType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
import java.net.URI;
import org.projectnessie.client.NessieClientBuilder;
import org.projectnessie.client.api.NessieApiV1;
import org.projectnessie.client.api.NessieApiV2;

public enum NessieApiVersion {
V1("v1", NessieApiV1.class),
V2("v2", NessieApiV2.class),
;

private final String uriPathElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@
@ExtendWith(MultiVersionApiTest.class)
@Inherited
public @interface NessieApiVersions {
NessieApiVersion[] versions() default {NessieApiVersion.V1};
NessieApiVersion[] versions() default {NessieApiVersion.V1, NessieApiVersion.V2};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2022 Dremio
*
* Licensed 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.projectnessie.client.api;

/**
* Interface for the Nessie V2 API implementation.
*
* <p>At the java client level this API uses the same builder classes and model types as API v1,
* however the behaviour of some API methods is different.
*
* <p>Most changes between v1 and v2 exist at the REST level (HTTP).
*/
public interface NessieApiV2 extends NessieApiV1 {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2022 Dremio
*
* Licensed 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.projectnessie.client.http;

import java.util.function.Supplier;

/**
* This is a helper class for use with an {@link HttpRequest} that will unwrap the specified
* API-level exceptions from {@link HttpClientException} thrown during the execution of the {@link
* HttpRequest}.
*
* <p>Currently this class supports up to two distinct API-level exception types, but it can easily
* be extended to support more if required.
*
* <p>The exception types to be unwrapped are specifies as arguments to {@link
* HttpRequest#unwrap(Class)} and {@link HttpRequest#unwrap(Class, Class)} calls.
*
* @param <E1> the first API-level exception that should be unwrapped
* @param <E2> the second API-level exception that should be unwrapped
*/
public class ApiHttpRequest<E1 extends Throwable, E2 extends Throwable> {
private final HttpRequest request;
private final Class<E1> ex1;
private final Class<E2> ex2;

ApiHttpRequest(HttpRequest request, Class<E1> ex1, Class<E2> ex2) {
this.request = request;
this.ex1 = ex1;
this.ex2 = ex2;
}

public HttpResponse get() throws E1, E2 {
return unwrap(request::get);
}

public HttpResponse delete() throws E1, E2 {
return unwrap(request::delete);
}

public HttpResponse post(Object obj) throws E1, E2 {
return unwrap(() -> request.post(obj));
}

public HttpResponse put(Object obj) throws E1, E2 {
return unwrap(() -> request.put(obj));
}

private HttpResponse unwrap(Supplier<HttpResponse> action) throws E1, E2 {
try {
return action.get();
} catch (HttpClientException e) {
Throwable cause = e.getCause();

if (ex1.isInstance(cause)) {
throw ex1.cast(cause);
}

if (ex2.isInstance(cause)) {
throw ex2.cast(cause);
}

throw e;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.projectnessie.client.auth.NessieAuthentication;
import org.projectnessie.client.auth.NessieAuthenticationProvider;
import org.projectnessie.client.http.v1api.HttpApiV1;
import org.projectnessie.client.http.v2api.HttpApiV2;

/**
* A builder class that creates a {@link NessieHttpClient} via {@link HttpClientBuilder#builder()}.
Expand Down Expand Up @@ -282,12 +283,17 @@ public HttpClientBuilder withForceUrlConnectionClient(boolean forceUrlConnection
@Override
public <API extends NessieApi> API build(Class<API> apiVersion) {
Objects.requireNonNull(apiVersion, "API version class must be non-null");
NessieHttpClient client = new NessieHttpClient(authentication, tracing, builder);

if (apiVersion.isAssignableFrom(HttpApiV1.class)) {
NessieHttpClient client = new NessieHttpClient(authentication, tracing, builder);
return (API) new HttpApiV1(client);
}

if (apiVersion.isAssignableFrom(HttpApiV2.class)) {
HttpClient httpClient = NessieHttpClient.buildClient(authentication, tracing, builder);
return (API) new HttpApiV2(httpClient);
}

throw new IllegalArgumentException(
String.format("API version %s is not supported.", apiVersion.getName()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,13 @@ public HttpRequest resolveTemplate(String name, String value) {
uriBuilder.resolveTemplate(name, value);
return this;
}

public <E extends Exception> ApiHttpRequest<E, RuntimeException> unwrap(Class<E> ex) {
return new ApiHttpRequest<>(this, ex, RuntimeException.class);
}

public <E1 extends Exception, E2 extends Exception> ApiHttpRequest<E1, E2> unwrap(
Class<E1> ex1, Class<E2> ex2) {
return new ApiHttpRequest<>(this, ex1, ex2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public class NessieHttpClient extends NessieApiClient {
this(buildClient(authentication, enableTracing, clientBuilder));
}

private static HttpClient buildClient(
static HttpClient buildClient(
HttpAuthentication authentication, boolean enableTracing, HttpClient.Builder clientBuilder) {
clientBuilder.setObjectMapper(MAPPER);
if (enableTracing) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2022 Dremio
*
* Licensed 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.projectnessie.client.http.v2api;

import org.projectnessie.client.api.OnReferenceBuilder;
import org.projectnessie.client.http.HttpClient;

abstract class BaseHttpOnReferenceRequest<R extends OnReferenceBuilder<R>> extends BaseHttpRequest
implements OnReferenceBuilder<R> {
protected String refName;
protected String hashOnRef;

protected BaseHttpOnReferenceRequest(HttpClient client) {
super(client);
}

@Override
public R refName(String refName) {
this.refName = refName;
return (R) this;
}

@Override
public R hashOnRef(String hashOnRef) {
this.hashOnRef = hashOnRef;
return (R) this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2022 Dremio
*
* Licensed 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.projectnessie.client.http.v2api;

import org.projectnessie.client.http.HttpClient;

public abstract class BaseHttpRequest {

protected final HttpClient client;

protected BaseHttpRequest(HttpClient client) {
this.client = client;
}
}
Loading

0 comments on commit 6028226

Please sign in to comment.