Copilot commented on code in PR #1154:
URL: https://github.com/apache/ranger/pull/1154#discussion_r3776989006


##########
security-admin/src/main/java/org/apache/ranger/solr/SolrAccessAuditsService.java:
##########
@@ -126,6 +153,520 @@ public VXLong getXAccessAuditSearchCount(SearchCriteria 
searchCriteria) {
         return vXLong;
     }
 
+    public RangerAuditMetrics getLatestAuditMetrics(String serviceType, String 
serviceName) {
+        return getLatestAuditMetrics(serviceType, serviceName, null);
+    }
+
+    public RangerAuditMetrics getLatestAuditMetrics(String serviceType, String 
serviceName, String timezone) {
+        SearchFilter filter = buildSearchFilter(serviceType, serviceName, 
null, null, null);
+
+        SolrQuery query = buildMetricsQuery();
+        applyAuditMetricsFilters(query, filter);
+        addLatestMetricsRangeFilter(query);
+        applyTimezone(query, timezone);
+
+        QueryResponse response = runMetricsQuery(query, "latest audit 
metrics");
+        long count = response.getResults() != null ? 
response.getResults().getNumFound() : 0L;
+        return buildAuditMetrics(serviceType, serviceName, null, null, null, 
count);
+    }
+
+    public RangerAuditMetrics getAuditMetrics(Long serviceId) {
+        return getAuditMetrics(serviceId, null);
+    }
+
+    public RangerAuditMetrics getAuditMetrics(Long serviceId, String timezone) 
{
+        if (serviceId == null) {
+            throw restErrorUtil.createRESTException("AuditMetrics id is 
required");
+        }
+
+        if (daoManager == null || daoManager.getXXService() == null) {
+            throw restErrorUtil.createRESTException("Service lookup is not 
available");
+        }
+
+        XXService service = daoManager.getXXService().getById(serviceId);
+        if (service == null) {
+            throw restErrorUtil.createRESTException("AuditMetrics with Id: " + 
serviceId + " does not exist");
+        }
+
+        String serviceName = service.getName();
+        String serviceType = resolveServiceType(service);
+
+        RangerAuditMetrics metric = getLatestAuditMetrics(serviceType, 
serviceName, timezone);
+        metric.setId(serviceId);
+        return metric;
+    }
+
+    public List<RangerAuditMetrics> getLatestAuditMetricsList(SearchFilter 
filter) {
+        return getLatestAuditMetricsList(filter, null);
+    }
+
+    public List<RangerAuditMetrics> getLatestAuditMetricsList(SearchFilter 
filter, String timezone) {
+        SolrQuery query = buildMetricsQuery();
+        query.set("json.facet", buildAuditMetricsListFacet());
+
+        applyAuditMetricsFilters(query, filter);
+        addLatestMetricsRangeFilter(query);
+        applyTimezone(query, timezone);
+
+        return extractAuditMetricsList(runMetricsQuery(query, "audit metrics 
list"), filter);
+    }
+
+    public List<RangerAuditMetricsByDays> getAuditMetricsByDays(int 
olderThanInDays, SearchFilter filter) {
+        return getAuditMetricsByDays(olderThanInDays, filter, null);
+    }
+
+    public List<RangerAuditMetricsByDays> getAuditMetricsByDays(int 
olderThanInDays, SearchFilter filter, String timezone) {
+        SolrQuery query = buildMetricsQuery();
+        query.set("json.facet", buildAuditAccessMetricsFacet(olderThanInDays));
+
+        applyAuditMetricsFilters(query, filter);
+        applyTimezone(query, timezone);
+
+        return extractAuditMetricsByDays(runMetricsQuery(query, "audit metrics 
by days"), filter);
+    }
+
+    public List<RangerAuditMetricsByHours> getAuditMetricsByHours(SearchFilter 
filter) {
+        return getAuditMetricsByHours(filter, null);
+    }
+
+    public List<RangerAuditMetricsByHours> getAuditMetricsByHours(SearchFilter 
filter, String timezone) {
+        SolrQuery query = buildMetricsQuery();
+        query.set("json.facet", buildAuditMetricsByHourFacet());
+
+        applyAuditMetricsFilters(query, filter);
+        addTodayMetricsRangeFilter(query);
+        applyTimezone(query, timezone);
+
+        return extractAuditMetricsByHours(runMetricsQuery(query, "audit 
metrics by hours"), filter, timezone);
+    }
+
+    private SolrQuery buildMetricsQuery() {
+        SolrQuery query = new SolrQuery();
+        query.setQuery("*:*");
+        query.setRows(0);
+        return query;
+    }
+
+    private QueryResponse runMetricsQuery(SolrQuery query, String context) {
+        SolrClient solrClient = solrMgr.getSolrClient();
+        if (solrClient == null) {
+            LOGGER.warn("Solr client is null, so not running the query.");
+            throw restErrorUtil.createRESTException("Error connecting to 
search engine", MessageEnums.ERROR_SYSTEM);
+        }
+
+        QueryResponse response;
+        try {
+            response = solrUtil.runQuery(solrClient, query);
+        } catch (Throwable e) {
+            LOGGER.error("Error running Solr query for {}.", context, e);
+            throw restErrorUtil.createRESTException("Error running Solr query, 
please check solr configs. " + e.getMessage(), MessageEnums.ERROR_SYSTEM);
+        }
+
+        if (response == null || response.getStatus() != 0) {
+            LOGGER.error("Error running Solr query for {}. Query = {}, 
response = {}", context, query, response);
+            throw restErrorUtil.createRESTException("Unable to connect to 
Audit store !!", MessageEnums.ERROR_SYSTEM);
+        }
+
+        return response;
+    }
+
+    private String buildAuditAccessMetricsFacet(int olderThanInDays) {
+        // If olderThanInDays is 7, we go back 6 days from today to include 
today
+        int daysBack = olderThanInDays - 1;
+
+        return 
String.format("{per_day:{type:range,field:evtTime,start:\"NOW-%dDAYS/DAY\",end:\"NOW\",gap:\"+1DAY\",mincount:1}}",
 daysBack);
+    }
+
+    private String buildAuditMetricsListFacet() {
+        return "{per_repo:{type:terms,field:repo,limit:-1,sort:\"count desc\","
+                + 
"facet:{per_agent:{type:terms,field:agent,limit:-1,missing:true,"
+                + 
"facet:{per_cliip:{type:terms,field:cliIP,limit:-1,missing:true,"
+                + 
"facet:{per_cluster:{type:terms,field:cluster,limit:-1,missing:true"
+                + "}}}}}}}}";
+    }
+
+    private String buildAuditMetricsByHourFacet() {
+        return 
"{per_hour:{type:range,field:evtTime,start:\"NOW/DAY\",end:\"NOW\",gap:\"+1HOUR\"}}";
+    }
+
+    private void addLatestMetricsRangeFilter(SolrQuery query) {
+        if (query == null) {
+            return;
+        }
+
+        query.addFilterQuery("evtTime:[NOW-1DAY TO NOW]");
+    }
+
+    private void addTodayMetricsRangeFilter(SolrQuery query) {
+        if (query == null) {
+            return;
+        }
+
+        query.addFilterQuery("evtTime:[NOW/DAY TO NOW]");
+    }
+
+    private SearchFilter buildSearchFilter(String serviceType, String 
serviceName, String appId, String clusterName, String clientIP) {
+        SearchFilter filter = new SearchFilter();
+        filter.setParam(SearchFilter.SERVICE_TYPE, serviceType);
+        filter.setParam(SearchFilter.SERVICE_NAME, serviceName);
+        filter.setParam(SearchFilter.APP_ID, appId);
+        filter.setParam(SearchFilter.CLUSTER_NAME, clusterName);
+        filter.setParam(SearchFilter.CLIENT_IP, clientIP);
+        return filter;
+    }
+
+    private void applyAuditMetricsFilters(SolrQuery query, SearchFilter 
filter) {
+        if (query == null || filter == null) {
+            return;
+        }
+
+        String serviceName = filter.getParam(SearchFilter.SERVICE_NAME);
+        addFilterQuery(query, "repo", serviceName);
+
+        String serviceType = filter.getParam(SearchFilter.SERVICE_TYPE);
+        if (StringUtils.isNotBlank(serviceType)) {
+            long repoType = resolveRepoType(serviceType);
+            if (repoType == MISSING_REPO_TYPE_SENTINEL) {
+                query.addFilterQuery("repoType:-1");
+            } else {
+                query.addFilterQuery("repoType:" + repoType);
+            }
+        }
+
+        addFilterQuery(query, "cluster", 
filter.getParam(SearchFilter.CLUSTER_NAME));
+        addFilterQuery(query, "cliIP", 
filter.getParam(SearchFilter.CLIENT_IP));
+        addFilterQuery(query, "agent", filter.getParam(SearchFilter.APP_ID));
+    }
+
+    private void addFilterQuery(SolrQuery query, String field, String value) {
+        if (query == null || StringUtils.isBlank(value)) {
+            return;
+        }
+
+        String escapedValue = 
ClientUtils.escapeQueryChars(value.trim().toLowerCase());
+        query.addFilterQuery(field + ":" + escapedValue);
+    }
+
+    private void applyTimezone(SolrQuery query, String timezone) {
+        if (query == null || StringUtils.isBlank(timezone)) {
+            return;
+        }
+
+        query.set("TZ", timezone.trim());
+    }

Review Comment:
   `applyTimezone()` forwards the raw user-provided timezone to Solr without 
validation, but hour-bucket extraction later falls back to UTC for invalid 
timezones. Validating here (and falling back to a known-good TZ) avoids 
inconsistent behavior and potential query failures when an invalid timezone is 
provided.



##########
security-admin/src/main/java/org/apache/ranger/solr/SolrAccessAuditsService.java:
##########
@@ -126,6 +153,520 @@ public VXLong getXAccessAuditSearchCount(SearchCriteria 
searchCriteria) {
         return vXLong;
     }
 
+    public RangerAuditMetrics getLatestAuditMetrics(String serviceType, String 
serviceName) {
+        return getLatestAuditMetrics(serviceType, serviceName, null);
+    }
+
+    public RangerAuditMetrics getLatestAuditMetrics(String serviceType, String 
serviceName, String timezone) {
+        SearchFilter filter = buildSearchFilter(serviceType, serviceName, 
null, null, null);
+
+        SolrQuery query = buildMetricsQuery();
+        applyAuditMetricsFilters(query, filter);
+        addLatestMetricsRangeFilter(query);
+        applyTimezone(query, timezone);
+
+        QueryResponse response = runMetricsQuery(query, "latest audit 
metrics");
+        long count = response.getResults() != null ? 
response.getResults().getNumFound() : 0L;
+        return buildAuditMetrics(serviceType, serviceName, null, null, null, 
count);
+    }
+
+    public RangerAuditMetrics getAuditMetrics(Long serviceId) {
+        return getAuditMetrics(serviceId, null);
+    }
+
+    public RangerAuditMetrics getAuditMetrics(Long serviceId, String timezone) 
{
+        if (serviceId == null) {
+            throw restErrorUtil.createRESTException("AuditMetrics id is 
required");
+        }
+
+        if (daoManager == null || daoManager.getXXService() == null) {
+            throw restErrorUtil.createRESTException("Service lookup is not 
available");
+        }
+
+        XXService service = daoManager.getXXService().getById(serviceId);
+        if (service == null) {
+            throw restErrorUtil.createRESTException("AuditMetrics with Id: " + 
serviceId + " does not exist");
+        }
+
+        String serviceName = service.getName();
+        String serviceType = resolveServiceType(service);
+
+        RangerAuditMetrics metric = getLatestAuditMetrics(serviceType, 
serviceName, timezone);
+        metric.setId(serviceId);
+        return metric;
+    }
+
+    public List<RangerAuditMetrics> getLatestAuditMetricsList(SearchFilter 
filter) {
+        return getLatestAuditMetricsList(filter, null);
+    }
+
+    public List<RangerAuditMetrics> getLatestAuditMetricsList(SearchFilter 
filter, String timezone) {
+        SolrQuery query = buildMetricsQuery();
+        query.set("json.facet", buildAuditMetricsListFacet());
+
+        applyAuditMetricsFilters(query, filter);
+        addLatestMetricsRangeFilter(query);
+        applyTimezone(query, timezone);
+
+        return extractAuditMetricsList(runMetricsQuery(query, "audit metrics 
list"), filter);
+    }
+
+    public List<RangerAuditMetricsByDays> getAuditMetricsByDays(int 
olderThanInDays, SearchFilter filter) {
+        return getAuditMetricsByDays(olderThanInDays, filter, null);
+    }
+
+    public List<RangerAuditMetricsByDays> getAuditMetricsByDays(int 
olderThanInDays, SearchFilter filter, String timezone) {
+        SolrQuery query = buildMetricsQuery();
+        query.set("json.facet", buildAuditAccessMetricsFacet(olderThanInDays));
+
+        applyAuditMetricsFilters(query, filter);
+        applyTimezone(query, timezone);
+
+        return extractAuditMetricsByDays(runMetricsQuery(query, "audit metrics 
by days"), filter);
+    }
+
+    public List<RangerAuditMetricsByHours> getAuditMetricsByHours(SearchFilter 
filter) {
+        return getAuditMetricsByHours(filter, null);
+    }
+
+    public List<RangerAuditMetricsByHours> getAuditMetricsByHours(SearchFilter 
filter, String timezone) {
+        SolrQuery query = buildMetricsQuery();
+        query.set("json.facet", buildAuditMetricsByHourFacet());
+
+        applyAuditMetricsFilters(query, filter);
+        addTodayMetricsRangeFilter(query);
+        applyTimezone(query, timezone);
+
+        return extractAuditMetricsByHours(runMetricsQuery(query, "audit 
metrics by hours"), filter, timezone);
+    }
+
+    private SolrQuery buildMetricsQuery() {
+        SolrQuery query = new SolrQuery();
+        query.setQuery("*:*");
+        query.setRows(0);
+        return query;
+    }
+
+    private QueryResponse runMetricsQuery(SolrQuery query, String context) {
+        SolrClient solrClient = solrMgr.getSolrClient();
+        if (solrClient == null) {
+            LOGGER.warn("Solr client is null, so not running the query.");
+            throw restErrorUtil.createRESTException("Error connecting to 
search engine", MessageEnums.ERROR_SYSTEM);
+        }
+
+        QueryResponse response;
+        try {
+            response = solrUtil.runQuery(solrClient, query);
+        } catch (Throwable e) {
+            LOGGER.error("Error running Solr query for {}.", context, e);
+            throw restErrorUtil.createRESTException("Error running Solr query, 
please check solr configs. " + e.getMessage(), MessageEnums.ERROR_SYSTEM);
+        }
+
+        if (response == null || response.getStatus() != 0) {
+            LOGGER.error("Error running Solr query for {}. Query = {}, 
response = {}", context, query, response);
+            throw restErrorUtil.createRESTException("Unable to connect to 
Audit store !!", MessageEnums.ERROR_SYSTEM);
+        }
+
+        return response;
+    }
+
+    private String buildAuditAccessMetricsFacet(int olderThanInDays) {
+        // If olderThanInDays is 7, we go back 6 days from today to include 
today
+        int daysBack = olderThanInDays - 1;
+
+        return 
String.format("{per_day:{type:range,field:evtTime,start:\"NOW-%dDAYS/DAY\",end:\"NOW\",gap:\"+1DAY\",mincount:1}}",
 daysBack);
+    }
+
+    private String buildAuditMetricsListFacet() {
+        return "{per_repo:{type:terms,field:repo,limit:-1,sort:\"count desc\","
+                + 
"facet:{per_agent:{type:terms,field:agent,limit:-1,missing:true,"
+                + 
"facet:{per_cliip:{type:terms,field:cliIP,limit:-1,missing:true,"
+                + 
"facet:{per_cluster:{type:terms,field:cluster,limit:-1,missing:true"
+                + "}}}}}}}}";
+    }
+
+    private String buildAuditMetricsByHourFacet() {
+        return 
"{per_hour:{type:range,field:evtTime,start:\"NOW/DAY\",end:\"NOW\",gap:\"+1HOUR\"}}";
+    }
+
+    private void addLatestMetricsRangeFilter(SolrQuery query) {
+        if (query == null) {
+            return;
+        }
+
+        query.addFilterQuery("evtTime:[NOW-1DAY TO NOW]");
+    }
+
+    private void addTodayMetricsRangeFilter(SolrQuery query) {
+        if (query == null) {
+            return;
+        }
+
+        query.addFilterQuery("evtTime:[NOW/DAY TO NOW]");
+    }
+
+    private SearchFilter buildSearchFilter(String serviceType, String 
serviceName, String appId, String clusterName, String clientIP) {
+        SearchFilter filter = new SearchFilter();
+        filter.setParam(SearchFilter.SERVICE_TYPE, serviceType);
+        filter.setParam(SearchFilter.SERVICE_NAME, serviceName);
+        filter.setParam(SearchFilter.APP_ID, appId);
+        filter.setParam(SearchFilter.CLUSTER_NAME, clusterName);
+        filter.setParam(SearchFilter.CLIENT_IP, clientIP);
+        return filter;
+    }
+
+    private void applyAuditMetricsFilters(SolrQuery query, SearchFilter 
filter) {
+        if (query == null || filter == null) {
+            return;
+        }
+
+        String serviceName = filter.getParam(SearchFilter.SERVICE_NAME);
+        addFilterQuery(query, "repo", serviceName);
+
+        String serviceType = filter.getParam(SearchFilter.SERVICE_TYPE);
+        if (StringUtils.isNotBlank(serviceType)) {
+            long repoType = resolveRepoType(serviceType);
+            if (repoType == MISSING_REPO_TYPE_SENTINEL) {
+                query.addFilterQuery("repoType:-1");
+            } else {
+                query.addFilterQuery("repoType:" + repoType);
+            }
+        }
+
+        addFilterQuery(query, "cluster", 
filter.getParam(SearchFilter.CLUSTER_NAME));
+        addFilterQuery(query, "cliIP", 
filter.getParam(SearchFilter.CLIENT_IP));
+        addFilterQuery(query, "agent", filter.getParam(SearchFilter.APP_ID));
+    }
+
+    private void addFilterQuery(SolrQuery query, String field, String value) {
+        if (query == null || StringUtils.isBlank(value)) {
+            return;
+        }
+
+        String escapedValue = 
ClientUtils.escapeQueryChars(value.trim().toLowerCase());
+        query.addFilterQuery(field + ":" + escapedValue);
+    }
+
+    private void applyTimezone(SolrQuery query, String timezone) {
+        if (query == null || StringUtils.isBlank(timezone)) {
+            return;
+        }
+
+        query.set("TZ", timezone.trim());
+    }
+
+    private long resolveRepoType(String serviceType) {
+        if (StringUtils.isBlank(serviceType)) {
+            return MISSING_REPO_TYPE_SENTINEL;
+        }
+
+        String cacheKey = serviceType.trim().toLowerCase();
+        Long cached = repoTypeByServiceType.get(cacheKey);
+        if (cached != null) {
+            return cached;
+        }
+
+        long resolved = MISSING_REPO_TYPE_SENTINEL;
+        if (daoManager != null && daoManager.getXXServiceDef() != null) {
+            XXServiceDef serviceDef = 
daoManager.getXXServiceDef().findByName(serviceType);
+            if (serviceDef != null && serviceDef.getId() != null) {
+                resolved = serviceDef.getId();
+            }
+        }
+
+        repoTypeByServiceType.put(cacheKey, resolved);
+        return resolved;
+    }
+
+    private List<RangerAuditMetrics> extractAuditMetricsList(QueryResponse 
response, SearchFilter filter) {
+        NamedList<Object> responseList = response.getResponse();
+        if (responseList == null || !(responseList.get(FACETS_KEY) instanceof 
NamedList)) {
+            return Collections.emptyList();
+        }
+
+        NamedList<?> facets = (NamedList<?>) responseList.get(FACETS_KEY);
+        List<?> repoBuckets = extractBuckets(facets.get(FACET_REPO));
+
+        if (repoBuckets == null || repoBuckets.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        String serviceTypeFilter = filter != null ? 
filter.getParam(SearchFilter.SERVICE_TYPE) : null;
+        List<RangerAuditMetrics> metrics = new ArrayList<>();
+
+        processRepoBuckets(repoBuckets, metrics, serviceTypeFilter);
+
+        return metrics;
+    }
+
+    private void processRepoBuckets(List<?> repoBuckets, 
List<RangerAuditMetrics> metrics, String serviceTypeFilter) {
+        for (Object repoBucket : repoBuckets) {
+            Object repoVal = getBucketValue(repoBucket, BUCKET_VAL);
+            if (repoVal == null) {
+                continue;
+            }
+
+            String serviceName = repoVal.toString();
+            List<?> agentBuckets = extractBuckets(getBucketValue(repoBucket, 
FACET_AGENT));
+
+            if (agentBuckets == null || agentBuckets.isEmpty()) {
+                metrics.add(buildAuditMetrics(serviceTypeFilter, serviceName, 
null, null, null, bucketCount(repoBucket)));
+            } else {
+                processAgentBuckets(agentBuckets, metrics, serviceTypeFilter, 
serviceName);
+            }
+        }
+    }
+
+    private void processAgentBuckets(List<?> agentBuckets, 
List<RangerAuditMetrics> metrics, String serviceTypeFilter, String serviceName) 
{
+        for (Object agentBucket : agentBuckets) {
+            String appId = bucketValToString(getBucketValue(agentBucket, 
BUCKET_VAL));
+            if (appId == null) {
+                continue;
+            }

Review Comment:
   The metrics list facet requests `missing:true` for `agent`, but 
`processAgentBuckets()` skips buckets where `val` is null. This drops audit 
counts for documents that don't have an `agent` field, so `/audit/metrics` can 
under-report totals.



##########
agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetrics.java:
##########
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonAutoDetect(fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)

Review Comment:
   These model classes use the deprecated `@JsonSerialize(include=...)` 
pattern, while the codebase largely standardizes on `@JsonInclude(...)` (e.g., 
`agents-common/.../RangerBaseModelObject.java:37-39`). Using 
`@JsonInclude(Include.NON_NULL)` avoids deprecated annotations and aligns with 
existing conventions.



##########
agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByHours.java:
##########
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonAutoDetect(fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)

Review Comment:
   These model classes use the deprecated `@JsonSerialize(include=...)` 
pattern, while the codebase largely standardizes on `@JsonInclude(...)` (e.g., 
`agents-common/.../RangerBaseModelObject.java:37-39`). Using 
`@JsonInclude(Include.NON_NULL)` avoids deprecated annotations and aligns with 
existing conventions.



##########
security-admin/src/main/java/org/apache/ranger/view/RangerAuditMetricsListByDays.java:
##########
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ranger.view;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.ranger.common.view.VList;
+import org.apache.ranger.plugin.model.RangerAuditMetricsByDays;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = 
Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RangerAuditMetricsListByDays extends VList {
+    private static final long serialVersionUID = 1L;
+
+    List<RangerAuditMetricsByDays> auditMetricsByDays = new ArrayList<>();
+
+    public RangerAuditMetricsListByDays() {
+        super();
+    }
+
+    public RangerAuditMetricsListByDays(List<RangerAuditMetricsByDays> 
objList) {
+        super(objList);
+        this.auditMetricsByDays = objList;
+    }
+
+    public List<RangerAuditMetricsByDays> getAuditMetricsListByUnit() {
+        return auditMetricsByDays;
+    }

Review Comment:
   The getter name `getAuditMetricsListByUnit()` doesn’t match the class 
purpose or the corresponding setter `setAuditMetricsListByDays()`. This makes 
the API confusing for callers and inconsistent with 
`RangerAuditMetricsListByHours`.



##########
agents-common/src/main/java/org/apache/ranger/plugin/model/RangerAuditMetricsByDays.java:
##########
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ranger.plugin.model;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
+@JsonAutoDetect(getterVisibility = Visibility.NONE, setterVisibility = 
Visibility.NONE, fieldVisibility = Visibility.ANY)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)

Review Comment:
   These model classes use the deprecated `@JsonSerialize(include=...)` 
pattern, while the codebase largely standardizes on `@JsonInclude(...)` (e.g., 
`agents-common/.../RangerBaseModelObject.java:37-39`). Using 
`@JsonInclude(Include.NON_NULL)` avoids deprecated annotations and aligns with 
existing conventions.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to