-
Notifications
You must be signed in to change notification settings - Fork 2.9k
[WIP] REST Based Catalog #3424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] REST Based Catalog #3424
Changes from all commits
c2dccbf
21b169c
3c26658
5ce62d1
0da8807
52508c3
a48bb2b
6648eef
cf9d563
5b74cb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /* | ||
| * 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.iceberg.exceptions; | ||
|
|
||
| /** | ||
| * Exception raised when an attempt to perform an operation fails due to invalid permissions. | ||
| */ | ||
| public class NotAuthorizedException extends RuntimeException { | ||
| public NotAuthorizedException(String message) { | ||
| super(message); | ||
| } | ||
|
|
||
| public NotAuthorizedException(String message, Object... args) { | ||
| super(String.format(message, args)); | ||
| } | ||
|
|
||
| public NotAuthorizedException(String message, Throwable cause) { | ||
| super(message, cause); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| /* | ||
| * 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.iceberg.rest; | ||
|
|
||
| import java.util.Map; | ||
| import org.apache.iceberg.catalog.Namespace; | ||
| import org.apache.iceberg.relocated.com.google.common.base.Preconditions; | ||
| import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList; | ||
| import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap; | ||
|
|
||
| /** | ||
| * Represents a REST request to create a namespace / database. | ||
| * | ||
| * Possible example POST body (outer format object possibly only used on Response): | ||
| * { "data": { "namespace": ["prod", "accounting"], properties: {} }} | ||
| */ | ||
| public class CreateNamespaceRequest { | ||
|
|
||
| private Namespace namespace; | ||
| private Map<String, String> properties; | ||
|
|
||
| private CreateNamespaceRequest() { | ||
| } | ||
|
|
||
| private CreateNamespaceRequest(String[] namespaceLevels, Map<String, String> properties) { | ||
| this.namespace = Namespace.of(namespaceLevels); | ||
| this.properties = properties; | ||
| } | ||
|
|
||
| public Namespace getNamespace() { | ||
| return namespace; | ||
| } | ||
|
|
||
| public void setNamespace(Namespace namespace) { | ||
| this.namespace = namespace; | ||
| } | ||
|
|
||
| public Map<String, String> getProperties() { | ||
| return properties; | ||
| } | ||
|
|
||
| public void setProperties(Map<String, String> properties) { | ||
| this.properties = properties; | ||
| } | ||
|
|
||
| public static Builder builder() { | ||
| return new Builder(); | ||
| } | ||
|
|
||
| public static class Builder { | ||
| private ImmutableList.Builder<String> namespaceBuilder; | ||
| private final ImmutableMap.Builder<String, String> propertiesBuilder; | ||
|
|
||
| public Builder() { | ||
| this.namespaceBuilder = ImmutableList.builder(); | ||
| this.propertiesBuilder = ImmutableMap.builder(); | ||
| } | ||
|
|
||
| public Builder withNamespace(Namespace namespace) { | ||
| this.namespaceBuilder.add(namespace.levels()); | ||
| return this; | ||
| } | ||
|
|
||
| public Builder withProperties(Map<String, String> properties) { | ||
| if (properties != null) { | ||
| propertiesBuilder.putAll(properties); | ||
| } | ||
| return this; | ||
| } | ||
|
|
||
| public Builder withProperty(String key, String value) { | ||
| propertiesBuilder.put(key, value); | ||
| return this; | ||
| } | ||
|
|
||
| public CreateNamespaceRequest build() { | ||
| String[] namespaceLevels = namespaceBuilder.build().toArray(new String[0]); | ||
| Preconditions.checkState(namespaceLevels.length > 0, | ||
| "Cannot create a CreateNamespaceRequest with an empty namespace."); | ||
| return new CreateNamespaceRequest(namespaceLevels, propertiesBuilder.build()); | ||
|
|
||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| /* | ||
| * 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.iceberg.rest; | ||
|
|
||
| import java.util.Map; | ||
| import org.apache.iceberg.catalog.Namespace; | ||
| import org.apache.iceberg.relocated.com.google.common.base.Preconditions; | ||
|
|
||
| /** | ||
| * Represents a REST response to a create a namespace / database request. | ||
| * | ||
| * The properties returned will include all the user provided properties from the | ||
| * request, as well as any server-side added properties. | ||
| * | ||
| * Example server-side added properties could include things such as "created-at" | ||
| * or "owner". | ||
| * | ||
| * Presently, the JSON looks as follows: | ||
| * { "namespace": "ns1.ns2.ns3", "properties": { "owner": "hank", "created-at": "1425744000000" } } | ||
| * | ||
| * Eventually, the idea is to wrap responses in IcebergHttpResponse so that it has a more standardized | ||
| * structure, including the possibility of richer metadata on errors, such as tracing telemetry or follw | ||
| * up user instruction. | ||
| * | ||
| * { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you need |
||
| * "error": { }, | ||
| * "data": { | ||
| * "namespace": "ns1.ns2.ns3", | ||
| * "properties": { | ||
| * "owner": "hank", | ||
| * "created-at": "1425744000000" | ||
| * } | ||
| * } | ||
| * } | ||
| * | ||
| * For an error response, we'll see something like the following: | ||
| * | ||
| * { | ||
| * "data": { }, | ||
| * "error": { | ||
| * "message": "Namespace already exists", | ||
| * "type": "AlreadyExistsException", | ||
| * "code": 40901 | ||
| * } | ||
| * } | ||
| */ | ||
| public class CreateNamespaceResponse { | ||
| private Namespace namespace; | ||
| private Map<String, String> properties; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these the properties that the namespace has after create? For example, this may include a "created-at" property that was added by the server automatically.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that was my thinking (about server side additions). I was thinking that this would be either:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I meant #2. All properties of the namespace, including the ones the user sent and the ones that were added automatically. We should document this in the class Javadoc. |
||
|
|
||
| private CreateNamespaceResponse() { | ||
| } | ||
|
|
||
| private CreateNamespaceResponse(Namespace namespace, Map<String, String> properties) { | ||
| this.namespace = namespace; | ||
| this.properties = properties; | ||
| } | ||
|
|
||
| public Namespace getNamespace() { | ||
| return namespace; | ||
| } | ||
|
|
||
| public void setNamespace(Namespace namespace) { | ||
| this.namespace = namespace; | ||
| } | ||
|
|
||
| public Map<String, String> getProperties() { | ||
| return properties; | ||
| } | ||
|
|
||
| public void setProperties(Map<String, String> properties) { | ||
| this.properties = properties; | ||
| } | ||
|
|
||
| public static Builder builder() { | ||
| return new Builder(); | ||
| } | ||
|
|
||
| public static class Builder { | ||
| private Namespace namespace; | ||
| private Map<String, String> properties; | ||
|
|
||
| private Builder() { | ||
|
|
||
| } | ||
|
|
||
| public Builder withNamespace(Namespace ns) { | ||
| this.namespace = ns; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder withProperties(Map<String, String> props) { | ||
| this.properties = props; | ||
| return this; | ||
| } | ||
|
|
||
| public CreateNamespaceResponse build() { | ||
| Preconditions.checkArgument(namespace != null && !namespace.isEmpty(), | ||
| "Cannot create a CreateNamespaceResponse with a null or empty namespace"); | ||
| return new CreateNamespaceResponse(namespace, properties); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently it's actually as follows, without using an array for
Namespace.{ "namespace": "prod.accounting", "properties": { "key1": "value1" } }Now that I have the mock server going, I'm going to enter an OpenAPI spec and then run the tests over the spec (as I've done for a create namespace based one).
Will put the spec in this PR as a separate document.