1717 */
1818package org .apache .beam .sdk .io .gcp .pubsub ;
1919
20+ import static org .apache .beam .sdk .util .Preconditions .checkArgumentNotNull ;
21+ import static org .apache .beam .sdk .util .Preconditions .checkStateNotNull ;
2022import static org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .base .Preconditions .checkArgument ;
2123import static org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .base .Preconditions .checkNotNull ;
2224import static org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .base .Preconditions .checkState ;
4042import org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .collect .ImmutableList ;
4143import org .apache .beam .vendor .guava .v32_1_2_jre .com .google .common .collect .ImmutableMap ;
4244import org .checkerframework .checker .nullness .qual .Nullable ;
45+ import org .checkerframework .dataflow .qual .Pure ;
4346import org .slf4j .Logger ;
4447import org .slf4j .LoggerFactory ;
4548
4649/** An (abstract) helper class for talking to Pubsub via an underlying transport. */
47- @ SuppressWarnings ({
48- "nullness" // TODO(https://github.com/apache/beam/issues/20497)
49- })
5050public abstract class PubsubClient implements Closeable {
5151 private static final Logger LOG = LoggerFactory .getLogger (PubsubClient .class );
5252 private static final Map <String , SerializableFunction <String , Schema >>
@@ -82,7 +82,7 @@ PubsubClient newClient(
8282 * Return timestamp as ms-since-unix-epoch corresponding to {@code timestamp}. Throw {@link
8383 * IllegalArgumentException} if timestamp cannot be recognized.
8484 */
85- protected static Long parseTimestampAsMsSinceEpoch (String timestamp ) {
85+ protected static long parseTimestampAsMsSinceEpoch (String timestamp ) {
8686 if (timestamp .isEmpty ()) {
8787 throw new IllegalArgumentException ("Empty timestamp." );
8888 }
@@ -113,17 +113,12 @@ protected static long extractTimestampAttribute(
113113 String timestampAttribute , @ Nullable Map <String , String > attributes ) {
114114 Preconditions .checkState (!timestampAttribute .isEmpty ());
115115 String value = attributes == null ? null : attributes .get (timestampAttribute );
116- checkArgument (
117- value != null ,
118- "PubSub message is missing a value for timestamp attribute %s" ,
119- timestampAttribute );
120- Long timestampMsSinceEpoch = parseTimestampAsMsSinceEpoch (value );
121- checkArgument (
122- timestampMsSinceEpoch != null ,
123- "Cannot interpret value of attribute %s as timestamp: %s" ,
124- timestampAttribute ,
125- value );
126- return timestampMsSinceEpoch ;
116+ String nonNullValue =
117+ checkArgumentNotNull (
118+ value ,
119+ "PubSub message is missing a value for timestamp attribute %s" ,
120+ timestampAttribute );
121+ return parseTimestampAsMsSinceEpoch (nonNullValue );
127122 }
128123
129124 /** Path representing a cloud project id. */
@@ -386,17 +381,21 @@ public static TopicPath topicPathFromName(String projectId, String topicName) {
386381 public abstract static class OutgoingMessage implements Serializable {
387382
388383 /** Underlying Message. May not have publish timestamp set. */
384+ @ Pure
389385 public abstract PubsubMessage getMessage ();
390386
391387 /** Timestamp for element (ms since epoch). */
388+ @ Pure
392389 public abstract long getTimestampMsSinceEpoch ();
393390
394391 /**
395392 * If using an id attribute, the record id to associate with this record's metadata so the
396393 * receiver can reject duplicates. Otherwise {@literal null}.
397394 */
395+ @ Pure
398396 public abstract @ Nullable String recordId ();
399397
398+ @ Pure
400399 public abstract @ Nullable String topic ();
401400
402401 public static OutgoingMessage of (
@@ -415,11 +414,13 @@ public static OutgoingMessage of(
415414 @ Nullable String topic ) {
416415 PubsubMessage .Builder builder =
417416 PubsubMessage .newBuilder ().setData (ByteString .copyFrom (message .getPayload ()));
418- if (message .getAttributeMap () != null ) {
419- builder .putAllAttributes (message .getAttributeMap ());
417+ Map <String , String > attributeMap = message .getAttributeMap ();
418+ if (attributeMap != null ) {
419+ builder .putAllAttributes (attributeMap );
420420 }
421- if (message .getOrderingKey () != null ) {
422- builder .setOrderingKey (message .getOrderingKey ());
421+ String orderingKey = message .getOrderingKey ();
422+ if (orderingKey != null ) {
423+ builder .setOrderingKey (orderingKey );
423424 }
424425 return of (builder .build (), timestampMsSinceEpoch , recordId , topic );
425426 }
@@ -435,21 +436,23 @@ public static OutgoingMessage of(
435436 public abstract static class IncomingMessage implements Serializable {
436437
437438 /** Underlying Message. */
439+ @ Pure
438440 public abstract PubsubMessage message ();
439441
440- /**
441- * Timestamp for element (ms since epoch). Either Pubsub's processing time, or the custom
442- * timestamp associated with the message.
443- */
442+ /** Either Pubsub's processing time, or the custom timestamp associated with the message. */
443+ @ Pure
444444 public abstract long timestampMsSinceEpoch ();
445445
446446 /** Timestamp (in system time) at which we requested the message (ms since epoch). */
447+ @ Pure
447448 public abstract long requestTimeMsSinceEpoch ();
448449
449450 /** Id to pass back to Pubsub to acknowledge receipt of this message. */
451+ @ Pure
450452 public abstract String ackId ();
451453
452454 /** Id to pass to the runner to distinguish this message from all others. */
455+ @ Pure
453456 public abstract String recordId ();
454457
455458 public static IncomingMessage of (
@@ -554,7 +557,7 @@ public abstract void createSchema(
554557 public abstract void deleteSchema (SchemaPath schemaPath ) throws IOException ;
555558
556559 /** Return {@link SchemaPath} from {@link TopicPath} if exists. */
557- public abstract SchemaPath getSchemaPath (TopicPath topicPath ) throws IOException ;
560+ public abstract @ Nullable SchemaPath getSchemaPath (TopicPath topicPath ) throws IOException ;
558561
559562 /** Return a Beam {@link Schema} from the Pub/Sub schema resource, if exists. */
560563 public abstract Schema getSchema (SchemaPath schemaPath ) throws IOException ;
@@ -567,8 +570,10 @@ static Schema fromPubsubSchema(com.google.api.services.pubsub.model.Schema pubsu
567570 "Pub/Sub schema type %s is not supported at this time" , pubsubSchema .getType ()));
568571 }
569572 SerializableFunction <String , Schema > definitionToSchemaFn =
570- schemaTypeToConversionFnMap .get (pubsubSchema .getType ());
571- return definitionToSchemaFn .apply (pubsubSchema .getDefinition ());
573+ checkStateNotNull (schemaTypeToConversionFnMap .get (pubsubSchema .getType ()));
574+ String definition =
575+ checkNotNull (pubsubSchema .getDefinition (), "Pub/Sub schema definition is null" );
576+ return definitionToSchemaFn .apply (definition );
572577 }
573578
574579 /** Convert a {@link com.google.pubsub.v1.Schema} to a Beam {@link Schema}. */
@@ -579,7 +584,7 @@ static Schema fromPubsubSchema(com.google.pubsub.v1.Schema pubsubSchema) {
579584 String .format ("Pub/Sub schema type %s is not supported at this time" , typeName ));
580585 }
581586 SerializableFunction <String , Schema > definitionToSchemaFn =
582- schemaTypeToConversionFnMap .get (typeName );
587+ checkStateNotNull ( schemaTypeToConversionFnMap .get (typeName ) );
583588 return definitionToSchemaFn .apply (pubsubSchema .getDefinition ());
584589 }
585590
0 commit comments