001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.petstore.console.ops; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.util.*; 022 023import org.apache.juneau.commons.beanquery.*; 024import org.apache.juneau.petstore.console.*; 025import org.apache.juneau.petstore.console.pages.*; 026import org.apache.juneau.http.*; 027import org.apache.juneau.petstore.service.*; 028import org.apache.juneau.rest.server.*; 029import org.apache.juneau.console.datatables.*; 030import org.apache.juneau.console.datatables.adapter.*; 031import org.apache.juneau.rest.server.view.*; 032import org.apache.juneau.rest.server.view.freemarker.*; 033 034/** 035 * Audit log: a read-only, server-mode table over the store's audit trail. 036 * 037 * <p> 038 * The table's {@code at} column takes a timestamp range as a column search value; the query layer parses the ISO-8601 039 * instants. 040 * 041 * <h5 class='section'>Example:</h5> 042 * <p class='bjava'> 043 * <jc>// What the table sends as the "at" column search to show one day:</jc> 044 * <js>"$between(2026-09-30T00:00:00Z,2026-10-01T00:00:00Z)"</js> 045 * 046 * <ja>@RestPost</ja>(path=<js>"/query"</js>) 047 * <jk>public</jk> DataTablesResults<AuditEntry> query(<ja>@Content</ja> DataTablesRequest <jv>req</jv>) { 048 * <jk>try</jk> (<jk>var</jk> <jv>s</jv> = store().queryAudit()) { 049 * <jk>return</jk> DataTablesQuery.<jsm>run</jsm>(<jv>req</jv>, <jv>s</jv>); 050 * } 051 * } 052 * </p> 053 */ 054@Rest(path="/audit", title="Audit") 055@SuppressWarnings({ 056 "java:S110" // Inheritance depth comes from the BasicRestServlet hierarchy, not this page. 057}) 058public class AuditRest extends PetstoreConsolePage { 059 060 private static final long serialVersionUID = 1L; 061 062 private static final int ROWS_CAP = 200; 063 064 /** 065 * Renders the Audit page. 066 * 067 * @param req The request; {@code ?builder} renders the builder twin. 068 * @return The page view. 069 */ 070 @RestGet(path="/") 071 public View page(RestRequest req) { 072 return builder(req) ? twin(req, OpsPageBuilders.audit()) : FreemarkerView.of("audit.ftlh"); 073 } 074 075 /** 076 * Server-mode DataTables query over the audit trail. 077 * 078 * @param req The DataTables request. 079 * @return One page of audit entries, or a 200 {@code error} envelope for a malformed search expression. 080 */ 081 @RestPost(path="/query") 082 public DataTablesResults<AuditEntry> query(@Content DataTablesRequest req) { 083 try (var s = store().queryAudit()) { 084 return DataTablesQuery.run(req, s); 085 } catch (BeanQuerySyntaxException e) { 086 return DataTablesResults.error(req.getDraw(), e.getMessage()); 087 } 088 } 089 090 /** 091 * @return The newest audit entries first, capped at {@value #ROWS_CAP}. 092 */ 093 @RestGet(path="/rows") 094 public List<AuditEntry> rows() { 095 var all = tl(store().getAudit()); 096 Collections.reverse(all); 097 return all.size() > ROWS_CAP ? all.subList(0, ROWS_CAP) : all; 098 } 099}