1 /* 2 * Copyright 2021 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.xds; 18 19 import com.google.auto.value.AutoValue; 20 import com.google.common.collect.ImmutableMap; 21 import com.google.protobuf.Any; 22 import com.google.protobuf.InvalidProtocolBufferException; 23 import com.google.protobuf.Message; 24 import io.grpc.internal.JsonParser; 25 import io.grpc.internal.JsonUtil; 26 import java.io.IOException; 27 import java.util.Map; 28 29 /** The ClusterSpecifierPlugin for RouteLookup policy. */ 30 final class RouteLookupServiceClusterSpecifierPlugin implements ClusterSpecifierPlugin { 31 32 static final RouteLookupServiceClusterSpecifierPlugin INSTANCE = 33 new RouteLookupServiceClusterSpecifierPlugin(); 34 35 private static final String TYPE_URL = 36 "type.googleapis.com/grpc.lookup.v1.RouteLookupClusterSpecifier"; 37 RouteLookupServiceClusterSpecifierPlugin()38 private RouteLookupServiceClusterSpecifierPlugin() {} 39 40 @Override typeUrls()41 public String[] typeUrls() { 42 return new String[] { 43 TYPE_URL, 44 }; 45 } 46 47 @Override 48 @SuppressWarnings("unchecked") parsePlugin(Message rawProtoMessage)49 public ConfigOrError<RlsPluginConfig> parsePlugin(Message rawProtoMessage) { 50 if (!(rawProtoMessage instanceof Any)) { 51 return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass()); 52 } 53 try { 54 Any anyMessage = (Any) rawProtoMessage; 55 Class<? extends Message> protoClass; 56 try { 57 protoClass = 58 (Class<? extends Message>) 59 Class.forName("io.grpc.lookup.v1.RouteLookupClusterSpecifier"); 60 } catch (ClassNotFoundException e) { 61 return ConfigOrError.fromError("Dependency for 'io.grpc:grpc-rls' is missing: " + e); 62 } 63 Message configProto; 64 try { 65 configProto = anyMessage.unpack(protoClass); 66 } catch (InvalidProtocolBufferException e) { 67 return ConfigOrError.fromError("Invalid proto: " + e); 68 } 69 String jsonString = MessagePrinter.print(configProto); 70 try { 71 Map<String, ?> jsonMap = (Map<String, ?>) JsonParser.parse(jsonString); 72 Map<String, ?> config = JsonUtil.getObject(jsonMap, "routeLookupConfig"); 73 return ConfigOrError.fromConfig(RlsPluginConfig.create(config)); 74 } catch (IOException e) { 75 return ConfigOrError.fromError( 76 "Unable to parse RouteLookupClusterSpecifier: " + jsonString); 77 } 78 } catch (RuntimeException e) { 79 return ConfigOrError.fromError("Error parsing RouteLookupConfig: " + e); 80 } 81 } 82 83 @AutoValue 84 abstract static class RlsPluginConfig implements PluginConfig { 85 config()86 abstract ImmutableMap<String, ?> config(); 87 create(Map<String, ?> config)88 static RlsPluginConfig create(Map<String, ?> config) { 89 return new AutoValue_RouteLookupServiceClusterSpecifierPlugin_RlsPluginConfig( 90 ImmutableMap.copyOf(config)); 91 } 92 93 @Override typeUrl()94 public String typeUrl() { 95 return TYPE_URL; 96 } 97 } 98 } 99