• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.grpc;
18 
19 import com.google.common.base.Preconditions;
20 import java.util.concurrent.Executor;
21 
22 /**
23  * Uses multiple {@code CallCredentials} as if they were one. If the first credential fails, the
24  * second will not be used. Both must succeed to allow the RPC.
25  */
26 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1914")
27 public final class CompositeCallCredentials extends CallCredentials {
28   private final CallCredentials credentials1;
29   private final CallCredentials credentials2;
30 
CompositeCallCredentials(CallCredentials creds1, CallCredentials creds2)31   public CompositeCallCredentials(CallCredentials creds1, CallCredentials creds2) {
32     this.credentials1 = Preconditions.checkNotNull(creds1, "creds1");
33     this.credentials2 = Preconditions.checkNotNull(creds2, "creds2");
34   }
35 
36   @Override
applyRequestMetadata( RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier)37   public void applyRequestMetadata(
38       RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) {
39     credentials1.applyRequestMetadata(requestInfo, appExecutor,
40         new WrappingMetadataApplier(requestInfo, appExecutor, applier, Context.current()));
41   }
42 
43   private final class WrappingMetadataApplier extends MetadataApplier {
44     private final RequestInfo requestInfo;
45     private final Executor appExecutor;
46     private final MetadataApplier delegate;
47     private final Context context;
48 
WrappingMetadataApplier( RequestInfo requestInfo, Executor appExecutor, MetadataApplier delegate, Context context)49     public WrappingMetadataApplier(
50         RequestInfo requestInfo, Executor appExecutor, MetadataApplier delegate, Context context) {
51       this.requestInfo = requestInfo;
52       this.appExecutor = appExecutor;
53       this.delegate = Preconditions.checkNotNull(delegate, "delegate");
54       this.context = Preconditions.checkNotNull(context, "context");
55     }
56 
57     @Override
apply(Metadata headers)58     public void apply(Metadata headers) {
59       Preconditions.checkNotNull(headers, "headers");
60       Context previous = context.attach();
61       try {
62         credentials2.applyRequestMetadata(
63             requestInfo, appExecutor, new CombiningMetadataApplier(delegate, headers));
64       } finally {
65         context.detach(previous);
66       }
67     }
68 
69     @Override
fail(Status status)70     public void fail(Status status) {
71       delegate.fail(status);
72     }
73   }
74 
75   private static final class CombiningMetadataApplier extends MetadataApplier {
76     private final MetadataApplier delegate;
77     private final Metadata firstHeaders;
78 
CombiningMetadataApplier(MetadataApplier delegate, Metadata firstHeaders)79     public CombiningMetadataApplier(MetadataApplier delegate, Metadata firstHeaders) {
80       this.delegate = delegate;
81       this.firstHeaders = firstHeaders;
82     }
83 
84     @Override
apply(Metadata headers)85     public void apply(Metadata headers) {
86       Preconditions.checkNotNull(headers, "headers");
87       Metadata combined = new Metadata();
88       combined.merge(firstHeaders);
89       combined.merge(headers);
90       delegate.apply(combined);
91     }
92 
93     @Override
fail(Status status)94     public void fail(Status status) {
95       delegate.fail(status);
96     }
97   }
98 }
99