1 //
2 // Copyright (C) 2022 The Android Open Source Project
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 #include "codegen_java.h"
18 
19 #include <expresscatalog-utils.h>
20 #include <stdio.h>
21 
22 namespace android {
23 namespace express {
24 
writeJavaFilePreamble(FILE * fd)25 void writeJavaFilePreamble(FILE* fd) {
26     fprintf(fd, "// DO NOT EDIT THIS FILE\n");
27     fprintf(fd, "// This is auto-generated file by expresscatalog-codegen\n\n");
28 }
29 
writeJavaPackagePreamble(FILE * fd,const std::string & packageName)30 void writeJavaPackagePreamble(FILE* fd, const std::string& packageName) {
31     fprintf(fd, "package %s;\n\n", packageName.c_str());
32 
33     fprintf(fd, "import android.util.ArrayMap;\n\n");
34     fprintf(fd, "import java.util.InputMismatchException;\n\n");
35 }
36 
getMetricTypeString(int metricType)37 const char* getMetricTypeString(int metricType) {
38     static const char* metricTypeStringMap[] = {
39             "METRIC_TYPE_UNKNOWN",
40             "METRIC_TYPE_COUNTER",
41             "METRIC_TYPE_HISTOGRAM",
42             "METRIC_TYPE_COUNTER_WITH_UID",
43             "METRIC_TYPE_HISTOGRAM_WITH_UID",
44     };
45 
46     if (metricType == 0) {
47         return nullptr;
48     }
49 
50     return metricTypeStringMap[metricType];
51 }
52 
writeJavaHashMapInitFunction(FILE * fd,const MetricInfoMap & metricsIds)53 void writeJavaHashMapInitFunction(FILE* fd, const MetricInfoMap& metricsIds) {
54     fprintf(fd, "private static ArrayMap<String, MetricInfo> metricIds;\n");
55     fprintf(fd, "static {\n");
56     fprintf(fd, "    metricIds = new ArrayMap<String, MetricInfo>();\n");
57     for (const auto& metricInfo : metricsIds) {
58         const char* metricTypeString = getMetricTypeString(metricInfo.second.type);
59         if (metricTypeString != nullptr) {
60             fprintf(fd, "    metricIds.put(\"%s\", new MetricInfo(%ldl, %s));\n",
61                     metricInfo.first.c_str(), metricInfo.second.hash, metricTypeString);
62         } else {
63             LOGE("Metric type is undefined for %s. Termination\n", metricInfo.first.c_str());
64             exit(-1);
65         }
66     }
67     fprintf(fd, "}\n\n");
68 }
69 
generateCodeImpl(FILE * fd,const MetricInfoMap & metricsIds) const70 bool CodeGeneratorJava::generateCodeImpl(FILE* fd, const MetricInfoMap& metricsIds) const {
71     writeJavaFilePreamble(fd);
72     writeJavaPackagePreamble(fd, mPackageName);
73 
74     fprintf(fd, "public final class %s {\n\n", mClassName.c_str());
75 
76     // TODO: auto-generate enum int constants
77     fprintf(fd, "public static final int METRIC_TYPE_UNKNOWN = 0;\n");
78     fprintf(fd, "public static final int METRIC_TYPE_COUNTER = 1;\n");
79     fprintf(fd, "public static final int METRIC_TYPE_HISTOGRAM = 2;\n");
80     fprintf(fd, "public static final int METRIC_TYPE_COUNTER_WITH_UID = 3;\n");
81     fprintf(fd, "public static final int METRIC_TYPE_HISTOGRAM_WITH_UID = 4;\n\n");
82 
83     fprintf(fd, "private static final class MetricInfo {\n");
84     fprintf(fd, "   MetricInfo(long hash, int type) {\n");
85     fprintf(fd, "       mHash = hash;\n");
86     fprintf(fd, "       mType = type;\n");
87     fprintf(fd, "   }\n");
88     fprintf(fd, "   public long mHash;\n");
89     fprintf(fd, "   public int mType;\n");
90     fprintf(fd, "}\n\n");
91 
92     writeJavaHashMapInitFunction(fd, metricsIds);
93 
94     fprintf(fd, "static long getMetricIdHash(String metricId, int type) {\n");
95     fprintf(fd, "    MetricInfo info = metricIds.get(metricId);\n");
96     fprintf(fd, "    if(info == null) {\n");
97     fprintf(fd,
98             "        throw new IllegalArgumentException(\"Metric is undefined \" + metricId);\n");
99     fprintf(fd, "    }\n");
100     fprintf(fd, "    if(info.mType != type) {\n");
101     fprintf(fd, "        throw new InputMismatchException(\"Metric type is not \" + type);\n");
102     fprintf(fd, "    }\n");
103     fprintf(fd, "    return info.mHash;\n");
104     fprintf(fd, "}\n\n");
105 
106     fprintf(fd, "}\n\n");
107 
108     return true;
109 }
110 
111 }  // namespace express
112 }  // namespace android
113