View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions copyright [year] [name of copyright owner]".
13   *
14   * Copyright 2015-2016 ForgeRock AS.
15   */
16  package org.forgerock.audit.handlers.jdbc;
17  
18  import static org.forgerock.util.Utils.joinAsString;
19  
20  import java.sql.PreparedStatement;
21  import java.util.ArrayList;
22  import java.util.LinkedList;
23  import java.util.List;
24  
25  import org.forgerock.audit.AuditException;
26  import org.forgerock.json.JsonPointer;
27  import org.forgerock.json.JsonValue;
28  import org.forgerock.json.resource.QueryRequest;
29  import org.forgerock.json.resource.SortKey;
30  import org.slf4j.Logger;
31  import org.slf4j.LoggerFactory;
32  
33  /**
34   * Provides Create, Read, and Query {@link PreparedStatement}'s for databases supporting limit and offset.
35   */
36  class GenericDatabaseStatementProvider extends BaseDatabaseStatementProvider {
37  
38      private static final Logger logger = LoggerFactory.getLogger(GenericDatabaseStatementProvider.class);
39  
40      private final StringSqlQueryFilterVisitor queryFilterVisitor = new StringSqlQueryFilterVisitor();
41  
42      /**
43       * Builds a query event for databases supporting limit and offset.
44       * {@inheritDoc}
45       */
46      @Override
47      public JdbcAuditEvent buildQueryEvent(final TableMapping mapping, final QueryRequest queryRequest,
48              final JsonValue eventTopicMetaData) throws AuditException {
49          final TableMappingParametersPair tableMappingParametersPair = new TableMappingParametersPair(mapping);
50          final String querySelectStatement = buildQuerySql(queryRequest, tableMappingParametersPair);
51          logger.info("Built query select statement: {}", querySelectStatement);
52  
53          final SqlStatementParser sqlStatementParser = new SqlStatementParser(querySelectStatement);
54          final List<Parameter> params = new LinkedList<>();
55          for (String field : sqlStatementParser.getNamedParameters()) {
56              final JsonPointer fieldPointer = new JsonPointer(field);
57              params.add(
58                      new Parameter(
59                              getParameterType(eventTopicMetaData, fieldPointer),
60                              tableMappingParametersPair.getParameters().get(field)));
61          }
62          return new JdbcAuditEvent(sqlStatementParser.getSqlStatement(), params);
63      }
64  
65      private String buildQuerySql(final QueryRequest queryRequest,
66              final TableMappingParametersPair tableMappingParametersPair) {
67          final TableMapping tableMapping = tableMappingParametersPair.getTableMapping();
68  
69          int offsetParam = queryRequest.getPagedResultsOffset();
70          int pageSizeParam = queryRequest.getPageSize();
71          if (pageSizeParam == 0) {
72              pageSizeParam = Integer.MAX_VALUE;
73          }
74  
75          String pageClause = "LIMIT " + pageSizeParam + " OFFSET " + offsetParam;
76  
77          final List<SortKey> sortKeys = queryRequest.getSortKeys();
78          // Check for sort keys and build up order-by syntax
79          if (sortKeys != null && sortKeys.size() > 0) {
80              List<String> keys = new ArrayList<>();
81              for (SortKey sortKey : sortKeys) {
82                  keys.add(tableMappingParametersPair.getColumnName(sortKey.getField()) + (sortKey.isAscendingOrder()
83                          ? " ASC" : " DESC"));
84              }
85              pageClause = "ORDER BY " + joinAsString(", ", keys) + pageClause;
86          }
87  
88          return String.format("SELECT * FROM %s WHERE %s %s",
89                  tableMapping.getTable(),
90                  queryRequest.getQueryFilter().accept(queryFilterVisitor, tableMappingParametersPair).toSql(),
91                  pageClause);
92      }
93  }