Skip to content

Commit

Permalink
feat: Add reservation support. (#661)
Browse files Browse the repository at this point in the history
* feat: Add reservation support.

This feature is not be supported in the backend yet. When it is, the BetaApi annotation will be removed.

* feat: Add reservation support.

This feature is not be supported in the backend yet. When it is, the BetaApi annotation will be removed.
  • Loading branch information
dpcollins-google committed Jun 7, 2021
1 parent 06573d1 commit 79bb58c
Show file tree
Hide file tree
Showing 13 changed files with 779 additions and 125 deletions.
19 changes: 17 additions & 2 deletions google-cloud-pubsublite/clirr-ignored-differences.xml
Expand Up @@ -3,15 +3,30 @@
<differences>
<!-- TODO: Remove on next release -->
<difference>
<differenceType>8001</differenceType>
<className>com/google/cloud/pubsublite/PublishMetadata</className>
<differenceType>7006</differenceType>
<className>com/google/cloud/pubsublite/LocationPath</className>
<method>*</method>
<to>*</to>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/pubsublite/AdminClient</className>
<method>*</method>
</difference>
<difference>
<!-- This one is actually a clirr bug: It doesn't handle CRTP well. -->
<differenceType>7006</differenceType>
<className>com/google/cloud/pubsublite/LocationPath$Builder</className>
<method>*</method>
<to>*</to>
</difference>
<difference>
<!-- This one is actually a clirr bug: It doesn't handle CRTP well. -->
<differenceType>7002</differenceType>
<className>com/google/cloud/pubsublite/LocationPath$Builder</className>
<method>*</method>
</difference>
<!-- END TODO: Remove on next release -->
<!-- Added abstract method to AutoValue.Builder class (Always okay) -->
<difference>
<differenceType>7013</differenceType>
Expand Down
Expand Up @@ -17,8 +17,10 @@
package com.google.cloud.pubsublite;

import com.google.api.core.ApiFuture;
import com.google.api.core.BetaApi;
import com.google.api.gax.rpc.ApiException;
import com.google.cloud.pubsublite.internal.ApiBackgroundResource;
import com.google.cloud.pubsublite.proto.Reservation;
import com.google.cloud.pubsublite.proto.Subscription;
import com.google.cloud.pubsublite.proto.Topic;
import com.google.protobuf.FieldMask;
Expand Down Expand Up @@ -174,4 +176,68 @@ ApiFuture<Subscription> createSubscription(
* exception with status {@link com.google.api.gax.rpc.StatusCode.Code#NOT_FOUND}
*/
ApiFuture<Void> deleteSubscription(SubscriptionPath path);

/**
* Create the provided reservation if it does not yet exist.
*
* @param reservation The reservation to create.
* @return A future that will have either an error {@link com.google.api.gax.rpc.ApiException} or
* the reservation on success.
*/
@BetaApi("This may not be implemented in the backend, it is a pre-release feature.")
ApiFuture<Reservation> createReservation(Reservation reservation);

/**
* Get the reservation with id {@code id} if it exists.
*
* @param path The path of the reservation to retrieve.
* @return A future that will have either an error {@link com.google.api.gax.rpc.ApiException} or
* the reservation on success.
*/
@BetaApi("This may not be implemented in the backend, it is a pre-release feature.")
ApiFuture<Reservation> getReservation(ReservationPath path);

/**
* List all reservations for the specified project.
*
* @param path The path of the project to list reservations for.
* @return A future that will have either an error {@link com.google.api.gax.rpc.ApiException} or
* the list of reservation paths on success.
*/
@BetaApi("This may not be implemented in the backend, it is a pre-release feature.")
ApiFuture<List<Reservation>> listReservations(LocationPath path);

/**
* Update the reservation with path {@code reservation.getPath()} if it exists.
*
* @param reservation The reservation to update.
* @param mask The mask indicating which fields should be updated.
* @return A future that will have either an error {@link com.google.api.gax.rpc.ApiException} or
* the resulting reservation on success. Updating nonexistent reservations will cause the
* future to have an exception with status {@link
* com.google.api.gax.rpc.StatusCode.Code#NOT_FOUND}
*/
@BetaApi("This may not be implemented in the backend, it is a pre-release feature.")
ApiFuture<Reservation> updateReservation(Reservation reservation, FieldMask mask);

/**
* Delete the reservation with id {@code id} if it exists.
*
* @param path The path of the reservation to retrieve.
* @return A future that will have either an error {@link com.google.api.gax.rpc.ApiException} or
* void on success. Deleting nonexistent reservations will cause the future to have an
* exception with status {@link com.google.api.gax.rpc.StatusCode.Code#NOT_FOUND}
*/
@BetaApi("This may not be implemented in the backend, it is a pre-release feature.")
ApiFuture<Void> deleteReservation(ReservationPath path);

/**
* Get the list of topics for the reservation with id {@code id} if it exists.
*
* @param path The path of the reservation to retrieve.
* @return A future that will have either an error {@link com.google.api.gax.rpc.ApiException} or
* the list of topics on success.
*/
@BetaApi("This may not be implemented in the backend, it is a pre-release feature.")
ApiFuture<List<TopicPath>> listReservationTopics(ReservationPath path);
}
Expand Up @@ -16,7 +16,10 @@

package com.google.cloud.pubsublite;

import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.StatusCode.Code;
import com.google.auto.value.AutoValue;
import com.google.cloud.pubsublite.internal.CheckedApiException;
import java.io.Serializable;

/** A wrapped string representing a Google Cloud region. */
Expand All @@ -25,10 +28,21 @@ public abstract class CloudRegion implements Serializable {
private static final long serialVersionUID = 6814654654L;

/** Construct a CloudRegion from a string. */
public static CloudRegion of(String value) {
public static CloudRegion of(String value) throws ApiException {
String[] splits = value.split("-", -1);
if (splits.length != 2) {
throw new CheckedApiException("Invalid region name: " + value, Code.INVALID_ARGUMENT)
.underlying;
}
return new AutoValue_CloudRegion(value);
}

/** The string representing this region. */
public abstract String value();

/** {@inheritDoc} */
@Override
public String toString() {
return value();
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2020 Google LLC
*
* 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 com.google.cloud.pubsublite;

import com.google.api.gax.rpc.ApiException;
import com.google.auto.value.AutoOneOf;
import java.io.Serializable;

@AutoOneOf(CloudRegionOrZone.Kind.class)
public abstract class CloudRegionOrZone implements Serializable {
enum Kind {
REGION,
ZONE
}

public abstract Kind getKind();

public abstract CloudRegion region();

public abstract CloudZone zone();

/** Extract the region from this regardless of which case is set. */
public CloudRegion extractRegion() {
switch (getKind()) {
case REGION:
return region();
case ZONE:
return zone().region();
default:
throw new RuntimeException("Unknown case for CloudRegionOrZone.");
}
}

public static CloudRegionOrZone of(CloudRegion region) {
return AutoOneOf_CloudRegionOrZone.region(region);
}

public static CloudRegionOrZone of(CloudZone zone) {
return AutoOneOf_CloudRegionOrZone.zone(zone);
}

public static CloudRegionOrZone parse(String value) throws ApiException {
try {
return of(CloudZone.parse(value));
} catch (ApiException e) {
// pass
}
return of(CloudRegion.of(value));
}

/** {@inheritDoc} */
@Override
public String toString() {
switch (getKind()) {
case REGION:
return region().toString();
case ZONE:
return zone().toString();
default:
throw new RuntimeException("Unknown case for CloudRegionOrZone.");
}
}
}
Expand Up @@ -28,7 +28,7 @@
public abstract class LocationPath implements Serializable {
public abstract ProjectIdOrNumber project();

public abstract CloudZone location();
public abstract CloudRegionOrZone location();

public ProjectPath projectPath() {
return ProjectPath.newBuilder().setProject(project()).build();
Expand All @@ -47,9 +47,7 @@ public static Builder newBuilder() {
public abstract Builder toBuilder();

@AutoValue.Builder
public abstract static class Builder extends ProjectBuilderHelper<Builder> {
public abstract Builder setLocation(CloudZone zone);

public abstract static class Builder extends ProjectLocationBuilderHelper<Builder> {
public abstract LocationPath build();
}

Expand All @@ -65,7 +63,7 @@ public static LocationPath parse(String path) throws ApiException {
ProjectPath project = ProjectPath.parse(String.join("/", Arrays.copyOf(splits, 2)));
return LocationPath.newBuilder()
.setProject(project.project())
.setLocation(CloudZone.parse(splits[3]))
.setLocation(CloudRegionOrZone.parse(splits[3]))
.build();
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2020 Google LLC
*
* 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 com.google.cloud.pubsublite;

abstract class ProjectLocationBuilderHelper<Builder extends ProjectLocationBuilderHelper<Builder>>
extends ProjectBuilderHelper<Builder> {
public abstract Builder setLocation(CloudRegionOrZone location);

public Builder setLocation(CloudRegion region) {
return setLocation(CloudRegionOrZone.of(region));
}

public Builder setLocation(CloudZone zone) {
return setLocation(CloudRegionOrZone.of(zone));
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2020 Google LLC
*
* 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 com.google.cloud.pubsublite;

import static com.google.cloud.pubsublite.internal.UncheckedApiPreconditions.checkArgument;

import com.google.api.gax.rpc.ApiException;
import com.google.auto.value.AutoValue;
import java.io.Serializable;

/** A string wrapper for the name of a reservation. */
@AutoValue
public abstract class ReservationName implements Serializable {
public abstract String value();

@Override
public String toString() {
return value();
}

public static ReservationName of(String value) throws ApiException {
checkArgument(!value.isEmpty());
return new AutoValue_ReservationName(value);
}
}

0 comments on commit 79bb58c

Please sign in to comment.