1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.google.api.generator.gapic.model;
16 
17 import com.google.api.generator.gapic.utils.JavaStyle;
18 import com.google.auto.value.AutoValue;
19 import com.google.common.collect.ImmutableSet;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.stream.Collectors;
25 import javax.annotation.Nullable;
26 
27 @AutoValue
28 public abstract class HttpBindings {
29   public enum HttpVerb {
30     GET,
31     PUT,
32     POST,
33     DELETE,
34     PATCH,
35   }
36 
37   @AutoValue
38   public abstract static class HttpBinding implements Comparable<HttpBinding> {
39 
40     // The fully qualified name of the field. e.g. request.complex_object.another_object.name
name()41     public abstract String name();
42 
lowerCamelName()43     abstract String lowerCamelName();
44 
45     // An object that contains all info of the leaf level field
46     @Nullable
field()47     public abstract Field field();
48 
isOptional()49     public boolean isOptional() {
50       return field() != null && field().isProto3Optional();
51     }
52 
isRepeated()53     public boolean isRepeated() {
54       return field() != null && field().isRepeated();
55     }
56 
isEnum()57     public boolean isEnum() {
58       return field() != null && field().isEnum();
59     }
60 
61     @Nullable
valuePattern()62     public abstract String valuePattern();
63 
builder()64     public static HttpBindings.HttpBinding.Builder builder() {
65       return new AutoValue_HttpBindings_HttpBinding.Builder();
66     }
67 
68     @AutoValue.Builder
69     public abstract static class Builder {
70 
setName(String name)71       public abstract HttpBindings.HttpBinding.Builder setName(String name);
72 
setField(Field field)73       public abstract HttpBindings.HttpBinding.Builder setField(Field field);
74 
setLowerCamelName(String lowerCamelName)75       abstract HttpBindings.HttpBinding.Builder setLowerCamelName(String lowerCamelName);
76 
setValuePattern(String valuePattern)77       public abstract HttpBindings.HttpBinding.Builder setValuePattern(String valuePattern);
78 
name()79       abstract String name();
80 
autoBuild()81       abstract HttpBindings.HttpBinding autoBuild();
82 
build()83       public HttpBindings.HttpBinding build() {
84         setLowerCamelName(JavaStyle.toLowerCamelCase(name()));
85         return autoBuild();
86       }
87     }
88 
89     // Do not forget to keep it in sync with equals() implementation.
90     @Override
compareTo(HttpBinding o)91     public int compareTo(HttpBinding o) {
92       int res = name().compareTo(o.name());
93       return res == 0 ? Boolean.compare(isOptional(), o.isOptional()) : res;
94     }
95   }
96 
httpVerb()97   public abstract HttpVerb httpVerb();
98 
pattern()99   public abstract String pattern();
100 
additionalPatterns()101   public abstract List<String> additionalPatterns();
102 
pathParameters()103   public abstract Set<HttpBinding> pathParameters();
104 
queryParameters()105   public abstract Set<HttpBinding> queryParameters();
106 
bodyParameters()107   public abstract Set<HttpBinding> bodyParameters();
108 
isAsteriskBody()109   public abstract boolean isAsteriskBody();
110 
builder()111   public static HttpBindings.Builder builder() {
112     return new AutoValue_HttpBindings.Builder()
113         .setPathParameters(ImmutableSet.of())
114         .setQueryParameters(ImmutableSet.of())
115         .setBodyParameters(ImmutableSet.of());
116   }
117 
118   // Protobuf fields and template patterns follow snake_case style. When translated into actual Java
119   // class fields and URL respectively, those must be converted to lowerCamelCase.
120   // For example:
121   //   in .proto file: "/global/instanceTemplates/{instance_template=*}"
122   //   in .java file:  "/global/instanceTemplates/{instanceTemplate=*}"
lowerCamelPattern()123   public String lowerCamelPattern() {
124     return lowerCamelPattern(pattern(), pathParameters());
125   }
126 
lowerCamelAdditionalPatterns()127   public List<String> lowerCamelAdditionalPatterns() {
128     return additionalPatterns().stream()
129         .map(a -> lowerCamelPattern(a, pathParameters()))
130         .collect(Collectors.toList());
131   }
132 
lowerCamelPattern(String originalPattern, Set<HttpBinding> pathParameters)133   private static String lowerCamelPattern(String originalPattern, Set<HttpBinding> pathParameters) {
134     String lowerCamelPattern = originalPattern;
135     for (HttpBinding pathParam : pathParameters) {
136       lowerCamelPattern =
137           lowerCamelPattern.replaceAll(
138               "\\{" + pathParam.name(), "{" + JavaStyle.toLowerCamelCase(pathParam.name()));
139     }
140     return lowerCamelPattern;
141   }
142 
getPathParametersValuePatterns()143   public Map<String, String> getPathParametersValuePatterns() {
144     Map<String, String> valuePatterns = new LinkedHashMap<>();
145     for (HttpBinding pathParameter : pathParameters()) {
146       valuePatterns.put(pathParameter.lowerCamelName(), pathParameter.valuePattern());
147     }
148     return valuePatterns;
149   }
150 
151   @AutoValue.Builder
152   public abstract static class Builder {
setHttpVerb(HttpVerb httpVerb)153     public abstract HttpBindings.Builder setHttpVerb(HttpVerb httpVerb);
154 
setPattern(String pattern)155     public abstract HttpBindings.Builder setPattern(String pattern);
156 
setAdditionalPatterns(List<String> additionalPatterns)157     public abstract HttpBindings.Builder setAdditionalPatterns(List<String> additionalPatterns);
158 
pattern()159     abstract String pattern();
160 
setPathParameters(Set<HttpBinding> pathParameters)161     public abstract HttpBindings.Builder setPathParameters(Set<HttpBinding> pathParameters);
162 
setQueryParameters(Set<HttpBinding> queryParameters)163     public abstract HttpBindings.Builder setQueryParameters(Set<HttpBinding> queryParameters);
164 
setBodyParameters(Set<HttpBinding> bodyParameters)165     public abstract HttpBindings.Builder setBodyParameters(Set<HttpBinding> bodyParameters);
166 
setIsAsteriskBody(boolean asteriskBody)167     public abstract HttpBindings.Builder setIsAsteriskBody(boolean asteriskBody);
168 
autoBuild()169     public abstract HttpBindings autoBuild();
170 
build()171     public HttpBindings build() {
172       if ("".equals(pattern())) {
173         throw new IllegalArgumentException("pattern cannot be empty");
174       }
175       return autoBuild();
176     }
177   }
178 }
179