Skip to content

Commit

Permalink
Merge pull request #3711 from DependencyTrack/feature-alpine-2.2.6
Browse files Browse the repository at this point in the history
Bump Alpine to `2.2.6-SNAPSHOT`
  • Loading branch information
nscuro committed May 15, 2024
2 parents b221329 + 706221d commit 3346907
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 168 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>us.springett</groupId>
<artifactId>alpine-parent</artifactId>
<version>2.2.5</version>
<version>2.2.6-SNAPSHOT</version>
</parent>

<modelVersion>4.0.0</modelVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class ProjectProperty implements IConfigProperty, Serializable {

@Persistent
@Column(name = "PROJECT_ID", allowsNull = "false")
@JsonIgnore
private Project project;

@Persistent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,19 @@
*/
package org.dependencytrack.persistence;

import java.util.Date;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import alpine.persistence.PaginatedResult;
import alpine.resources.AlpineRequest;
import org.dependencytrack.model.Component;
import org.dependencytrack.model.DependencyMetrics;
import org.dependencytrack.model.PortfolioMetrics;
import org.dependencytrack.model.Project;
import org.dependencytrack.model.ProjectMetrics;
import org.dependencytrack.model.VulnerabilityMetrics;

import alpine.persistence.PaginatedResult;
import alpine.resources.AlpineRequest;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import java.util.Date;
import java.util.List;

public class MetricsQueryManager extends QueryManager implements IQueryManager {

Expand Down Expand Up @@ -164,17 +162,14 @@ public List<DependencyMetrics> getDependencyMetricsSince(Component component, Da
}

public void synchronizeVulnerabilityMetrics(List<VulnerabilityMetrics> metrics) {
pm.currentTransaction().begin();
// No need for complex updating, just replace the existing ~400 rows with new ones
// Unless we have a contract with clients that the ID of metric records cannot change?

final Query<VulnerabilityMetrics> delete = pm.newQuery("DELETE FROM org.dependencytrack.model.VulnerabilityMetrics");
delete.execute();

// This still does ~400 queries, probably because not all databases can do bulk insert with autogenerated PKs
// Or because Datanucleus is trying to be smart as it wants to cache all these instances
pm.makePersistentAll(metrics);
pm.currentTransaction().commit();
runInTransaction(() -> {
// No need for complex updating, just replace the existing ~400 rows with new ones.
pm.newQuery(Query.JDOQL, "DELETE FROM org.dependencytrack.model.VulnerabilityMetrics").execute();

// This still does ~400 queries, probably because not all databases can do bulk insert with autogenerated PKs
// Or because Datanucleus is trying to be smart as it wants to cache all these instances
pm.makePersistentAll(metrics);
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,16 @@ private NotificationPublisher getDefaultNotificationPublisher(final String clazz
public NotificationPublisher createNotificationPublisher(final String name, final String description,
final Class<? extends Publisher> publisherClass, final String templateContent,
final String templateMimeType, final boolean defaultPublisher) {
pm.currentTransaction().begin();
final NotificationPublisher publisher = new NotificationPublisher();
publisher.setName(name);
publisher.setDescription(description);
publisher.setPublisherClass(publisherClass.getName());
publisher.setTemplate(templateContent);
publisher.setTemplateMimeType(templateMimeType);
publisher.setDefaultPublisher(defaultPublisher);
pm.makePersistent(publisher);
pm.currentTransaction().commit();
pm.getFetchPlan().addGroup(NotificationPublisher.FetchGroup.ALL.name());
return getObjectById(NotificationPublisher.class, publisher.getId());
return callInTransaction(() -> {
final NotificationPublisher publisher = new NotificationPublisher();
publisher.setName(name);
publisher.setDescription(description);
publisher.setPublisherClass(publisherClass.getName());
publisher.setTemplate(templateContent);
publisher.setTemplateMimeType(templateMimeType);
publisher.setDefaultPublisher(defaultPublisher);
return pm.makePersistent(publisher);
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -816,25 +816,26 @@ public List<ProjectProperty> getProjectProperties(final Project project) {
* @param project a Project object
* @param tags a List of Tag objects
*/
@SuppressWarnings("unchecked")
@Override
public void bind(Project project, List<Tag> tags) {
final Query<Tag> query = pm.newQuery(Tag.class, "projects.contains(:project)");
final List<Tag> currentProjectTags = (List<Tag>)query.execute(project);
pm.currentTransaction().begin();
for (final Tag tag: currentProjectTags) {
if (!tags.contains(tag)) {
tag.getProjects().remove(project);
runInTransaction(() -> {
final Query<Tag> query = pm.newQuery(Tag.class, "projects.contains(:project)");
query.setParameters(project);
final List<Tag> currentProjectTags = executeAndCloseList(query);

for (final Tag tag : currentProjectTags) {
if (!tags.contains(tag)) {
tag.getProjects().remove(project);
}
}
}
project.setTags(tags);
for (final Tag tag: tags) {
final List<Project> projects = tag.getProjects();
if (!projects.contains(project)) {
projects.add(project);
project.setTags(tags);
for (final Tag tag : tags) {
final List<Project> projects = tag.getProjects();
if (!projects.contains(project)) {
projects.add(project);
}
}
}
pm.currentTransaction().commit();
});
}

/**
Expand Down
109 changes: 28 additions & 81 deletions src/main/java/org/dependencytrack/persistence/QueryManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import alpine.notification.NotificationLevel;
import alpine.persistence.AlpineQueryManager;
import alpine.persistence.PaginatedResult;
import alpine.persistence.ScopedCustomization;
import alpine.resources.AlpineRequest;
import com.github.packageurl.PackageURL;
import com.google.common.collect.Lists;
Expand Down Expand Up @@ -94,9 +95,8 @@
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import static org.datanucleus.PropertyNames.PROPERTY_QUERY_SQL_ALLOWALL;

/**
* This QueryManager provides a concrete extension of {@link AlpineQueryManager} by
Expand Down Expand Up @@ -416,11 +416,11 @@ public PaginatedResult getProjects(final Team team, final boolean excludeInactiv
return getProjectQueryManager().getProjects(team, excludeInactive, bypass, onlyRoot);
}

public PaginatedResult getProjectsWithoutDescendantsOf(final boolean excludeInactive, final Project project){
public PaginatedResult getProjectsWithoutDescendantsOf(final boolean excludeInactive, final Project project) {
return getProjectQueryManager().getProjectsWithoutDescendantsOf(excludeInactive, project);
}

public PaginatedResult getProjectsWithoutDescendantsOf(final String name, final boolean excludeInactive, final Project project){
public PaginatedResult getProjectsWithoutDescendantsOf(final String name, final boolean excludeInactive, final Project project) {
return getProjectQueryManager().getProjectsWithoutDescendantsOf(name, excludeInactive, project);
}

Expand All @@ -436,15 +436,15 @@ public PaginatedResult getProjects(final Classifier classifier, final boolean in
return getProjectQueryManager().getProjects(classifier, includeMetrics, excludeInactive, onlyRoot);
}

public PaginatedResult getChildrenProjects(final UUID uuid, final boolean includeMetrics, final boolean excludeInactive){
public PaginatedResult getChildrenProjects(final UUID uuid, final boolean includeMetrics, final boolean excludeInactive) {
return getProjectQueryManager().getChildrenProjects(uuid, includeMetrics, excludeInactive);
}

public PaginatedResult getChildrenProjects(final Tag tag, final UUID uuid, final boolean includeMetrics, final boolean excludeInactive){
public PaginatedResult getChildrenProjects(final Tag tag, final UUID uuid, final boolean includeMetrics, final boolean excludeInactive) {
return getProjectQueryManager().getChildrenProjects(tag, uuid, includeMetrics, excludeInactive);
}

public PaginatedResult getChildrenProjects(final Classifier classifier, final UUID uuid, final boolean includeMetrics, final boolean excludeInactive){
public PaginatedResult getChildrenProjects(final Classifier classifier, final UUID uuid, final boolean includeMetrics, final boolean excludeInactive) {
return getProjectQueryManager().getChildrenProjects(classifier, uuid, includeMetrics, excludeInactive);
}

Expand Down Expand Up @@ -674,7 +674,7 @@ public synchronized PolicyViolation addPolicyViolationIfNotExist(final PolicyVio
return getPolicyQueryManager().addPolicyViolationIfNotExist(pv);
}

public PolicyViolation clonePolicyViolation(PolicyViolation sourcePolicyViolation, Component destinationComponent){
public PolicyViolation clonePolicyViolation(PolicyViolation sourcePolicyViolation, Component destinationComponent) {
return getPolicyQueryManager().clonePolicyViolation(sourcePolicyViolation, destinationComponent);
}

Expand Down Expand Up @@ -1275,7 +1275,7 @@ public List<ComponentAnalysisCache> getComponentAnalysisCache(ComponentAnalysisC
}

public synchronized void updateComponentAnalysisCache(ComponentAnalysisCache.CacheType cacheType, String targetHost, String targetType, String target, Date lastOccurrence, JsonObject result) {
getCacheQueryManager().updateComponentAnalysisCache(cacheType, targetHost, targetType, target, lastOccurrence, result);
getCacheQueryManager().updateComponentAnalysisCache(cacheType, targetHost, targetType, target, lastOccurrence, result);
}

public void clearComponentAnalysisCache() {
Expand All @@ -1293,7 +1293,7 @@ public void bind(Project project, List<Tag> tags) {
/**
* Commits the Lucene index.
* @param commitIndex specifies if the search index should be committed (an expensive operation)
* @param clazz the indexable class to commit the index of
* @param clazz the indexable class to commit the index of
*/
public void commitSearchIndex(boolean commitIndex, Class clazz) {
if (commitIndex) {
Expand Down Expand Up @@ -1340,11 +1340,11 @@ public PaginatedResult getTags(String policyUuid) {
* <p>
* Eventually, this may be moved to {@link alpine.persistence.AbstractAlpineQueryManager}.
*
* @param clazz Class of the object to fetch
* @param uuid {@link UUID} of the object to fetch
* @param clazz Class of the object to fetch
* @param uuid {@link UUID} of the object to fetch
* @param fetchGroups Fetch groups to use for this operation
* @return The object if found, otherwise {@code null}
* @param <T> Type of the object
* @param <T> Type of the object
* @throws Exception When closing the query failed
* @since 4.6.0
*/
Expand Down Expand Up @@ -1393,7 +1393,7 @@ public <T> T detachWithGroups(final T object, final List<String> fetchGroups) {
* @param clazz Class of the object to fetch
* @param uuids {@link UUID} list of uuids to fetch
* @return The list of objects found
* @param <T> Type of the object
* @param <T> Type of the object
* @since 4.9.0
*/
public <T> List<T> getObjectsByUuids(final Class<T> clazz, final List<UUID> uuids) {
Expand All @@ -1407,7 +1407,7 @@ public <T> List<T> getObjectsByUuids(final Class<T> clazz, final List<UUID> uuid
* @param clazz Class of the object to fetch
* @param uuids {@link UUID} list of uuids to fetch
* @return The query to execute
* @param <T> Type of the object
* @param <T> Type of the object
* @since 4.9.0
*/
public <T> Query<T> getObjectsByUuidsQuery(final Class<T> clazz, final List<UUID> uuids) {
Expand All @@ -1416,59 +1416,6 @@ public <T> Query<T> getObjectsByUuidsQuery(final Class<T> clazz, final List<UUID
return query;
}

/**
* Convenience method to execute a given {@link Runnable} within the context of a {@link Transaction}.
* <p>
* Eventually, this may be moved to {@link alpine.persistence.AbstractAlpineQueryManager}.
*
* @param runnable The {@link Runnable} to execute
* @since 4.6.0
*/
public void runInTransaction(final Runnable runnable) {
runInTransaction((Function<Transaction, Void>) trx -> {
runnable.run();
return null;
});
}

public void runInTransaction(final Consumer<Transaction> consumer) {
runInTransaction((Function<Transaction, Void>) trx -> {
consumer.accept(trx);
return null;
});
}

/**
* Convenience method to execute a given {@link Supplier} within the context of a {@link Transaction}.
* <p>
* Eventually, this may be moved to {@link alpine.persistence.AbstractAlpineQueryManager}.
*
* @param supplier The {@link Supplier} to execute
* @since 4.9.0
*/
public <T> T runInTransaction(final Supplier<T> supplier) {
return runInTransaction((Function<Transaction, T>) trx -> supplier.get());
}

public <T> T runInTransaction(final Function<Transaction, T> function) {
final Transaction trx = pm.currentTransaction();
final boolean isJoiningExisting = trx.isActive();
try {
if (!isJoiningExisting) {
trx.begin();
}
final T result = function.apply(trx);
if (!isJoiningExisting) {
trx.commit();
}
return result;
} finally {
if (!isJoiningExisting && trx.isActive()) {
trx.rollback();
}
}
}

/**
* Convenience method to ensure that any active transaction is rolled back.
* <p>
Expand All @@ -1487,17 +1434,17 @@ public void ensureNoActiveTransaction() {
}

public void recursivelyDeleteTeam(Team team) {
pm.setProperty("datanucleus.query.sql.allowAll", true);
final Transaction trx = pm.currentTransaction();
pm.currentTransaction().begin();
pm.deletePersistentAll(team.getApiKeys());
String aclDeleteQuery = """
DELETE FROM \"PROJECT_ACCESS_TEAMS\" WHERE \"PROJECT_ACCESS_TEAMS\".\"TEAM_ID\" = ?
""";
final Query query = pm.newQuery(JDOQuery.SQL_QUERY_LANGUAGE, aclDeleteQuery);
query.executeWithArray(team.getId());
pm.deletePersistent(team);
pm.currentTransaction().commit();
runInTransaction(() -> {
pm.deletePersistentAll(team.getApiKeys());

try (var ignored = new ScopedCustomization(pm).withProperty(PROPERTY_QUERY_SQL_ALLOWALL, "true")) {
final Query<?> aclDeleteQuery = pm.newQuery(JDOQuery.SQL_QUERY_LANGUAGE, """
DELETE FROM "PROJECT_ACCESS_TEAMS" WHERE "PROJECT_ACCESS_TEAMS"."TEAM_ID" = ?""");
executeAndCloseWithArray(aclDeleteQuery, team.getId());
}

pm.deletePersistent(team);
});
}

/**
Expand Down Expand Up @@ -1532,7 +1479,7 @@ public List<RepositoryMetaComponent> getRepositoryMetaComponentsBatch(final List

/**
* Returns a list of all {@link RepositoryMetaComponent} objects by {@link RepositoryQueryManager.RepositoryMetaComponentSearch} UUID.
* @param list a list of {@link RepositoryQueryManager.RepositoryMetaComponentSearch}
* @param list a list of {@link RepositoryQueryManager.RepositoryMetaComponentSearch}
* @param batchSize the batch size
* @return a list of {@link RepositoryMetaComponent} objects
* @since 4.9.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

final class VulnerabilityQueryManager extends QueryManager implements IQueryManager {
Expand Down Expand Up @@ -243,15 +243,16 @@ public void addVulnerability(Vulnerability vulnerability, Component component, A
* @param component the component unaffected by the vulnerabiity
*/
public void removeVulnerability(Vulnerability vulnerability, Component component) {
if (contains(vulnerability, component)) {
pm.currentTransaction().begin();
component.removeVulnerability(vulnerability);
pm.currentTransaction().commit();
}
final FindingAttribution fa = getFindingAttribution(vulnerability, component);
if (fa != null) {
delete(fa);
}
runInTransaction(() -> {
if (contains(vulnerability, component)) {
component.removeVulnerability(vulnerability);
}

final FindingAttribution fa = getFindingAttribution(vulnerability, component);
if (fa != null) {
delete(fa);
}
});
}

/**
Expand Down Expand Up @@ -530,7 +531,7 @@ public List<AffectedProject> getAffectedProjects(Vulnerability vulnerability) {
}

public synchronized VulnerabilityAlias synchronizeVulnerabilityAlias(final VulnerabilityAlias alias) {
return runInTransaction(() -> {
return callInTransaction(() -> {
// Query existing aliases that match AT LEAST ONE identifier of the given alias.
//
// For each data source, we want to know the existing aliases where the respective identifier either:
Expand Down

0 comments on commit 3346907

Please sign in to comment.