diff --git a/clients/client-testextension/src/main/java/org/projectnessie/client/ext/MultiVersionApiTest.java b/clients/client-testextension/src/main/java/org/projectnessie/client/ext/MultiVersionApiTest.java
index 1fa828dcf4e..5bbd8b010a0 100644
--- a/clients/client-testextension/src/main/java/org/projectnessie/client/ext/MultiVersionApiTest.java
+++ b/clients/client-testextension/src/main/java/org/projectnessie/client/ext/MultiVersionApiTest.java
@@ -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() {
diff --git a/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersion.java b/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersion.java
index b20c18960f5..23099432e06 100644
--- a/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersion.java
+++ b/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersion.java
@@ -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;
diff --git a/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersions.java b/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersions.java
index 75542636592..793647adf7c 100644
--- a/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersions.java
+++ b/clients/client-testextension/src/main/java/org/projectnessie/client/ext/NessieApiVersions.java
@@ -36,5 +36,5 @@
@ExtendWith(MultiVersionApiTest.class)
@Inherited
public @interface NessieApiVersions {
- NessieApiVersion[] versions() default {NessieApiVersion.V1};
+ NessieApiVersion[] versions() default {NessieApiVersion.V1, NessieApiVersion.V2};
}
diff --git a/clients/client/src/main/java/org/projectnessie/client/api/NessieApiV2.java b/clients/client/src/main/java/org/projectnessie/client/api/NessieApiV2.java
new file mode 100644
index 00000000000..596a9dfda98
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/api/NessieApiV2.java
@@ -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.
+ *
+ *
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.
+ *
+ *
Most changes between v1 and v2 exist at the REST level (HTTP).
+ */
+public interface NessieApiV2 extends NessieApiV1 {}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/ApiHttpRequest.java b/clients/client/src/main/java/org/projectnessie/client/http/ApiHttpRequest.java
new file mode 100644
index 00000000000..db5f1dbfff6
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/ApiHttpRequest.java
@@ -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}.
+ *
+ *
Currently this class supports up to two distinct API-level exception types, but it can easily
+ * be extended to support more if required.
+ *
+ *
The exception types to be unwrapped are specifies as arguments to {@link
+ * HttpRequest#unwrap(Class)} and {@link HttpRequest#unwrap(Class, Class)} calls.
+ *
+ * @param the first API-level exception that should be unwrapped
+ * @param the second API-level exception that should be unwrapped
+ */
+public class ApiHttpRequest {
+ private final HttpRequest request;
+ private final Class ex1;
+ private final Class ex2;
+
+ ApiHttpRequest(HttpRequest request, Class ex1, Class 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 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;
+ }
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/HttpClientBuilder.java b/clients/client/src/main/java/org/projectnessie/client/http/HttpClientBuilder.java
index 5f4f0f6208d..35341152bf6 100644
--- a/clients/client/src/main/java/org/projectnessie/client/http/HttpClientBuilder.java
+++ b/clients/client/src/main/java/org/projectnessie/client/http/HttpClientBuilder.java
@@ -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()}.
@@ -282,12 +283,17 @@ public HttpClientBuilder withForceUrlConnectionClient(boolean forceUrlConnection
@Override
public API build(Class 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()));
}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/HttpRequest.java b/clients/client/src/main/java/org/projectnessie/client/http/HttpRequest.java
index 2e75ab91955..ec2ccb43696 100644
--- a/clients/client/src/main/java/org/projectnessie/client/http/HttpRequest.java
+++ b/clients/client/src/main/java/org/projectnessie/client/http/HttpRequest.java
@@ -89,4 +89,13 @@ public HttpRequest resolveTemplate(String name, String value) {
uriBuilder.resolveTemplate(name, value);
return this;
}
+
+ public ApiHttpRequest unwrap(Class ex) {
+ return new ApiHttpRequest<>(this, ex, RuntimeException.class);
+ }
+
+ public ApiHttpRequest unwrap(
+ Class ex1, Class ex2) {
+ return new ApiHttpRequest<>(this, ex1, ex2);
+ }
}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/NessieHttpClient.java b/clients/client/src/main/java/org/projectnessie/client/http/NessieHttpClient.java
index 518b195301c..fee37455bfd 100644
--- a/clients/client/src/main/java/org/projectnessie/client/http/NessieHttpClient.java
+++ b/clients/client/src/main/java/org/projectnessie/client/http/NessieHttpClient.java
@@ -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) {
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/BaseHttpOnReferenceRequest.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/BaseHttpOnReferenceRequest.java
new file mode 100644
index 00000000000..e50f425872c
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/BaseHttpOnReferenceRequest.java
@@ -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> extends BaseHttpRequest
+ implements OnReferenceBuilder {
+ 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;
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/BaseHttpRequest.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/BaseHttpRequest.java
new file mode 100644
index 00000000000..c9f619df2d4
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/BaseHttpRequest.java
@@ -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;
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpApiV2.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpApiV2.java
new file mode 100644
index 00000000000..d034da1f037
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpApiV2.java
@@ -0,0 +1,178 @@
+/*
+ * 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.AssignBranchBuilder;
+import org.projectnessie.client.api.AssignTagBuilder;
+import org.projectnessie.client.api.CommitMultipleOperationsBuilder;
+import org.projectnessie.client.api.CreateNamespaceBuilder;
+import org.projectnessie.client.api.CreateReferenceBuilder;
+import org.projectnessie.client.api.DeleteBranchBuilder;
+import org.projectnessie.client.api.DeleteNamespaceBuilder;
+import org.projectnessie.client.api.DeleteTagBuilder;
+import org.projectnessie.client.api.GetAllReferencesBuilder;
+import org.projectnessie.client.api.GetCommitLogBuilder;
+import org.projectnessie.client.api.GetContentBuilder;
+import org.projectnessie.client.api.GetDiffBuilder;
+import org.projectnessie.client.api.GetEntriesBuilder;
+import org.projectnessie.client.api.GetMultipleNamespacesBuilder;
+import org.projectnessie.client.api.GetNamespaceBuilder;
+import org.projectnessie.client.api.GetRefLogBuilder;
+import org.projectnessie.client.api.GetReferenceBuilder;
+import org.projectnessie.client.api.MergeReferenceBuilder;
+import org.projectnessie.client.api.NessieApiV2;
+import org.projectnessie.client.api.TransplantCommitsBuilder;
+import org.projectnessie.client.api.UpdateNamespaceBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.client.util.v2api.ClientSideCreateNamespace;
+import org.projectnessie.client.util.v2api.ClientSideDeleteNamespace;
+import org.projectnessie.client.util.v2api.ClientSideGetMultipleNamespaces;
+import org.projectnessie.client.util.v2api.ClientSideGetNamespace;
+import org.projectnessie.client.util.v2api.ClientSideUpdateNamespace;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Branch;
+import org.projectnessie.model.NessieConfiguration;
+import org.projectnessie.model.SingleReferenceResponse;
+
+public class HttpApiV2 implements NessieApiV2 {
+ private final HttpClient client;
+
+ public HttpApiV2(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public void close() {
+ // nop
+ }
+
+ @Override
+ public NessieConfiguration getConfig() {
+ return client.newRequest().path("config").get().readEntity(NessieConfiguration.class);
+ }
+
+ @Override
+ public Branch getDefaultBranch() throws NessieNotFoundException {
+ return (Branch)
+ client
+ .newRequest()
+ .path("trees/main") // TODO: use trees/-
+ .unwrap(NessieNotFoundException.class)
+ .get()
+ .readEntity(SingleReferenceResponse.class)
+ .getReference();
+ }
+
+ @Override
+ public GetContentBuilder getContent() {
+ return new HttpGetContent(client);
+ }
+
+ @Override
+ public GetAllReferencesBuilder getAllReferences() {
+ return new HttpGetAllReferences(client);
+ }
+
+ @Override
+ public CreateReferenceBuilder createReference() {
+ return new HttpCreateReference(client);
+ }
+
+ @Override
+ public GetReferenceBuilder getReference() {
+ return new HttpGetReference(client);
+ }
+
+ @Override
+ public GetEntriesBuilder getEntries() {
+ return new HttpGetEntries(client);
+ }
+
+ @Override
+ public GetCommitLogBuilder getCommitLog() {
+ return new HttpGetCommitLog(client);
+ }
+
+ @Override
+ public AssignTagBuilder assignTag() {
+ return new HttpAssignTag(client);
+ }
+
+ @Override
+ public DeleteTagBuilder deleteTag() {
+ return new HttpDeleteTag(client);
+ }
+
+ @Override
+ public AssignBranchBuilder assignBranch() {
+ return new HttpAssignBranch(client);
+ }
+
+ @Override
+ public DeleteBranchBuilder deleteBranch() {
+ return new HttpDeleteBranch(client);
+ }
+
+ @Override
+ public TransplantCommitsBuilder transplantCommitsIntoBranch() {
+ return new HttpTransplantCommits(client);
+ }
+
+ @Override
+ public MergeReferenceBuilder mergeRefIntoBranch() {
+ return new HttpMergeReference(client);
+ }
+
+ @Override
+ public CommitMultipleOperationsBuilder commitMultipleOperations() {
+ return new HttpCommitMultipleOperations(client);
+ }
+
+ @Override
+ public GetDiffBuilder getDiff() {
+ return new HttpGetDiff(client);
+ }
+
+ @Override
+ public GetRefLogBuilder getRefLog() {
+ throw new UnsupportedOperationException("Reflog is not supported in API v2");
+ }
+
+ @Override
+ public GetNamespaceBuilder getNamespace() {
+ return new ClientSideGetNamespace(this);
+ }
+
+ @Override
+ public GetMultipleNamespacesBuilder getMultipleNamespaces() {
+ return new ClientSideGetMultipleNamespaces(this);
+ }
+
+ @Override
+ public CreateNamespaceBuilder createNamespace() {
+ return new ClientSideCreateNamespace(this);
+ }
+
+ @Override
+ public DeleteNamespaceBuilder deleteNamespace() {
+ return new ClientSideDeleteNamespace(this);
+ }
+
+ @Override
+ public UpdateNamespaceBuilder updateProperties() {
+ return new ClientSideUpdateNamespace(this);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpAssignBranch.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpAssignBranch.java
new file mode 100644
index 00000000000..2bba5b16749
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpAssignBranch.java
@@ -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.builder.BaseAssignBranchBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Reference;
+
+final class HttpAssignBranch extends BaseAssignBranchBuilder {
+ private final HttpClient client;
+
+ HttpAssignBranch(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public void assign() throws NessieNotFoundException, NessieConflictException {
+ client
+ .newRequest()
+ .path("trees/{ref}")
+ .resolveTemplate("ref", Reference.toPathString(branchName, hash))
+ .queryParam("type", Reference.ReferenceType.BRANCH.name())
+ .unwrap(NessieNotFoundException.class, NessieConflictException.class)
+ .put(assignTo);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpAssignTag.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpAssignTag.java
new file mode 100644
index 00000000000..4c7651e069e
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpAssignTag.java
@@ -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.builder.BaseAssignTagBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Reference;
+
+final class HttpAssignTag extends BaseAssignTagBuilder {
+ private final HttpClient client;
+
+ HttpAssignTag(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public void assign() throws NessieNotFoundException, NessieConflictException {
+ client
+ .newRequest()
+ .path("trees/{ref}")
+ .resolveTemplate("ref", Reference.toPathString(tagName, hash))
+ .queryParam("type", Reference.ReferenceType.TAG.name())
+ .unwrap(NessieNotFoundException.class, NessieConflictException.class)
+ .put(assignTo);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpCommitMultipleOperations.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpCommitMultipleOperations.java
new file mode 100644
index 00000000000..76ce27dddc4
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpCommitMultipleOperations.java
@@ -0,0 +1,44 @@
+/*
+ * 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.builder.BaseCommitMultipleOperationsBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Branch;
+import org.projectnessie.model.CommitResponse;
+import org.projectnessie.model.Reference;
+
+final class HttpCommitMultipleOperations extends BaseCommitMultipleOperationsBuilder {
+ private final HttpClient client;
+
+ HttpCommitMultipleOperations(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public Branch commit() throws NessieNotFoundException, NessieConflictException {
+ return client
+ .newRequest()
+ .path("trees/{ref}/history/commit")
+ .resolveTemplate("ref", Reference.toPathString(branchName, hash))
+ .unwrap(NessieNotFoundException.class, NessieConflictException.class)
+ .post(operations.build())
+ .readEntity(CommitResponse.class)
+ .getTargetBranch();
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpCreateReference.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpCreateReference.java
new file mode 100644
index 00000000000..616d33ee326
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpCreateReference.java
@@ -0,0 +1,58 @@
+/*
+ * 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.builder.BaseCreateReferenceBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Branch;
+import org.projectnessie.model.Detached;
+import org.projectnessie.model.Reference;
+import org.projectnessie.model.SingleReferenceResponse;
+
+public class HttpCreateReference extends BaseCreateReferenceBuilder {
+
+ private final HttpClient client;
+
+ protected HttpCreateReference(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public Reference create() throws NessieNotFoundException, NessieConflictException {
+ Reference source;
+ if (sourceRefName == null) {
+ if (reference.getHash() == null) {
+ source = null;
+ } else {
+ source = Detached.of(reference.getHash());
+ }
+ } else {
+ source = Branch.of(sourceRefName, reference.getHash());
+ }
+
+ return client
+ .newRequest()
+ .path("trees")
+ .queryParam("name", reference.getName())
+ .queryParam("type", reference.getType().name())
+ .unwrap(NessieNotFoundException.class, NessieConflictException.class)
+ .post(source) // TODO: support all types
+ .readEntity(SingleReferenceResponse.class)
+ .getReference();
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpDeleteBranch.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpDeleteBranch.java
new file mode 100644
index 00000000000..44f3e4c13e5
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpDeleteBranch.java
@@ -0,0 +1,43 @@
+/*
+ * 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.DeleteBranchBuilder;
+import org.projectnessie.client.builder.BaseOnBranchBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Reference;
+
+final class HttpDeleteBranch extends BaseOnBranchBuilder
+ implements DeleteBranchBuilder {
+ private final HttpClient client;
+
+ HttpDeleteBranch(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public void delete() throws NessieConflictException, NessieNotFoundException {
+ client
+ .newRequest()
+ .path("trees/{ref}")
+ .resolveTemplate("ref", Reference.toPathString(branchName, hash))
+ .queryParam("type", Reference.ReferenceType.BRANCH.name())
+ .unwrap(NessieConflictException.class, NessieNotFoundException.class)
+ .delete();
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpDeleteTag.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpDeleteTag.java
new file mode 100644
index 00000000000..abe20ef3bcc
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpDeleteTag.java
@@ -0,0 +1,42 @@
+/*
+ * 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.DeleteTagBuilder;
+import org.projectnessie.client.builder.BaseOnTagBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Reference;
+
+final class HttpDeleteTag extends BaseOnTagBuilder implements DeleteTagBuilder {
+ private final HttpClient client;
+
+ HttpDeleteTag(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public void delete() throws NessieConflictException, NessieNotFoundException {
+ client
+ .newRequest()
+ .path("trees/{ref}")
+ .resolveTemplate("ref", Reference.toPathString(tagName, hash))
+ .queryParam("type", Reference.ReferenceType.TAG.name())
+ .unwrap(NessieConflictException.class, NessieNotFoundException.class)
+ .delete();
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetAllReferences.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetAllReferences.java
new file mode 100644
index 00000000000..a4663d85d78
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetAllReferences.java
@@ -0,0 +1,54 @@
+/*
+ * 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.api.params.FetchOption;
+import org.projectnessie.api.v2.params.ReferencesParams;
+import org.projectnessie.client.builder.BaseGetAllReferencesBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.model.ReferencesResponse;
+
+final class HttpGetAllReferences extends BaseGetAllReferencesBuilder {
+
+ private final HttpClient client;
+
+ HttpGetAllReferences(HttpClient client) {
+ super(ReferencesParams::forNextPage);
+ this.client = client;
+ }
+
+ @Override
+ protected ReferencesParams params() {
+ return ReferencesParams.builder()
+ .fetchOption(fetchOption)
+ .filter(filter)
+ .maxRecords(maxRecords)
+ .build();
+ }
+
+ @Override
+ protected ReferencesResponse get(ReferencesParams p) {
+ return client
+ .newRequest()
+ .path("trees")
+ .queryParam("fetch", FetchOption.getFetchOptionName(p.fetchOption()))
+ .queryParam("max-records", p.maxRecords())
+ .queryParam("page-token", p.pageToken())
+ .queryParam("filter", p.filter())
+ .get()
+ .readEntity(ReferencesResponse.class);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetCommitLog.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetCommitLog.java
new file mode 100644
index 00000000000..f6e563b9b36
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetCommitLog.java
@@ -0,0 +1,71 @@
+/*
+ * 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 java.util.stream.Stream;
+import org.projectnessie.api.params.FetchOption;
+import org.projectnessie.api.v2.params.CommitLogParams;
+import org.projectnessie.client.StreamingUtil;
+import org.projectnessie.client.builder.BaseGetCommitLogBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.LogResponse;
+import org.projectnessie.model.Reference;
+
+final class HttpGetCommitLog extends BaseGetCommitLogBuilder {
+
+ private final HttpClient client;
+
+ HttpGetCommitLog(HttpClient client) {
+ super(CommitLogParams::forNextPage);
+ this.client = client;
+ }
+
+ @Override
+ protected CommitLogParams params() {
+ return CommitLogParams.builder()
+ .fetchOption(fetchOption)
+ .startHash(untilHash)
+ .maxRecords(maxRecords)
+ .filter(filter)
+ .build();
+ }
+
+ @Override
+ protected LogResponse get(CommitLogParams p) throws NessieNotFoundException {
+ return client
+ .newRequest()
+ .path("trees/{ref}/history")
+ .resolveTemplate(
+ "ref",
+ Reference.toPathString(refName, hashOnRef)) // TODO: move refName, hashOnRef to params
+ .queryParam("max-records", p.maxRecords())
+ .queryParam("page-token", p.pageToken())
+ .queryParam("filter", p.filter())
+ .queryParam("limit-hash", p.startHash())
+ .queryParam("fetch", FetchOption.getFetchOptionName(p.fetchOption()))
+ .unwrap(NessieNotFoundException.class)
+ .get()
+ .readEntity(LogResponse.class);
+ }
+
+ @Override
+ public Stream stream() throws NessieNotFoundException {
+ CommitLogParams p = params();
+ return StreamingUtil.generateStream(
+ LogResponse::getLogEntries, pageToken -> get(p.forNextPage(pageToken)));
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetContent.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetContent.java
new file mode 100644
index 00000000000..8c8ec2ac395
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetContent.java
@@ -0,0 +1,49 @@
+/*
+ * 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 java.util.Map;
+import java.util.stream.Collectors;
+import org.projectnessie.client.builder.BaseGetContentBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Content;
+import org.projectnessie.model.ContentKey;
+import org.projectnessie.model.GetMultipleContentsResponse;
+import org.projectnessie.model.GetMultipleContentsResponse.ContentWithKey;
+import org.projectnessie.model.Reference;
+
+final class HttpGetContent extends BaseGetContentBuilder {
+ private final HttpClient client;
+
+ HttpGetContent(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public Map get() throws NessieNotFoundException {
+ GetMultipleContentsResponse response =
+ client
+ .newRequest()
+ .path("trees/{ref}/contents")
+ .resolveTemplate("ref", Reference.toPathString(refName, hashOnRef))
+ .unwrap(NessieNotFoundException.class)
+ .post(request.build())
+ .readEntity(GetMultipleContentsResponse.class);
+ return response.getContents().stream()
+ .collect(Collectors.toMap(ContentWithKey::getKey, ContentWithKey::getContent));
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetDiff.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetDiff.java
new file mode 100644
index 00000000000..38d1f8e70d2
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetDiff.java
@@ -0,0 +1,42 @@
+/*
+ * 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.builder.BaseGetDiffBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.DiffResponse;
+import org.projectnessie.model.Reference;
+
+final class HttpGetDiff extends BaseGetDiffBuilder {
+ private final HttpClient client;
+
+ HttpGetDiff(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public DiffResponse get() throws NessieNotFoundException {
+ return client
+ .newRequest()
+ .path("trees/{from}/diff/{to}")
+ .resolveTemplate("from", Reference.toPathString(fromRefName, fromHashOnRef))
+ .resolveTemplate("to", Reference.toPathString(toRefName, toHashOnRef))
+ .unwrap(NessieNotFoundException.class)
+ .get()
+ .readEntity(DiffResponse.class);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetEntries.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetEntries.java
new file mode 100644
index 00000000000..3aa9c61afb0
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetEntries.java
@@ -0,0 +1,55 @@
+/*
+ * 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.api.v2.params.EntriesParams;
+import org.projectnessie.client.builder.BaseGetEntriesBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.EntriesResponse;
+import org.projectnessie.model.Reference;
+
+final class HttpGetEntries extends BaseGetEntriesBuilder {
+
+ private final HttpClient client;
+
+ HttpGetEntries(HttpClient client) {
+ super(EntriesParams::forNextPage);
+ this.client = client;
+ }
+
+ @Override
+ protected EntriesParams params() {
+ return EntriesParams.builder() // TODO: namespace, derive prefix
+ .filter(filter)
+ .maxRecords(maxRecords)
+ .build();
+ }
+
+ @Override
+ protected EntriesResponse get(EntriesParams p) throws NessieNotFoundException {
+ return client
+ .newRequest()
+ .path("trees/{ref}/entries")
+ .resolveTemplate("ref", Reference.toPathString(refName, hashOnRef))
+ .queryParam("filter", p.filter())
+ .queryParam("page-token", p.pageToken())
+ .queryParam("max-records", p.maxRecords())
+ .unwrap(NessieNotFoundException.class)
+ .get()
+ .readEntity(EntriesResponse.class);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetReference.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetReference.java
new file mode 100644
index 00000000000..e6b76b505ae
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpGetReference.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 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.api.params.FetchOption;
+import org.projectnessie.client.builder.BaseGetReferenceBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.Reference;
+import org.projectnessie.model.SingleReferenceResponse;
+
+final class HttpGetReference extends BaseGetReferenceBuilder {
+
+ private final HttpClient client;
+
+ HttpGetReference(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public Reference get() throws NessieNotFoundException {
+ return client
+ .newRequest()
+ .path("trees/{ref}")
+ .queryParam("fetch", FetchOption.getFetchOptionName(fetchOption))
+ .resolveTemplate("ref", refName)
+ .unwrap(NessieNotFoundException.class)
+ .get()
+ .readEntity(SingleReferenceResponse.class)
+ .getReference();
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpMergeReference.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpMergeReference.java
new file mode 100644
index 00000000000..73f6a0714e5
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpMergeReference.java
@@ -0,0 +1,60 @@
+/*
+ * 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.api.v2.params.ImmutableMerge;
+import org.projectnessie.client.api.MergeReferenceBuilder;
+import org.projectnessie.client.builder.BaseMergeReferenceBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.MergeResponse;
+import org.projectnessie.model.Reference;
+
+final class HttpMergeReference extends BaseMergeReferenceBuilder {
+ private final HttpClient client;
+
+ public HttpMergeReference(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public MergeReferenceBuilder keepIndividualCommits(boolean keepIndividualCommits) {
+ if (keepIndividualCommits) {
+ throw new IllegalArgumentException("Commits are always squashed during merge operations.");
+ }
+ return this;
+ }
+
+ @Override
+ public MergeResponse merge() throws NessieNotFoundException, NessieConflictException {
+ ImmutableMerge merge =
+ ImmutableMerge.builder()
+ .fromHash(fromHash)
+ .fromRefName(fromRefName)
+ .isDryRun(dryRun)
+ .isFetchAdditionalInfo(fetchAdditionalInfo)
+ .isReturnConflictAsResult(returnConflictAsResult)
+ .build(); // TODO: message
+ return client
+ .newRequest()
+ .path("trees/{ref}/history/merge")
+ .resolveTemplate("ref", Reference.toPathString(branchName, hash))
+ .unwrap(NessieNotFoundException.class, NessieConflictException.class)
+ .post(merge)
+ .readEntity(MergeResponse.class);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpTransplantCommits.java b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpTransplantCommits.java
new file mode 100644
index 00000000000..888deac7a6d
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/http/v2api/HttpTransplantCommits.java
@@ -0,0 +1,61 @@
+/*
+ * 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.api.v2.params.ImmutableTransplant;
+import org.projectnessie.client.api.TransplantCommitsBuilder;
+import org.projectnessie.client.builder.BaseTransplantCommitsBuilder;
+import org.projectnessie.client.http.HttpClient;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.model.MergeResponse;
+import org.projectnessie.model.Reference;
+
+final class HttpTransplantCommits extends BaseTransplantCommitsBuilder {
+ private final HttpClient client;
+
+ public HttpTransplantCommits(HttpClient client) {
+ this.client = client;
+ }
+
+ @Override
+ public TransplantCommitsBuilder keepIndividualCommits(boolean keepIndividualCommits) {
+ if (!keepIndividualCommits) {
+ throw new IllegalArgumentException(
+ "Individual commits are always kept during transplant operations.");
+ }
+ return this;
+ }
+
+ @Override
+ public MergeResponse transplant() throws NessieNotFoundException, NessieConflictException {
+ ImmutableTransplant.Builder transplant =
+ ImmutableTransplant.builder()
+ .message(message)
+ .fromRefName(fromRefName)
+ .hashesToTransplant(hashesToTransplant)
+ .isDryRun(dryRun)
+ .isReturnConflictAsResult(returnConflictAsResult)
+ .isFetchAdditionalInfo(fetchAdditionalInfo);
+ return client
+ .newRequest()
+ .path("trees/{ref}/history/transplant")
+ .resolveTemplate("ref", Reference.toPathString(branchName, hash))
+ .unwrap(NessieNotFoundException.class, NessieConflictException.class)
+ .post(transplant.build())
+ .readEntity(MergeResponse.class);
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/util/v2api/ClientSideCreateNamespace.java b/clients/client/src/main/java/org/projectnessie/client/util/v2api/ClientSideCreateNamespace.java
new file mode 100644
index 00000000000..b8e3f2cd79b
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/util/v2api/ClientSideCreateNamespace.java
@@ -0,0 +1,98 @@
+/*
+ * 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.util.v2api;
+
+import java.util.Map;
+import java.util.Optional;
+import org.projectnessie.client.api.NessieApiV2;
+import org.projectnessie.client.builder.BaseCreateNamespaceBuilder;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNamespaceAlreadyExistsException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.error.NessieReferenceNotFoundException;
+import org.projectnessie.model.Branch;
+import org.projectnessie.model.CommitMeta;
+import org.projectnessie.model.Content;
+import org.projectnessie.model.ContentKey;
+import org.projectnessie.model.ImmutableNamespace;
+import org.projectnessie.model.Namespace;
+import org.projectnessie.model.Operation;
+
+/**
+ * Supports previous "create namespace" functionality of the java client over Nessie API v2.
+ *
+ *
API v2 does not have methods dedicated to manging namespaces. Namespaces are expected to be
+ * managed as ordinary content objects.
+ */
+public final class ClientSideCreateNamespace extends BaseCreateNamespaceBuilder {
+ private final NessieApiV2 api;
+
+ public ClientSideCreateNamespace(NessieApiV2 api) {
+ this.api = api;
+ }
+
+ @Override
+ public Namespace create()
+ throws NessieReferenceNotFoundException, NessieNamespaceAlreadyExistsException {
+ if (namespace.isEmpty()) {
+ throw new IllegalArgumentException("Creating empty namespaces is not supported");
+ }
+
+ ImmutableNamespace content =
+ ImmutableNamespace.builder().from(namespace).properties(properties).build();
+ ContentKey key = ContentKey.of(namespace.getElements());
+
+ Map contentMap;
+ try {
+ contentMap = api.getContent().refName(refName).hashOnRef(hashOnRef).key(key).get();
+ } catch (NessieNotFoundException e) {
+ throw new NessieReferenceNotFoundException(e.getMessage(), e);
+ }
+
+ if (contentMap.containsKey(key)) {
+ if (contentMap.get(key) instanceof Namespace) {
+ throw new NessieNamespaceAlreadyExistsException(
+ String.format("Namespace '%s' already exists", key.toPathString()));
+ } else {
+ throw new NessieNamespaceAlreadyExistsException(
+ String.format(
+ "Another content object with name '%s' already exists", key.toPathString()));
+ }
+ }
+
+ try {
+ Branch branch =
+ api.commitMultipleOperations()
+ .commitMeta(CommitMeta.fromMessage("create namespace " + namespace.name()))
+ .branchName(refName)
+ .hash(hashOnRef)
+ .operation(Operation.Put.of(key, content))
+ .commit();
+
+ contentMap = api.getContent().reference(branch).key(key).get();
+ } catch (NessieNotFoundException | NessieConflictException e) {
+ throw new NessieReferenceNotFoundException(e.getMessage(), e);
+ }
+
+ Optional result = Optional.ofNullable(contentMap.get(key));
+ return result
+ .flatMap(r -> r.unwrap(Namespace.class))
+ .orElseThrow(
+ () ->
+ new NessieReferenceNotFoundException(
+ String.format("Namespace '%s' not found", key)));
+ }
+}
diff --git a/clients/client/src/main/java/org/projectnessie/client/util/v2api/ClientSideDeleteNamespace.java b/clients/client/src/main/java/org/projectnessie/client/util/v2api/ClientSideDeleteNamespace.java
new file mode 100644
index 00000000000..8653bb03c3b
--- /dev/null
+++ b/clients/client/src/main/java/org/projectnessie/client/util/v2api/ClientSideDeleteNamespace.java
@@ -0,0 +1,99 @@
+/*
+ * 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.util.v2api;
+
+import java.util.Map;
+import java.util.Optional;
+import org.projectnessie.client.api.NessieApiV2;
+import org.projectnessie.client.builder.BaseDeleteNamespaceBuilder;
+import org.projectnessie.error.NessieConflictException;
+import org.projectnessie.error.NessieNamespaceNotEmptyException;
+import org.projectnessie.error.NessieNamespaceNotFoundException;
+import org.projectnessie.error.NessieNotFoundException;
+import org.projectnessie.error.NessieReferenceNotFoundException;
+import org.projectnessie.model.CommitMeta;
+import org.projectnessie.model.Content;
+import org.projectnessie.model.ContentKey;
+import org.projectnessie.model.EntriesResponse;
+import org.projectnessie.model.Namespace;
+import org.projectnessie.model.Operation;
+
+/**
+ * Supports previous "delete namespace" functionality of the java client over Nessie API v2.
+ *
+ *
API v2 does not have methods dedicated to manging namespaces. Namespaces are expected to be
+ * managed as ordinary content objects.
+ */
+public final class ClientSideDeleteNamespace extends BaseDeleteNamespaceBuilder {
+ private final NessieApiV2 api;
+
+ public ClientSideDeleteNamespace(NessieApiV2 api) {
+ this.api = api;
+ }
+
+ @Override
+ public void delete()
+ throws NessieNamespaceNotFoundException, NessieReferenceNotFoundException,
+ NessieNamespaceNotEmptyException {
+ ContentKey key = ContentKey.of(namespace.getElements());
+ Map contentMap;
+ try {
+ contentMap = api.getContent().refName(refName).hashOnRef(hashOnRef).key(key).get();
+ } catch (NessieNotFoundException e) {
+ throw new NessieReferenceNotFoundException(e.getMessage(), e);
+ }
+
+ Optional