-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve JDBI integration with Alpine
Adds an `AlpineRequest`-aware JDBI `StatementCustomizer`, that transparently enriches statement contexts with query template variables and parameter bindings for: * Filtering * Ordering * Pagination * Portfolio Access Control This removes the need for explicit `@DefineOrdering` and `@DefinePagination` parameters in JDBI queries. Functionality-wise, this matches what Alpine is providing via [`AbstractAlpineQueryManager#decorate`](https://github.com/stevespringett/Alpine/blob/c50e5253c6d93387b0c1fd4c4058d25f7dc56abe/alpine-infra/src/main/java/alpine/persistence/AbstractAlpineQueryManager.java#L200-L246) for ordering and pagination, and Dependency-Track via [`QueryManager#preprocessACLs`](https://github.com/DependencyTrack/dependency-track/blob/09fdec3b39d825844d6a08f25cedb149f39385d9/src/main/java/org/dependencytrack/persistence/ProjectQueryManager.java#L897-L933) for portfolio ACLs. This change will reduce code redundancies once we start serving more REST API requests from JDBI queries (i.e. DependencyTrack/hyades#1292). Signed-off-by: nscuro <[email protected]>
- Loading branch information
Showing
31 changed files
with
1,490 additions
and
702 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
src/main/java/org/dependencytrack/persistence/jdbi/AllowOrdering.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* This file is part of Dependency-Track. | ||
* | ||
* Licensed 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. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright (c) OWASP Foundation. All Rights Reserved. | ||
*/ | ||
package org.dependencytrack.persistence.jdbi; | ||
|
||
import org.jdbi.v3.core.config.ConfigRegistry; | ||
import org.jdbi.v3.core.extension.SimpleExtensionConfigurer; | ||
import org.jdbi.v3.core.extension.annotation.UseExtensionConfigurer; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
import java.util.Arrays; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.apache.commons.lang3.StringUtils.trimToNull; | ||
|
||
/** | ||
* @since 5.5.0 | ||
*/ | ||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
@UseExtensionConfigurer(AllowOrdering.ExtensionConfigurer.class) | ||
public @interface AllowOrdering { | ||
|
||
/** | ||
* Columns to allow ordering by. | ||
*/ | ||
Column[] by(); | ||
|
||
/** | ||
* Name of the column that should always be included in the {@code ORDER BY} | ||
* clause. A corresponding {@link Column} must be provided to {@link #by()}. | ||
* <p> | ||
* Can optionally include the ordering direction as {@code asc} or {@code desc}. | ||
*/ | ||
String alwaysBy() default ""; | ||
|
||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.METHOD) | ||
@interface Column { | ||
|
||
/** | ||
* Name of the column to allow ordering by. | ||
* <p> | ||
* It will be quoted automatically with double quotes before insertion to the query. | ||
*/ | ||
String name(); | ||
|
||
/** | ||
* An optional, <strong>raw</strong> name of the column, as used in the query. | ||
* <p> | ||
* When provided, this name will be used instead of {@link #name()}, | ||
* when ordering by a column matching {@link #name()} is requested. | ||
* <p> | ||
* This name will not be quoted automatically. | ||
*/ | ||
String queryName() default ""; | ||
|
||
} | ||
|
||
final class ExtensionConfigurer extends SimpleExtensionConfigurer { | ||
|
||
@Override | ||
public void configure(final ConfigRegistry configRegistry, final Annotation annotation, final Class<?> extensionType) { | ||
final var allowOrderingAnnotation = (AllowOrdering) annotation; | ||
|
||
final var config = configRegistry.get(AlpineRequestConfig.class); | ||
config.setOrderingAlwaysBy(allowOrderingAnnotation.alwaysBy()); | ||
config.setOrderingAllowedColumns(Arrays.stream(allowOrderingAnnotation.by()) | ||
.map(column -> new AlpineRequestConfig.OrderingColumn( | ||
column.name(), | ||
trimToNull(column.queryName()) | ||
)) | ||
.collect(Collectors.toSet())); | ||
} | ||
|
||
} | ||
|
||
} |
89 changes: 89 additions & 0 deletions
89
src/main/java/org/dependencytrack/persistence/jdbi/AlpineRequestConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* This file is part of Dependency-Track. | ||
* | ||
* Licensed 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. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* Copyright (c) OWASP Foundation. All Rights Reserved. | ||
*/ | ||
package org.dependencytrack.persistence.jdbi; | ||
|
||
import org.jdbi.v3.core.config.JdbiConfig; | ||
|
||
import java.util.Collections; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
/** | ||
* @since 5.5.0 | ||
*/ | ||
public class AlpineRequestConfig implements JdbiConfig<AlpineRequestConfig> { | ||
|
||
private Set<OrderingColumn> orderingAllowedColumns = Collections.emptySet(); | ||
private String orderingAlwaysBy = ""; | ||
|
||
// TODO: Make this configurable via annotation when needed (similar to @AllowOrdering). | ||
// In some queries the PROJECT table may be aliased (e.g. as P). | ||
private String projectAclProjectTableName = "PROJECT"; | ||
|
||
@SuppressWarnings("unused") | ||
public AlpineRequestConfig() { | ||
// Used by JDBI to instantiate the class via reflection. | ||
} | ||
|
||
private AlpineRequestConfig(final AlpineRequestConfig that) { | ||
this.orderingAllowedColumns = Set.copyOf(that.orderingAllowedColumns); | ||
this.orderingAlwaysBy = that.orderingAlwaysBy; | ||
this.projectAclProjectTableName = that.projectAclProjectTableName; | ||
} | ||
|
||
@Override | ||
public AlpineRequestConfig createCopy() { | ||
return new AlpineRequestConfig(this); | ||
} | ||
|
||
Optional<OrderingColumn> orderingAllowedColumn(final String name) { | ||
return orderingAllowedColumns.stream() | ||
.filter(column -> column.name().equals(name)) | ||
.findAny(); | ||
} | ||
|
||
Set<OrderingColumn> orderingAllowedColumns() { | ||
return orderingAllowedColumns; | ||
} | ||
|
||
public void setOrderingAllowedColumns(final Set<OrderingColumn> orderingAllowedColumns) { | ||
this.orderingAllowedColumns = orderingAllowedColumns; | ||
} | ||
|
||
String orderingAlwaysBy() { | ||
return orderingAlwaysBy; | ||
} | ||
|
||
public void setOrderingAlwaysBy(final String orderingAlwaysBy) { | ||
this.orderingAlwaysBy = orderingAlwaysBy; | ||
} | ||
|
||
String projectAclProjectTableName() { | ||
return projectAclProjectTableName; | ||
} | ||
|
||
public record OrderingColumn(String name, String queryName) { | ||
|
||
public OrderingColumn(final String name) { | ||
this(name, null); | ||
} | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.