2525import org .apache .beam .sdk .coders .Coder .NonDeterministicException ;
2626import org .apache .beam .sdk .coders .IterableCoder ;
2727import org .apache .beam .sdk .coders .KvCoder ;
28+ import org .apache .beam .sdk .options .PipelineOptions ;
2829import org .apache .beam .sdk .runners .AppliedPTransform ;
30+ import org .apache .beam .sdk .transforms .GroupByEncryptedKey ;
2931import org .apache .beam .sdk .transforms .PTransform ;
3032import org .apache .beam .sdk .transforms .windowing .DefaultTrigger ;
3133import org .apache .beam .sdk .transforms .windowing .GlobalWindows ;
34+ import org .apache .beam .sdk .util .Secret ;
3235import org .apache .beam .sdk .util .construction .PTransformTranslation ;
3336import org .apache .beam .sdk .util .construction .SdkComponents ;
3437import org .apache .beam .sdk .util .construction .TransformPayloadTranslatorRegistrar ;
3538import org .apache .beam .sdk .values .KV ;
3639import org .apache .beam .sdk .values .PCollection ;
3740import org .apache .beam .sdk .values .PCollection .IsBounded ;
3841import org .apache .beam .sdk .values .WindowingStrategy ;
42+ import org .checkerframework .checker .nullness .qual .Nullable ;
3943
4044/**
4145 * Specialized implementation of {@code GroupByKey} for translating Redistribute transform into
@@ -46,9 +50,13 @@ public class DataflowGroupByKey<K, V>
4650
4751 // Plumbed from Redistribute transform.
4852 private final boolean allowDuplicates ;
53+ private boolean insideGBEK ;
54+ private boolean surroundsGBEK ;
4955
5056 private DataflowGroupByKey (boolean allowDuplicates ) {
5157 this .allowDuplicates = allowDuplicates ;
58+ this .insideGBEK = false ;
59+ this .surroundsGBEK = false ;
5260 }
5361
5462 /**
@@ -79,6 +87,22 @@ public boolean allowDuplicates() {
7987 return allowDuplicates ;
8088 }
8189
90+ /**
91+ * For Beam internal use only. Tells runner that this is an inner GBK inside of a
92+ * GroupByEncryptedKey
93+ */
94+ public void setInsideGBEK () {
95+ this .insideGBEK = true ;
96+ }
97+
98+ /**
99+ * For Beam internal use only. Tells runner that this is a GBK wrapped around of a
100+ * GroupByEncryptedKey
101+ */
102+ public boolean surroundsGBEK () {
103+ return this .surroundsGBEK ;
104+ }
105+
82106 /////////////////////////////////////////////////////////////////////////////
83107
84108 public static void applicableTo (PCollection <?> input ) {
@@ -117,6 +141,20 @@ public PCollection<KV<K, Iterable<V>>> expand(PCollection<KV<K, V>> input) {
117141 "the keyCoder of a DataflowGroupByKey must be deterministic" , e );
118142 }
119143
144+ PipelineOptions options = input .getPipeline ().getOptions ();
145+ String gbekOveride = options .getGbek ();
146+ if (!this .insideGBEK && gbekOveride != null && !gbekOveride .trim ().isEmpty ()) {
147+ this .surroundsGBEK = true ;
148+ Secret hmacSecret = Secret .parseSecretOption (gbekOveride );
149+ DataflowGroupByKey <byte [], KV <byte [], byte []>> gbk = DataflowGroupByKey .create ();
150+ if (this .allowDuplicates ) {
151+ gbk = DataflowGroupByKey .createWithAllowDuplicates ();
152+ }
153+ gbk .setInsideGBEK ();
154+ GroupByEncryptedKey <K , V > gbek = GroupByEncryptedKey .createWithCustomGbk (hmacSecret , gbk );
155+ return input .apply (gbek );
156+ }
157+
120158 // This primitive operation groups by the combination of key and window,
121159 // merging windows as needed, using the windows assigned to the
122160 // key/value input elements and the window merge operation of the
@@ -171,10 +209,22 @@ public String getUrn() {
171209 return PTransformTranslation .GROUP_BY_KEY_TRANSFORM_URN ;
172210 }
173211
212+ @ Override
213+ public String getUrn (DataflowGroupByKey <?, ?> transform ) {
214+ if (transform .surroundsGBEK ()) {
215+ return PTransformTranslation .GROUP_BY_KEY_WRAPPER_TRANSFORM_URN ;
216+ }
217+ return PTransformTranslation .GROUP_BY_KEY_TRANSFORM_URN ;
218+ }
219+
174220 @ Override
175221 @ SuppressWarnings ("nullness" )
176- public RunnerApi .FunctionSpec translate (
222+ public RunnerApi .@ Nullable FunctionSpec translate (
177223 AppliedPTransform <?, ?, DataflowGroupByKey <?, ?>> transform , SdkComponents components ) {
224+ if (transform .getTransform ().surroundsGBEK ()) {
225+ // Can use null for spec for empty composite.
226+ return null ;
227+ }
178228 return RunnerApi .FunctionSpec .newBuilder ().setUrn (getUrn (transform .getTransform ())).build ();
179229 }
180230 }
0 commit comments