Feature/ctx aware and access controller2 (#1456)
* Introduce the AccessControlManager and use if for the TargetManagement and TargetTypeManagement. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Extend the access control manager by an API to serialize the current active context and persist it for scheduled background operations like auto-assignment. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Verify modification is permitted before performing automatic assignment Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Start with controlling distribution set type access. Perform some refactoring. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Support distribution set access control. Increase character limit to 512 chars for access control context. Refactor default implementations. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce ContextRunner and define admin execution to check for duplicates before creating/updating entities. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce Software Module, Module Type and Artifact control management. Fix tests. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce access controlling test base. Add first test verifying the read operations for target types. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Finalize target type access controlling test. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce ContextRunnerTest and TargetAccessControllingTest. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Introduce DistributionSetAccessControllingTest and fix missing access control specifications. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Extend test cases. Include only updatable targets into rollout. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Fix action visibility. Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> * Modifiable->Updatable & UPDATE check where needed Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * ContextRunner superseded by ContextAware + ContextRunner remaned to ContextAware (move as a cenral entry/concept). It now extends (and replace) TenantAware + SecurityContextTenantAware becomes ContextAware + Pluggable serialization mechanism (default Java serialization of contexts) for SecurityContextTenantAware (using SecurityContextSerializer) + AccessControl methods are added to ensure no entities fill be retrieved just to call access control - so, if all permitted - no additional db queries will be made + <repo type>AccessControl classes removed and replaced with AccessControl <repo type> generics + AccessControlService removed - every AccessControl is registered and overiden independently + access_control_context in DB increased to 4k (in order to support java security context serialization) + needed adaptaion of implemtation and tests done Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Refactor SoftModules & DistSets Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Refactoring of the Repositories Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Repostiotory level permissions Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Improvements Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Simplification of AccessControl interface * Simplifications & management package Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> * Implementation improvements + Artifact management & repo reviewed and tuned + Action(Status) management & repo reviewed and tuned + SoftwareModule(Type/Meta) management & repo reviewed and tuned + DistributionSet(Type/Tag/Meta) management(+Invalidation) & repo reviewed and tuned + Target(Tag/Type/Meta) management & repo reviewed and tuned + TargetQueryFilter management & repo reviewed and tuned * Apply suggestions from code review Suggestions accepted. Thanks @herdt-michael Co-authored-by: Michael Herdt <michael.herdt@bosch.com> * Apply suggestions from code review 2 Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> --------- Signed-off-by: Michael Herdt <Michael.Herdt@bosch.io> Signed-off-by: Marinov Avgustin <Avgustin.Marinov@bosch.com> Co-authored-by: Michael Herdt <Michael.Herdt@bosch.com>
This commit is contained in:
@@ -14,17 +14,20 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.autoconfigure.security.MultiUserProperties.User;
|
||||
import org.eclipse.hawkbit.im.authentication.PermissionService;
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.InMemoryUserAuthoritiesResolver;
|
||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.SecurityContextSerializer;
|
||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.security.SpringSecurityAuditorAware;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
@@ -49,20 +52,22 @@ import org.springframework.util.CollectionUtils;
|
||||
public class SecurityAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Creates a {@link TenantAware} bean based on the given
|
||||
* {@link UserAuthoritiesResolver}.
|
||||
*
|
||||
* Creates a {@link ContextAware} (hence {@link TenantAware}) bean based on the given
|
||||
* {@link UserAuthoritiesResolver} and {@link SecurityContextSerializer}.
|
||||
*
|
||||
* @param authoritiesResolver
|
||||
* The user authorities/roles resolver
|
||||
*
|
||||
* @return the {@link TenantAware} singleton bean which holds the current
|
||||
* {@link TenantAware} service and make it accessible in beans which
|
||||
* cannot access the service directly, e.g. JPA entities.
|
||||
* @param securityContextSerializer
|
||||
* The security context serializer.
|
||||
*
|
||||
* @return the {@link ContextAware} singleton bean.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TenantAware tenantAware(final UserAuthoritiesResolver authoritiesResolver) {
|
||||
return new SecurityContextTenantAware(authoritiesResolver);
|
||||
public ContextAware contextAware(
|
||||
final UserAuthoritiesResolver authoritiesResolver,
|
||||
@Autowired(required = false) final SecurityContextSerializer securityContextSerializer) {
|
||||
return new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* {@link ContextAware} provides means for getting the current context (via {@link #getCurrentContext()}) and then
|
||||
* to execute a {@link Runnable} or a {@link Function} in the same context using {@link #runInContext(String, Runnable)}
|
||||
* or {@link #runInContext(String, Function, Object)}.
|
||||
* <p/>
|
||||
* This is useful for scheduled background operations like rollouts and auto assignments where they shall
|
||||
* be processed in the scope of the creator.
|
||||
*/
|
||||
public interface ContextAware extends TenantAware {
|
||||
|
||||
/**
|
||||
* Return the current context encoded as a {@link String}. Depending on the implementation it could,
|
||||
* for instance, be a serialized context or a reference to such.
|
||||
*
|
||||
* @return could be empty if there is nothing to serialize or context aware is not supported.
|
||||
*/
|
||||
Optional<String> getCurrentContext();
|
||||
|
||||
/**
|
||||
* Wrap a specific execution in a known and pre-serialized context.
|
||||
*
|
||||
* @param <T> the type of the input to the function
|
||||
* @param <R> the type of the result of the function
|
||||
*
|
||||
* @param serializedContext created by {@link #getCurrentContext()}. Must be non-<code>null</code>.
|
||||
* @param function function to call in the reconstructed context. Must be non-<code>null</code>.
|
||||
* @param t the argument that will be passed to the function
|
||||
* @return the function result
|
||||
*/
|
||||
<T, R> R runInContext(String serializedContext, Function<T, R> function, T t);
|
||||
|
||||
/**
|
||||
* Wrap a specific execution in a known and pre-serialized context.
|
||||
*
|
||||
* @param serializedContext created by {@link #getCurrentContext()}. Must be non-<code>null</code>.
|
||||
* @param runnable runnable to call in the reconstructed context. Must be non-<code>null</code>.
|
||||
*/
|
||||
default void runInContext(String serializedContext, Runnable runnable) {
|
||||
Objects.requireNonNull(runnable);
|
||||
runInContext(serializedContext, v -> {
|
||||
runnable.run();
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,6 @@ public interface TenantAware {
|
||||
* the runner which is implemented to run this specific code
|
||||
* under the given tenant
|
||||
* @return the return type of the {@link TenantRunner}
|
||||
* @throws any
|
||||
* kind of {@link RuntimeException}
|
||||
*/
|
||||
<T> T runAsTenant(String tenant, TenantRunner<T> tenantRunner);
|
||||
|
||||
@@ -60,8 +58,6 @@ public interface TenantAware {
|
||||
* the runner which is implemented to run this specific code
|
||||
* under the given tenant
|
||||
* @return the return type of the {@link TenantRunner}
|
||||
* @throws any
|
||||
* kind of {@link RuntimeException}
|
||||
*/
|
||||
<T> T runAsTenantAsUser(String tenant, String username, TenantRunner<T> tenantRunner);
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
private List<Target> getTargetsWithoutPendingCancellations(final Set<String> controllerIds) {
|
||||
return partitionedParallelExecution(controllerIds, partition -> {
|
||||
return targetManagement.getByControllerID(partition).stream().filter(target -> {
|
||||
if (hasPendingCancellations(target.getControllerId())) {
|
||||
if (hasPendingCancellations(target.getId())) {
|
||||
LOG.debug("Target {} has pending cancellations. Will not send update message to it.",
|
||||
target.getControllerId());
|
||||
return false;
|
||||
@@ -469,8 +469,8 @@ public class AmqpMessageDispatcherService extends BaseAmqpService {
|
||||
return serviceMatcher == null || serviceMatcher.isFromSelf(event);
|
||||
}
|
||||
|
||||
private boolean hasPendingCancellations(final String controllerId) {
|
||||
return deploymentManagement.hasPendingCancellations(controllerId);
|
||||
private boolean hasPendingCancellations(final Long targetId) {
|
||||
return deploymentManagement.hasPendingCancellations(targetId);
|
||||
}
|
||||
|
||||
protected void sendCancelMessageToTarget(final String tenant, final String controllerId, final Long actionId,
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.Anonymo
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.security.SecurityContextSerializer;
|
||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
|
||||
@@ -113,6 +114,9 @@ public class AmqpControllerAuthenticationTest {
|
||||
@Mock
|
||||
private UserAuthoritiesResolver authoritiesResolver;
|
||||
|
||||
@Mock
|
||||
private SecurityContextSerializer securityContextSerializer;
|
||||
|
||||
@Mock
|
||||
private RabbitTemplate rabbitTemplate;
|
||||
|
||||
@@ -147,7 +151,7 @@ public class AmqpControllerAuthenticationTest {
|
||||
when(tenantConfigurationManagementMock.getConfigurationValue(any(), eq(Boolean.class)))
|
||||
.thenReturn(CONFIG_VALUE_FALSE);
|
||||
|
||||
final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver);
|
||||
final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer);
|
||||
final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware);
|
||||
|
||||
authenticationManager = new AmqpControllerAuthentication(systemManagement, controllerManagement,
|
||||
|
||||
@@ -149,9 +149,10 @@ class AmqpMessageDispatcherServiceTest extends AbstractIntegrationTest {
|
||||
assertThat(softwareModule.getArtifacts().isEmpty()).as("Artifact list for softwaremodule should be empty")
|
||||
.isTrue();
|
||||
|
||||
assertThat(softwareModule.getMetadata()).containsExactly(
|
||||
new DmfMetadata(TestdataFactory.VISIBLE_SM_MD_KEY, TestdataFactory.VISIBLE_SM_MD_VALUE));
|
||||
|
||||
assertThat(softwareModule.getMetadata()).allSatisfy(metadata -> {
|
||||
assertThat(metadata.getKey()).isEqualTo(TestdataFactory.VISIBLE_SM_MD_KEY);
|
||||
assertThat(metadata.getValue()).isEqualTo(TestdataFactory.VISIBLE_SM_MD_VALUE);
|
||||
});
|
||||
for (final SoftwareModule softwareModule2 : action.getDistributionSet().getModules()) {
|
||||
if (!softwareModule.getModuleId().equals(softwareModule2.getId())) {
|
||||
continue;
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken;
|
||||
import org.eclipse.hawkbit.security.DmfTenantSecurityToken.FileResource;
|
||||
import org.eclipse.hawkbit.security.SecurityContextSerializer;
|
||||
import org.eclipse.hawkbit.security.SecurityContextTenantAware;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
@@ -148,6 +149,9 @@ public class AmqpMessageHandlerServiceTest {
|
||||
@Mock
|
||||
private UserAuthoritiesResolver authoritiesResolver;
|
||||
|
||||
@Mock
|
||||
private SecurityContextSerializer securityContextSerializer;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<Map<String, String>> attributesCaptor;
|
||||
|
||||
@@ -179,7 +183,7 @@ public class AmqpMessageHandlerServiceTest {
|
||||
lenient().when(tenantConfigurationManagement.getConfigurationValue(MULTI_ASSIGNMENTS_ENABLED, Boolean.class))
|
||||
.thenReturn(multiAssignmentConfig);
|
||||
|
||||
final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver);
|
||||
final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware(authoritiesResolver, securityContextSerializer);
|
||||
final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware);
|
||||
|
||||
amqpMessageHandlerService = new AmqpMessageHandlerService(rabbitTemplate, amqpMessageDispatcherServiceMock,
|
||||
|
||||
@@ -489,7 +489,7 @@ class AmqpMessageHandlerServiceIntegrationTest extends AbstractAmqpServiceIntegr
|
||||
@Expect(type = SoftwareModuleUpdatedEvent.class, count = 6),
|
||||
@Expect(type = DistributionSetCreatedEvent.class, count = 1),
|
||||
@Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 2) })
|
||||
void receiveDownLoadAndInstallMessageAfterAssignment() {
|
||||
void receiveDownloadAndInstallMessageAfterAssignment() {
|
||||
final String controllerId = TARGET_PREFIX + "receiveDownLoadAndInstallMessageAfterAssignment";
|
||||
|
||||
// setup
|
||||
|
||||
@@ -68,22 +68,6 @@ public interface ArtifactManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_CREATE_REPOSITORY)
|
||||
Artifact create(@NotNull @Valid ArtifactUpload artifactUpload);
|
||||
|
||||
/**
|
||||
* Garbage collects artifact binaries if only referenced by given
|
||||
* {@link SoftwareModule#getId()} or {@link SoftwareModule}'s that are
|
||||
* marked as deleted.
|
||||
*
|
||||
*
|
||||
* @param artifactSha1Hash
|
||||
* no longer needed
|
||||
* @param moduleId
|
||||
* the garbage collection call is made for
|
||||
*
|
||||
* @return <code>true</code> if an binary was actually garbage collected
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
boolean clearArtifactBinary(@NotEmpty String artifactSha1Hash, long moduleId);
|
||||
|
||||
/**
|
||||
* Deletes {@link Artifact} based on given id.
|
||||
*
|
||||
@@ -151,7 +135,7 @@ public interface ArtifactManagement {
|
||||
*
|
||||
* @param pageReq
|
||||
* Pageable parameter
|
||||
* @param swId
|
||||
* @param softwareModuleId
|
||||
* software module id
|
||||
* @return Page<Artifact>
|
||||
*
|
||||
@@ -159,12 +143,12 @@ public interface ArtifactManagement {
|
||||
* if software module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<Artifact> findBySoftwareModule(@NotNull Pageable pageReq, long swId);
|
||||
Page<Artifact> findBySoftwareModule(@NotNull Pageable pageReq, long softwareModuleId);
|
||||
|
||||
/**
|
||||
* Count local artifacts for a base software module.
|
||||
*
|
||||
* @param swId
|
||||
* @param softwareModuleId
|
||||
* software module id
|
||||
* @return count by software module
|
||||
*
|
||||
@@ -172,7 +156,7 @@ public interface ArtifactManagement {
|
||||
* if software module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countBySoftwareModule(long swId);
|
||||
long countBySoftwareModule(long softwareModuleId);
|
||||
|
||||
/**
|
||||
* Loads {@link DbArtifact} from store for given {@link Artifact}.
|
||||
|
||||
@@ -472,17 +472,6 @@ public interface ControllerManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
void updateActionExternalRef(long actionId, @NotEmpty String externalRef);
|
||||
|
||||
/**
|
||||
* Retrieves list of {@link Action}s which matches the provided
|
||||
* externalRefs.
|
||||
*
|
||||
* @param externalRefs
|
||||
* for which the actions need to be fetched.
|
||||
* @return list of {@link Action}s matching the externalRefs.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
List<Action> getActiveActionsByExternalRef(@NotNull List<String> externalRefs);
|
||||
|
||||
/**
|
||||
* Retrieves an {@link Action} using {@link Action#getExternalRef()}
|
||||
*
|
||||
|
||||
@@ -207,12 +207,10 @@ public interface DeploymentManagement {
|
||||
long countActionsByTarget(@NotNull String rsqlParam, @NotEmpty String controllerId);
|
||||
|
||||
/**
|
||||
* @return the total amount of stored action status
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countActionStatusAll();
|
||||
|
||||
/**
|
||||
* Returns total count of all actions
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @return the total amount of stored actions
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
@@ -220,6 +218,8 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* Counts the actions which match the given query.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param rsqlParam
|
||||
* RSQL query.
|
||||
@@ -241,29 +241,6 @@ public interface DeploymentManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countActionsByTarget(@NotEmpty String controllerId);
|
||||
|
||||
/**
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet.
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
* @return the count of actions referring to the given distributionSet
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countActionsByDistributionSetIdAndActiveIsTrue(Long distributionSet);
|
||||
|
||||
/**
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet
|
||||
* that are not in a given state.
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
* @param status
|
||||
* the state the actions should not have
|
||||
* @return the count of actions referring to the given distributionSet
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countActionsByDistributionSetIdAndActiveIsTrueAndStatusIsNot(Long distributionSet, Status status);
|
||||
|
||||
/**
|
||||
* Get the {@link Action} entity for given actionId.
|
||||
*
|
||||
@@ -277,9 +254,10 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s from repository.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param pageable
|
||||
* pagination parameter
|
||||
* @param pageable pagination parameter
|
||||
* @return a paged list of {@link Action}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
@@ -287,35 +265,17 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action} entities which match the given RSQL query.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param rsqlParam
|
||||
* RSQL query string
|
||||
* @param pageable
|
||||
* the page request parameter for paging and sorting the result
|
||||
* @param rsqlParam RSQL query string
|
||||
* @param pageable the page request parameter for paging and sorting the result
|
||||
*
|
||||
* @return a paged list of {@link Action}s.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Action> findActions(@NotNull String rsqlParam, @NotNull Pageable pageable);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action} which assigned to a specific
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param pageable
|
||||
* the page request parameter for paging and sorting the result
|
||||
* @param distributionSetId
|
||||
* the distribution set which should be assigned to the actions
|
||||
* in the result
|
||||
* @return a list of {@link Action} which are assigned to a specific
|
||||
* {@link DistributionSet}
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Action> findActionsByDistributionSet(@NotNull Pageable pageable, long distributionSetId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s assigned to a specific {@link Target} and a
|
||||
* given specification.
|
||||
@@ -384,7 +344,8 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* Retrieves all messages for an {@link ActionStatus}.
|
||||
*
|
||||
* <p/>
|
||||
* No entity based access control applied.
|
||||
*
|
||||
* @param pageable
|
||||
* the page request parameter for paging and sorting the result
|
||||
@@ -397,14 +358,15 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* Counts all messages for an {@link ActionStatus}.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
*
|
||||
* @param pageable
|
||||
* the page request parameter for paging and sorting the result
|
||||
* @deprecated Used by UI only. With future removal of UI it could be removed.
|
||||
* @param actionStatusId
|
||||
* the id of {@link ActionStatus} to count the messages from
|
||||
* @return count of messages by a specific {@link ActionStatus} id
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countMessagesByActionStatusId(long actionStatusId);
|
||||
|
||||
@@ -520,6 +482,8 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* Starts all scheduled actions of an RolloutGroup parent.
|
||||
* <p/>
|
||||
* No entity based access control applied.
|
||||
*
|
||||
* @param rolloutId
|
||||
* the rollout the actions belong to
|
||||
@@ -533,16 +497,6 @@ public interface DeploymentManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long startScheduledActionsByRolloutGroupParent(long rolloutId, long distributionSetId, Long rolloutGroupParentId);
|
||||
|
||||
/**
|
||||
* All {@link ActionStatus} entries in the repository.
|
||||
*
|
||||
* @param pageable
|
||||
* the pagination parameter
|
||||
* @return {@link Page} of {@link ActionStatus} entries
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Page<ActionStatus> findActionStatusAll(@NotNull Pageable pageable);
|
||||
|
||||
/**
|
||||
* Returns {@link DistributionSet} that is assigned to given {@link Target}.
|
||||
*
|
||||
@@ -570,7 +524,9 @@ public interface DeploymentManagement {
|
||||
|
||||
/**
|
||||
* Deletes actions which match one of the given action status and which have
|
||||
* not been modified since the given (absolute) time-stamp.
|
||||
* not been modified since the given (absolute) time-stamp. Used for obsolete actions cleanup.
|
||||
* <p/>
|
||||
* No entity based access control applied.
|
||||
*
|
||||
* @param status
|
||||
* Set of action status.
|
||||
@@ -586,12 +542,11 @@ public interface DeploymentManagement {
|
||||
* Checks if there is an action for the device with the given controller ID
|
||||
* that is in the {@link Action.Status#CANCELING} state.
|
||||
*
|
||||
* @param controllerId
|
||||
* of target
|
||||
* @param targetId of target
|
||||
* @return if actions in CANCELING state are present
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
boolean hasPendingCancellations(@NotEmpty String controllerId);
|
||||
boolean hasPendingCancellations(@NotNull Long targetId);
|
||||
|
||||
/**
|
||||
* Cancels all actions that refer to a given distribution set. This method
|
||||
|
||||
@@ -53,7 +53,7 @@ public interface DistributionSetManagement
|
||||
/**
|
||||
* Assigns {@link SoftwareModule} to existing {@link DistributionSet}.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* to assign and update
|
||||
* @param moduleIds
|
||||
* to get assigned
|
||||
@@ -76,13 +76,13 @@ public interface DistributionSetManagement
|
||||
* for the addressed {@link DistributionSet}.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSet assignSoftwareModules(long setId, @NotEmpty Collection<Long> moduleIds);
|
||||
DistributionSet assignSoftwareModules(long id, @NotEmpty Collection<Long> moduleIds);
|
||||
|
||||
/**
|
||||
* Assign a {@link DistributionSetTag} assignment to given
|
||||
* {@link DistributionSet}s.
|
||||
*
|
||||
* @param setIds
|
||||
* @param ids
|
||||
* to assign for
|
||||
* @param tagId
|
||||
* to assign
|
||||
@@ -94,12 +94,12 @@ public interface DistributionSetManagement
|
||||
* distribution sets.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
List<DistributionSet> assignTag(@NotEmpty Collection<Long> setIds, long tagId);
|
||||
List<DistributionSet> assignTag(@NotEmpty Collection<Long> ids, long tagId);
|
||||
|
||||
/**
|
||||
* Creates a list of distribution set meta data entries.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* if the {@link DistributionSet} the metadata has to be created
|
||||
* for
|
||||
* @param metadata
|
||||
@@ -118,12 +118,12 @@ public interface DistributionSetManagement
|
||||
* for the addressed {@link DistributionSet}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
List<DistributionSetMetadata> createMetaData(long setId, @NotEmpty Collection<MetaData> metadata);
|
||||
List<DistributionSetMetadata> createMetaData(long id, @NotEmpty Collection<MetaData> metadata);
|
||||
|
||||
/**
|
||||
* Deletes a distribution set meta data entry.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* where meta data has to be deleted
|
||||
* @param key
|
||||
* of the meta data element
|
||||
@@ -132,7 +132,7 @@ public interface DistributionSetManagement
|
||||
* if given set does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
void deleteMetaData(long setId, @NotEmpty String key);
|
||||
void deleteMetaData(long id, @NotEmpty String key);
|
||||
|
||||
/**
|
||||
* Retrieves the distribution set for a given action.
|
||||
@@ -154,13 +154,13 @@ public interface DistributionSetManagement
|
||||
* Note: for performance reasons it is recommended to use {@link #get(Long)}
|
||||
* if details are not necessary.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* to look for.
|
||||
*
|
||||
* @return {@link DistributionSet}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Optional<DistributionSet> getWithDetails(long setId);
|
||||
Optional<DistributionSet> getWithDetails(long id);
|
||||
|
||||
/**
|
||||
* Find distribution set by name and version.
|
||||
@@ -234,7 +234,7 @@ public interface DistributionSetManagement
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @param setId
|
||||
* @param id
|
||||
* the distribution set id to retrieve the meta data from
|
||||
*
|
||||
* @return a paged result of all meta data entries for a given distribution
|
||||
@@ -244,14 +244,12 @@ public interface DistributionSetManagement
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<DistributionSetMetadata> findMetaDataByDistributionSetId(@NotNull Pageable pageable, long setId);
|
||||
Page<DistributionSetMetadata> findMetaDataByDistributionSetId(@NotNull Pageable pageable, long id);
|
||||
|
||||
/**
|
||||
* Counts all meta data by the given distribution set id.
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @param setId
|
||||
* @param id
|
||||
* the distribution set id to retrieve the meta data count from
|
||||
*
|
||||
* @return count of ds metadata
|
||||
@@ -260,14 +258,14 @@ public interface DistributionSetManagement
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countMetaDataByDistributionSetId(long setId);
|
||||
long countMetaDataByDistributionSetId(long id);
|
||||
|
||||
/**
|
||||
* Finds all meta data by the given distribution set id.
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @param setId
|
||||
* @param id
|
||||
* the distribution set id to retrieve the meta data from
|
||||
* @param rsqlParam
|
||||
* rsql query string
|
||||
@@ -286,8 +284,8 @@ public interface DistributionSetManagement
|
||||
* of distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<DistributionSetMetadata> findMetaDataByDistributionSetIdAndRsql(@NotNull Pageable pageable, long setId,
|
||||
@NotNull String rsqlParam);
|
||||
Page<DistributionSetMetadata> findMetaDataByDistributionSetIdAndRsql(@NotNull Pageable pageable,
|
||||
long id, @NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
* Finds all {@link DistributionSet}s based on completeness.
|
||||
@@ -409,7 +407,7 @@ public interface DistributionSetManagement
|
||||
/**
|
||||
* Finds a single distribution set meta data by its id.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* of the {@link DistributionSet}
|
||||
* @param key
|
||||
* of the meta data element
|
||||
@@ -419,19 +417,19 @@ public interface DistributionSetManagement
|
||||
* is set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Optional<DistributionSetMetadata> getMetaDataByDistributionSetId(long setId, @NotEmpty String key);
|
||||
Optional<DistributionSetMetadata> getMetaDataByDistributionSetId(long id, @NotEmpty String key);
|
||||
|
||||
/**
|
||||
* Checks if a {@link DistributionSet} is currently in use by a target in
|
||||
* the repository.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* to check
|
||||
*
|
||||
* @return <code>true</code> if in use
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
boolean isInUse(long setId);
|
||||
boolean isInUse(long id);
|
||||
|
||||
/**
|
||||
* Toggles {@link DistributionSetTag} assignment to given
|
||||
@@ -439,7 +437,7 @@ public interface DistributionSetManagement
|
||||
* the list have the {@link Tag} not yet assigned, they will be. Only if all
|
||||
* of theme have the tag already assigned they will be removed instead.
|
||||
*
|
||||
* @param setIds
|
||||
* @param ids
|
||||
* to toggle for
|
||||
* @param tagName
|
||||
* to toggle
|
||||
@@ -450,13 +448,13 @@ public interface DistributionSetManagement
|
||||
* if given tag does not exist or (at least one) module
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection<Long> setIds, @NotNull String tagName);
|
||||
DistributionSetTagAssignmentResult toggleTagAssignment(@NotEmpty Collection<Long> ids, @NotNull String tagName);
|
||||
|
||||
/**
|
||||
* Unassigns a {@link SoftwareModule} form an existing
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* to get unassigned form
|
||||
* @param moduleId
|
||||
* to be unassigned
|
||||
@@ -470,13 +468,13 @@ public interface DistributionSetManagement
|
||||
* the DS is already in use.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSet unassignSoftwareModule(long setId, long moduleId);
|
||||
DistributionSet unassignSoftwareModule(long id, long moduleId);
|
||||
|
||||
/**
|
||||
* Unassign a {@link DistributionSetTag} assignment to given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* to unassign for
|
||||
* @param tagId
|
||||
* to unassign
|
||||
@@ -486,12 +484,12 @@ public interface DistributionSetManagement
|
||||
* if set or tag with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSet unAssignTag(long setId, long tagId);
|
||||
DistributionSet unAssignTag(long id, long tagId);
|
||||
|
||||
/**
|
||||
* Updates a distribution set meta data value if corresponding entry exists.
|
||||
*
|
||||
* @param setId
|
||||
* @param id
|
||||
* {@link DistributionSet} of the meta data entry to be updated
|
||||
* @param metadata
|
||||
* meta data entry to be updated
|
||||
@@ -502,7 +500,7 @@ public interface DistributionSetManagement
|
||||
* updated
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSetMetadata updateMetaData(long setId, @NotNull MetaData metadata);
|
||||
DistributionSetMetadata updateMetaData(long id, @NotNull MetaData metadata);
|
||||
|
||||
/**
|
||||
* Count all {@link DistributionSet}s in the repository that are not marked
|
||||
@@ -523,48 +521,47 @@ public interface DistributionSetManagement
|
||||
* Count all {@link org.eclipse.hawkbit.repository.model.Rollout}s by status for
|
||||
* Distribution Set.
|
||||
*
|
||||
* @param dsId
|
||||
* @param id
|
||||
* to look for
|
||||
*
|
||||
* @return List of Statistics for {@link org.eclipse.hawkbit.repository.model.Rollout}s status counts
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
List<Statistic> countRolloutsByStatusForDistributionSet(@NotNull Long dsId);
|
||||
List<Statistic> countRolloutsByStatusForDistributionSet(@NotNull Long id);
|
||||
|
||||
/**
|
||||
* Count all {@link org.eclipse.hawkbit.repository.model.Action}s by status for
|
||||
* Distribution Set.
|
||||
*
|
||||
* @param dsId
|
||||
* @param id
|
||||
* to look for
|
||||
*
|
||||
* @return List of Statistics for {@link org.eclipse.hawkbit.repository.model.Action}s status counts
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
List<Statistic> countActionsByStatusForDistributionSet(@NotNull Long dsId);
|
||||
List<Statistic> countActionsByStatusForDistributionSet(@NotNull Long id);
|
||||
|
||||
/**
|
||||
* Count all {@link org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate}s
|
||||
* for Distribution Set.
|
||||
*
|
||||
* @param dsId
|
||||
* @param id
|
||||
* to look for
|
||||
*
|
||||
* @return number of {@link org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate}s
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Long countAutoAssignmentsForDistributionSet(@NotNull Long dsId);
|
||||
Long countAutoAssignmentsForDistributionSet(@NotNull Long id);
|
||||
|
||||
/**
|
||||
* Sets the specified {@link DistributionSet} as invalidated.
|
||||
*
|
||||
* @param set
|
||||
* @param distributionSet
|
||||
* the ID of the {@link DistributionSet} to be set to invalid
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
void invalidate(DistributionSet set);
|
||||
|
||||
void invalidate(DistributionSet distributionSet);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public interface DistributionSetTagManagement extends RepositoryManagement<Distr
|
||||
* @param pageable
|
||||
* information for page size, offset and sort order.
|
||||
*
|
||||
* @param setId
|
||||
* @param distributionSetId
|
||||
* of the {@link DistributionSet}
|
||||
* @return page of the found {@link TargetTag}s
|
||||
*
|
||||
@@ -69,6 +69,5 @@ public interface DistributionSetTagManagement extends RepositoryManagement<Distr
|
||||
* if {@link DistributionSet} with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<DistributionSetTag> findByDistributionSet(@NotNull Pageable pageable, long setId);
|
||||
|
||||
Page<DistributionSetTag> findByDistributionSet(@NotNull Pageable pageable, long distributionSetId);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public interface DistributionSetTypeManagement
|
||||
/**
|
||||
* Assigns {@link DistributionSetType#getMandatoryModuleTypes()}.
|
||||
*
|
||||
* @param dsTypeId
|
||||
* @param id
|
||||
* to update
|
||||
* @param softwareModuleTypeIds
|
||||
* to assign
|
||||
@@ -71,15 +71,14 @@ public interface DistributionSetTypeManagement
|
||||
* exceeded for the addressed {@link DistributionSetType}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSetType assignOptionalSoftwareModuleTypes(long dsTypeId,
|
||||
@NotEmpty Collection<Long> softwareModuleTypeIds);
|
||||
DistributionSetType assignOptionalSoftwareModuleTypes(long id, @NotEmpty Collection<Long> softwareModuleTypeIds);
|
||||
|
||||
/**
|
||||
* Assigns {@link DistributionSetType#getOptionalModuleTypes()}.
|
||||
*
|
||||
* @param dsTypeId
|
||||
* @param id
|
||||
* to update
|
||||
* @param softwareModuleTypes
|
||||
* @param softwareModuleTypeIds
|
||||
* to assign
|
||||
* @return updated {@link DistributionSetType}
|
||||
*
|
||||
@@ -96,17 +95,16 @@ public interface DistributionSetTypeManagement
|
||||
* exceeded for the addressed {@link DistributionSetType}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSetType assignMandatorySoftwareModuleTypes(long dsTypeId,
|
||||
@NotEmpty Collection<Long> softwareModuleTypes);
|
||||
DistributionSetType assignMandatorySoftwareModuleTypes(long id, @NotEmpty Collection<Long> softwareModuleTypeIds);
|
||||
|
||||
/**
|
||||
* Unassigns a {@link SoftwareModuleType} from the
|
||||
* {@link DistributionSetType}. Does nothing if {@link SoftwareModuleType}
|
||||
* has not been assigned in the first place.
|
||||
*
|
||||
* @param dsTypeId
|
||||
* @param id
|
||||
* to update
|
||||
* @param softwareModuleId
|
||||
* @param softwareModuleTypeId
|
||||
* to unassign
|
||||
* @return updated {@link DistributionSetType}
|
||||
*
|
||||
@@ -118,6 +116,5 @@ public interface DistributionSetTypeManagement
|
||||
* by a {@link DistributionSet}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
DistributionSetType unassignSoftwareModuleType(long dsTypeId, long softwareModuleId);
|
||||
|
||||
DistributionSetType unassignSoftwareModuleType(long id, long softwareModuleTypeId);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ public interface RolloutManagement {
|
||||
/**
|
||||
* Counts all {@link Rollout}s for a specific {@link DistributionSet} that
|
||||
* are stoppable
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param setId
|
||||
* the distribution set
|
||||
|
||||
@@ -108,7 +108,7 @@ public interface SoftwareModuleManagement
|
||||
/**
|
||||
* Deletes a software module meta data entry.
|
||||
*
|
||||
* @param moduleId
|
||||
* @param id
|
||||
* where meta data has to be deleted
|
||||
* @param key
|
||||
* of the metda data element
|
||||
@@ -117,14 +117,14 @@ public interface SoftwareModuleManagement
|
||||
* of module or metadata entry does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
void deleteMetaData(long moduleId, @NotEmpty String key);
|
||||
void deleteMetaData(long id, @NotEmpty String key);
|
||||
|
||||
/**
|
||||
* Returns all modules assigned to given {@link DistributionSet}.
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param setId
|
||||
* @param distributionSetId
|
||||
* to search for
|
||||
*
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
@@ -134,12 +134,12 @@ public interface SoftwareModuleManagement
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<SoftwareModule> findByAssignedTo(@NotNull Pageable pageable, long setId);
|
||||
Page<SoftwareModule> findByAssignedTo(@NotNull Pageable pageable, long distributionSetId);
|
||||
|
||||
/**
|
||||
* Returns count of all modules assigned to given {@link DistributionSet}.
|
||||
*
|
||||
* @param setId
|
||||
* @param distributionSetId
|
||||
* to search for
|
||||
*
|
||||
* @return count of {@link SoftwareModule}s that are assigned to given
|
||||
@@ -149,7 +149,7 @@ public interface SoftwareModuleManagement
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countByAssignedTo(long setId);
|
||||
long countByAssignedTo(long distributionSetId);
|
||||
|
||||
/**
|
||||
* Filter {@link SoftwareModule}s with given
|
||||
@@ -192,7 +192,7 @@ public interface SoftwareModuleManagement
|
||||
/**
|
||||
* Finds a single software module meta data by its id.
|
||||
*
|
||||
* @param moduleId
|
||||
* @param id
|
||||
* where meta data has to be found
|
||||
* @param key
|
||||
* of the meta data element
|
||||
@@ -202,14 +202,14 @@ public interface SoftwareModuleManagement
|
||||
* is module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Optional<SoftwareModuleMetadata> getMetaDataBySoftwareModuleId(long moduleId, @NotEmpty String key);
|
||||
Optional<SoftwareModuleMetadata> getMetaDataBySoftwareModuleId(long id, @NotEmpty String key);
|
||||
|
||||
/**
|
||||
* Finds all meta data by the given software module id.
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @param moduleId
|
||||
* @param id
|
||||
* the software module id to retrieve the meta data from
|
||||
*
|
||||
* @return a paged result of all meta data entries for a given software
|
||||
@@ -219,12 +219,12 @@ public interface SoftwareModuleManagement
|
||||
* if software module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleId(@NotNull Pageable pageable, long moduleId);
|
||||
Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleId(@NotNull Pageable pageable, long id);
|
||||
|
||||
/**
|
||||
* Counts all meta data by the given software module id.
|
||||
*
|
||||
* @param moduleId
|
||||
* @param id
|
||||
* the software module id to retrieve the meta data count from
|
||||
*
|
||||
* @return count of all meta data entries for a given software module id
|
||||
@@ -233,7 +233,7 @@ public interface SoftwareModuleManagement
|
||||
* if software module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countMetaDataBySoftwareModuleId(long moduleId);
|
||||
long countMetaDataBySoftwareModuleId(long id);
|
||||
|
||||
/**
|
||||
* Finds all meta data by the given software module id where
|
||||
@@ -241,7 +241,7 @@ public interface SoftwareModuleManagement
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @param moduleId
|
||||
* @param id
|
||||
* the software module id to retrieve the meta data from
|
||||
*
|
||||
* @return a paged result of all meta data entries for a given software
|
||||
@@ -252,14 +252,14 @@ public interface SoftwareModuleManagement
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(@NotNull Pageable pageable,
|
||||
long moduleId);
|
||||
long id);
|
||||
|
||||
/**
|
||||
* Finds all meta data by the given software module id.
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result
|
||||
* @param moduleId
|
||||
* @param id
|
||||
* the software module id to retrieve the meta data from
|
||||
* @param rsqlParam
|
||||
* filter definition in RSQL syntax
|
||||
@@ -278,7 +278,7 @@ public interface SoftwareModuleManagement
|
||||
* if software module with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Page<SoftwareModuleMetadata> findMetaDataByRsql(@NotNull Pageable pageable, long moduleId,
|
||||
Page<SoftwareModuleMetadata> findMetaDataByRsql(@NotNull Pageable pageable, long id,
|
||||
@NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
@@ -296,7 +296,7 @@ public interface SoftwareModuleManagement
|
||||
*
|
||||
* @param pageable
|
||||
* page parameter
|
||||
* @param orderByDistributionId
|
||||
* @param orderByDistributionSetId
|
||||
* the ID of distribution set to be ordered on top
|
||||
* @param searchText
|
||||
* filtered as "like" on {@link SoftwareModule#getName()}
|
||||
@@ -310,7 +310,7 @@ public interface SoftwareModuleManagement
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
Slice<AssignedSoftwareModule> findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(
|
||||
@NotNull Pageable pageable, long orderByDistributionId, String searchText, Long typeId);
|
||||
@NotNull Pageable pageable, long orderByDistributionSetId, String searchText, Long typeId);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link SoftwareModule}s by their {@link SoftwareModuleType}
|
||||
|
||||
@@ -111,6 +111,8 @@ public interface TargetFilterQueryManagement {
|
||||
/**
|
||||
* Counts all target filters that have a given auto assign distribution set
|
||||
* assigned.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param autoAssignDistributionSetId
|
||||
* the id of the distribution set
|
||||
|
||||
@@ -69,13 +69,13 @@ public interface TargetManagement {
|
||||
/**
|
||||
* Counts number of targets with the given distribution set assigned.
|
||||
*
|
||||
* @param distId to search for
|
||||
* @param distributionSetId to search for
|
||||
* @return number of found {@link Target}s.
|
||||
* @throws EntityNotFoundException if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countByAssignedDistributionSet(long distId);
|
||||
long countByAssignedDistributionSet(long distributionSetId);
|
||||
|
||||
/**
|
||||
* Count {@link Target}s for all the given filter parameters.
|
||||
@@ -95,25 +95,25 @@ public interface TargetManagement {
|
||||
/**
|
||||
* Get the count of targets with the given distribution set id.
|
||||
*
|
||||
* @param distId to search for
|
||||
* @param distributionSetId to search for
|
||||
* @return number of found {@link Target}s.
|
||||
* @throws EntityNotFoundException if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
long countByInstalledDistributionSet(long distId);
|
||||
long countByInstalledDistributionSet(long distributionSetId);
|
||||
|
||||
/**
|
||||
* Checks if there is already a {@link Target} that has the given
|
||||
* distribution set Id assigned or installed.
|
||||
*
|
||||
* @param distId to search for
|
||||
* @param distributionSetId to search for
|
||||
* @return <code>true</code> if a {@link Target} exists.
|
||||
* @throws EntityNotFoundException if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
boolean existsByInstalledOrAssignedDistributionSet(long distId);
|
||||
boolean existsByInstalledOrAssignedDistributionSet(long distributionSetId);
|
||||
|
||||
/**
|
||||
* Count {@link TargetFilterQuery}s for given target filter query.
|
||||
@@ -131,13 +131,13 @@ public interface TargetManagement {
|
||||
*
|
||||
* @param rsqlParam
|
||||
* filter definition in RSQL syntax
|
||||
* @param dsTypeId
|
||||
* @param distributionSetId
|
||||
* ID of the {@link DistributionSetType} the targets need to be
|
||||
* compatible with
|
||||
* @return the found number of{@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByRsqlAndCompatible(@NotEmpty String rsqlParam, @NotNull Long dsTypeId);
|
||||
long countByRsqlAndCompatible(@NotEmpty String rsqlParam, @NotNull Long distributionSetId);
|
||||
|
||||
/**
|
||||
* Count all targets with failed actions for specific Rollout
|
||||
@@ -214,31 +214,31 @@ public interface TargetManagement {
|
||||
/**
|
||||
* Deletes all targets with the given IDs.
|
||||
*
|
||||
* @param targetIDs
|
||||
* @param ids
|
||||
* the IDs of the targets to be deleted
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if (at least one) of the given target IDs does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET)
|
||||
void delete(@NotEmpty Collection<Long> targetIDs);
|
||||
void delete(@NotEmpty Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* Deletes target with the given controller ID.
|
||||
*
|
||||
* @param controllerID
|
||||
* @param controllerId
|
||||
* the controller ID of the target to be deleted
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if target with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_DELETE_TARGET)
|
||||
void deleteByControllerID(@NotEmpty String controllerID);
|
||||
void deleteByControllerID(@NotEmpty String controllerId);
|
||||
|
||||
/**
|
||||
* Finds all targets for all the given parameter {@link TargetFilterQuery}
|
||||
* and that don't have the specified distribution set in their action
|
||||
* history and are compatible with the passed {@link DistributionSetType}.
|
||||
* Finds all targets for all the given parameter {@link TargetFilterQuery} and
|
||||
* that don't have the specified distribution set in their action history and
|
||||
* are compatible with the passed {@link DistributionSetType}.
|
||||
*
|
||||
* @param pageRequest
|
||||
* the pageRequest to enhance the query for paging and sorting
|
||||
@@ -251,9 +251,9 @@ public interface TargetManagement {
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Target> findByTargetFilterQueryAndNonDSAndCompatible(@NotNull Pageable pageRequest, long distributionSetId,
|
||||
@NotNull String rsqlParam);
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(@NotNull Pageable pageRequest,
|
||||
long distributionSetId, @NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
* Counts all targets for all the given parameter {@link TargetFilterQuery}
|
||||
@@ -269,8 +269,8 @@ public interface TargetManagement {
|
||||
* @throws EntityNotFoundException
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByRsqlAndNonDSAndCompatible(long distributionSetId, @NotNull String rsqlParam);
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
long countByRsqlAndNonDSAndCompatibleAndUpdatable(long distributionSetId, @NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
* Finds all targets for all the given parameter {@link TargetFilterQuery}
|
||||
@@ -285,11 +285,11 @@ public interface TargetManagement {
|
||||
* filter definition in RSQL syntax
|
||||
* @param distributionSetType
|
||||
* type of the {@link DistributionSet} the targets must be
|
||||
* compatible with
|
||||
* compatible withs
|
||||
* @return a page of the found {@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Target> findByTargetFilterQueryAndNotInRolloutGroupsAndCompatible(@NotNull Pageable pageRequest,
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
Slice<Target> findByTargetFilterQueryAndNotInRolloutGroupsAndCompatibleAndUpdatable(@NotNull Pageable pageRequest,
|
||||
@NotEmpty Collection<Long> groups, @NotNull String rsqlParam,
|
||||
@NotNull DistributionSetType distributionSetType);
|
||||
|
||||
@@ -320,13 +320,13 @@ public interface TargetManagement {
|
||||
* @param rsqlParam
|
||||
* filter definition in RSQL syntax
|
||||
* @param distributionSetType
|
||||
* type of the {@link DistributionSet} the targets must be
|
||||
* compatible with
|
||||
* type of the {@link DistributionSet} the targets must be compatible
|
||||
* with
|
||||
* @return count of the found {@link Target}s
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
long countByRsqlAndNotInRolloutGroupsAndCompatible(@NotEmpty Collection<Long> groups, @NotNull String rsqlParam,
|
||||
@NotNull DistributionSetType distributionSetType);
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(@NotEmpty Collection<Long> groups,
|
||||
@NotNull String rsqlParam, @NotNull DistributionSetType distributionSetType);
|
||||
|
||||
/**
|
||||
* Counts all targets with failed actions for specific Rollout
|
||||
@@ -363,7 +363,7 @@ public interface TargetManagement {
|
||||
*
|
||||
* @param pageReq
|
||||
* page parameter
|
||||
* @param distributionSetID
|
||||
* @param distributionSetId
|
||||
* the ID of the {@link DistributionSet}
|
||||
*
|
||||
*
|
||||
@@ -373,7 +373,7 @@ public interface TargetManagement {
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
|
||||
Page<Target> findByAssignedDistributionSet(@NotNull Pageable pageReq, long distributionSetID);
|
||||
Page<Target> findByAssignedDistributionSet(@NotNull Pageable pageReq, long distributionSetId);
|
||||
|
||||
/**
|
||||
* Retrieves {@link Target}s by the assigned {@link DistributionSet}
|
||||
@@ -381,7 +381,7 @@ public interface TargetManagement {
|
||||
*
|
||||
* @param pageReq
|
||||
* page parameter
|
||||
* @param distributionSetID
|
||||
* @param distributionSetId
|
||||
* the ID of the {@link DistributionSet}
|
||||
* @param rsqlParam
|
||||
* the specification to filter the result set
|
||||
@@ -396,7 +396,7 @@ public interface TargetManagement {
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
|
||||
Page<Target> findByAssignedDistributionSetAndRsql(@NotNull Pageable pageReq, long distributionSetID,
|
||||
Page<Target> findByAssignedDistributionSetAndRsql(@NotNull Pageable pageReq, long distributionSetId,
|
||||
@NotNull String rsqlParam);
|
||||
|
||||
/**
|
||||
@@ -442,7 +442,7 @@ public interface TargetManagement {
|
||||
*
|
||||
* @param pageReq
|
||||
* page parameter
|
||||
* @param distributionSetID
|
||||
* @param distributionSetId
|
||||
* the ID of the {@link DistributionSet}
|
||||
*
|
||||
* @return the found {@link Target}s
|
||||
@@ -451,7 +451,7 @@ public interface TargetManagement {
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_READ_TARGET)
|
||||
Page<Target> findByInstalledDistributionSet(@NotNull Pageable pageReq, long distributionSetID);
|
||||
Page<Target> findByInstalledDistributionSet(@NotNull Pageable pageReq, long distributionSetId);
|
||||
|
||||
/**
|
||||
* retrieves {@link Target}s by the installed {@link DistributionSet}
|
||||
@@ -557,7 +557,7 @@ public interface TargetManagement {
|
||||
*
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param orderByDistributionId
|
||||
* @param orderByDistributionSetId
|
||||
* {@link DistributionSet#getId()} to be ordered by
|
||||
* @param filterParams
|
||||
* the filters to apply; only filters are enabled that have non-null
|
||||
@@ -569,7 +569,7 @@ public interface TargetManagement {
|
||||
* if distribution set with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
|
||||
Slice<Target> findByFilterOrderByLinkedDistributionSet(@NotNull Pageable pageable, long orderByDistributionId,
|
||||
Slice<Target> findByFilterOrderByLinkedDistributionSet(@NotNull Pageable pageable, long orderByDistributionSetId,
|
||||
@NotNull FilterParams filterParams);
|
||||
|
||||
/**
|
||||
@@ -656,12 +656,12 @@ public interface TargetManagement {
|
||||
* assignment outcome.
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
TargetTypeAssignmentResult unAssignType(@NotEmpty Collection<String> controllerIds);
|
||||
TargetTypeAssignmentResult unassignType(@NotEmpty Collection<String> controllerIds);
|
||||
|
||||
/**
|
||||
* Un-assign a {@link TargetTag} assignment to given {@link Target}.
|
||||
*
|
||||
* @param controllerID
|
||||
* @param controllerId
|
||||
* to un-assign for
|
||||
* @param targetTagId
|
||||
* to un-assign
|
||||
@@ -671,23 +671,23 @@ public interface TargetManagement {
|
||||
* if TAG with given ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
Target unAssignTag(@NotEmpty String controllerID, long targetTagId);
|
||||
Target unassignTag(@NotEmpty String controllerId, long targetTagId);
|
||||
|
||||
/**
|
||||
* Un-assign a {@link TargetType} assignment to given {@link Target}.
|
||||
*
|
||||
* @param controllerID
|
||||
* @param controllerId
|
||||
* to un-assign for
|
||||
* @return the unassigned target
|
||||
*
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
Target unAssignType(@NotEmpty String controllerID);
|
||||
Target unassignType(@NotEmpty String controllerId);
|
||||
|
||||
/**
|
||||
* Assign a {@link TargetType} assignment to given {@link Target}.
|
||||
*
|
||||
* @param controllerID
|
||||
* @param controllerId
|
||||
* to un-assign for
|
||||
* @param targetTypeId
|
||||
* Target type id
|
||||
@@ -697,7 +697,7 @@ public interface TargetManagement {
|
||||
* if TargetType with given target ID does not exist
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET)
|
||||
Target assignType(@NotEmpty String controllerID, @NotNull Long targetTypeId);
|
||||
Target assignType(@NotEmpty String controllerId, @NotNull Long targetTypeId);
|
||||
|
||||
/**
|
||||
* updates the {@link Target}.
|
||||
@@ -940,5 +940,4 @@ public interface TargetManagement {
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
|
||||
TargetMetadata updateMetadata(@NotEmpty String controllerId, @NotNull MetaData metadata);
|
||||
|
||||
}
|
||||
|
||||
@@ -164,24 +164,23 @@ public interface TargetTypeManagement {
|
||||
TargetType update(@NotNull @Valid TargetTypeUpdate update);
|
||||
|
||||
/**
|
||||
* @param targetTypeId
|
||||
* @param id
|
||||
* Target type ID
|
||||
* @param distributionSetTypeIds
|
||||
* Distribution set ID
|
||||
* @return Target type
|
||||
*/
|
||||
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||
TargetType assignCompatibleDistributionSetTypes(long targetTypeId,
|
||||
TargetType assignCompatibleDistributionSetTypes(long id,
|
||||
@NotEmpty Collection<Long> distributionSetTypeIds);
|
||||
|
||||
/**
|
||||
* @param targetTypeId
|
||||
* @param id
|
||||
* Target type ID
|
||||
* @param distributionSetTypeIds
|
||||
* Distribution set ID
|
||||
* @return Target type
|
||||
*/
|
||||
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY_AND_UPDATE_TARGET)
|
||||
TargetType unassignDistributionSetType(long targetTypeId, long distributionSetTypeIds);
|
||||
|
||||
TargetType unassignDistributionSetType(long id, long distributionSetTypeIds);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,11 @@ public class InsufficientPermissionException extends AbstractServerRtException {
|
||||
/**
|
||||
* creates new InsufficientPermissionException.
|
||||
*/
|
||||
public InsufficientPermissionException(final String message) {
|
||||
super(message, SpServerError.SP_INSUFFICIENT_PERMISSION);
|
||||
}
|
||||
|
||||
public InsufficientPermissionException() {
|
||||
this(null);
|
||||
super(SpServerError.SP_INSUFFICIENT_PERMISSION, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,11 @@ public interface Rollout extends NamedEntity {
|
||||
*/
|
||||
Optional<Integer> getWeight();
|
||||
|
||||
/**
|
||||
* @return the stored access control context (if present)
|
||||
*/
|
||||
Optional<String> getAccessControlContext();
|
||||
|
||||
/**
|
||||
*
|
||||
* State machine for rollout.
|
||||
|
||||
@@ -73,8 +73,7 @@ public interface TargetFilterQuery extends TenantAwareBaseEntity {
|
||||
ActionType getAutoAssignActionType();
|
||||
|
||||
/**
|
||||
* @return the weight of the {@link Action}s created during an auto
|
||||
* assignment.
|
||||
* @return the weight of the {@link Action}s created during an auto assignment.
|
||||
*/
|
||||
Optional<Integer> getAutoAssignWeight();
|
||||
|
||||
@@ -88,4 +87,10 @@ public interface TargetFilterQuery extends TenantAwareBaseEntity {
|
||||
* (considered with confirmation flow active)
|
||||
*/
|
||||
boolean isConfirmationRequired();
|
||||
|
||||
/**
|
||||
* Defining a serialized access control context which needs to be set when
|
||||
* performing the auto-assignment by the scheduler
|
||||
*/
|
||||
Optional<String> getAccessControlContext();
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Command repository operations for all {@link TenantAwareBaseEntity}s.
|
||||
*
|
||||
* @param <T>
|
||||
* type if the entity type
|
||||
* @param <I>
|
||||
* of the entity type
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
@Transactional(readOnly = true)
|
||||
public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity, I extends Serializable>
|
||||
extends PagingAndSortingRepository<T, I>, CrudRepository<T, I>, NoCountSliceRepository<T> {
|
||||
|
||||
/**
|
||||
* Retrieves an {@link BaseEntity} by its id.
|
||||
*
|
||||
* @param id
|
||||
* to search for
|
||||
* @return {@link BaseEntity}
|
||||
*/
|
||||
Optional<T> findById(I id);
|
||||
|
||||
/**
|
||||
* Overrides
|
||||
* {@link org.springframework.data.repository.CrudRepository#saveAll(Iterable)}
|
||||
* to return a list of created entities instead of an instance of
|
||||
* {@link Iterable} to be able to work with it directly in further code
|
||||
* processing instead of converting the {@link Iterable}.
|
||||
*
|
||||
* @param entities
|
||||
* to persist in the database
|
||||
* @return the created entities
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
<S extends T> List<S> saveAll(Iterable<S> entities);
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSystemManagement;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -11,10 +11,12 @@ package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.NoCountSliceRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
@@ -33,6 +35,11 @@ public final class JpaManagementHelper {
|
||||
private JpaManagementHelper() {
|
||||
}
|
||||
|
||||
public static <T, J extends T> Optional<J> findOneBySpec(final JpaSpecificationExecutor<J> repository,
|
||||
final List<Specification<J>> specList) {
|
||||
return repository.findOne(combineWithAnd(specList));
|
||||
}
|
||||
|
||||
public static <T, J extends T> Page<T> findAllWithCountBySpec(final JpaSpecificationExecutor<J> repository,
|
||||
final Pageable pageable, final List<Specification<J>> specList) {
|
||||
if (CollectionUtils.isEmpty(specList)) {
|
||||
@@ -46,7 +53,7 @@ public final class JpaManagementHelper {
|
||||
return new PageImpl<>(Collections.unmodifiableList(jpaAll.getContent()), pageable, jpaAll.getTotalElements());
|
||||
}
|
||||
|
||||
private static <J> Specification<J> combineWithAnd(final List<Specification<J>> specList) {
|
||||
public static <J> Specification<J> combineWithAnd(final List<Specification<J>> specList) {
|
||||
return specList.size() == 1 ? specList.get(0) : SpecificationsBuilder.combineWithAnd(specList);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,10 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.EvaluatorNotConfiguredException;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupEvaluationManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
@@ -529,8 +533,8 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
||||
if (!RolloutHelper.isRolloutRetried(rollout.getTargetFilterQuery())) {
|
||||
targetsInGroupFilter = DeploymentHelper.runInNewTransaction(txManager,
|
||||
"countAllTargetsByTargetFilterQueryAndNotInRolloutGroups",
|
||||
count -> targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatible(readyGroups, groupTargetFilter,
|
||||
rollout.getDistributionSet().getType()));
|
||||
count -> targetManagement.countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(readyGroups,
|
||||
groupTargetFilter, rollout.getDistributionSet().getType()));
|
||||
} else {
|
||||
targetsInGroupFilter = DeploymentHelper.runInNewTransaction(txManager,
|
||||
"countByFailedRolloutAndNotInRolloutGroupsAndCompatible",
|
||||
@@ -582,7 +586,7 @@ public class JpaRolloutExecutor implements RolloutExecutor {
|
||||
RolloutGroupStatus.READY, group);
|
||||
Slice<Target> targets;
|
||||
if (!RolloutHelper.isRolloutRetried(rollout.getTargetFilterQuery())) {
|
||||
targets = targetManagement.findByTargetFilterQueryAndNotInRolloutGroupsAndCompatible(
|
||||
targets = targetManagement.findByTargetFilterQueryAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
pageRequest, readyGroups, targetFilter, rollout.getDistributionSet().getType());
|
||||
} else {
|
||||
targets = targetManagement.findByFailedRolloutAndNotInRolloutGroups(
|
||||
|
||||
@@ -10,14 +10,13 @@
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.RolloutExecutor;
|
||||
import org.eclipse.hawkbit.repository.RolloutHandler;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -35,6 +34,7 @@ public class JpaRolloutHandler implements RolloutHandler {
|
||||
private final RolloutExecutor rolloutExecutor;
|
||||
private final LockRegistry lockRegistry;
|
||||
private final PlatformTransactionManager txManager;
|
||||
private final ContextAware contextAware;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -52,12 +52,14 @@ public class JpaRolloutHandler implements RolloutHandler {
|
||||
*/
|
||||
public JpaRolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
|
||||
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
|
||||
final PlatformTransactionManager txManager) {
|
||||
final PlatformTransactionManager txManager,
|
||||
final ContextAware contextAware) {
|
||||
this.tenantAware = tenantAware;
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.rolloutExecutor = rolloutExecutor;
|
||||
this.lockRegistry = lockRegistry;
|
||||
this.txManager = txManager;
|
||||
this.contextAware = contextAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,19 +94,29 @@ public class JpaRolloutHandler implements RolloutHandler {
|
||||
return tenant + "-rollout";
|
||||
}
|
||||
|
||||
// run in a tenant context, i.e. contextAware.getCurrentTenant() returns the tenant
|
||||
// the rollout is made for
|
||||
private void handleRolloutInNewTransaction(final long rolloutId, final String handlerId) {
|
||||
DeploymentHelper.runInNewTransaction(txManager, handlerId + "-" + rolloutId, status -> {
|
||||
rolloutManagement.get(rolloutId).ifPresentOrElse(
|
||||
rollout -> runInUserContext(rollout, () -> rolloutExecutor.execute(rollout)),
|
||||
rollout -> {
|
||||
rollout.getAccessControlContext().ifPresentOrElse(
|
||||
context -> // has stored context - executes it with it
|
||||
contextAware.runInContext(
|
||||
context,
|
||||
() -> rolloutExecutor.execute(rollout)),
|
||||
() -> // has no stored context - executes it in the tenant & user scope
|
||||
contextAware.runAsTenantAsUser(
|
||||
contextAware.getCurrentTenant(),
|
||||
rollout.getCreatedBy(), () -> {
|
||||
rolloutExecutor.execute(rollout);
|
||||
return null;
|
||||
})
|
||||
);
|
||||
},
|
||||
() -> LOGGER.error("Could not retrieve rollout with id {}. Will not continue with execution.",
|
||||
rolloutId));
|
||||
return 0L;
|
||||
});
|
||||
}
|
||||
|
||||
private void runInUserContext(final BaseEntity rollout, final Runnable handler) {
|
||||
DeploymentHelper.runInNonSystemContext(handler, () -> Objects.requireNonNull(rollout.getCreatedBy()),
|
||||
tenantAware);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import org.eclipse.hawkbit.repository.BaseRepositoryTypeProvider;
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link BaseRepositoryTypeProvider} leveraging our
|
||||
* {@link SimpleJpaWithNoCountRepository} for all current use cases
|
||||
*/
|
||||
public class NoCountBaseRepositoryTypeProvider implements BaseRepositoryTypeProvider {
|
||||
|
||||
@Override
|
||||
public Class<?> getBaseRepositoryType(final Class<?> repositoryType) {
|
||||
return SimpleJpaWithNoCountRepository.class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import javax.persistence.EntityManager;
|
||||
import javax.sql.DataSource;
|
||||
import javax.validation.Validation;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.artifact.repository.ArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.ArtifactEncryption;
|
||||
import org.eclipse.hawkbit.repository.ArtifactEncryptionSecretsStore;
|
||||
@@ -62,6 +63,7 @@ import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
|
||||
import org.eclipse.hawkbit.repository.event.remote.EventEntityManager;
|
||||
import org.eclipse.hawkbit.repository.event.remote.EventEntityManagerHolder;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler;
|
||||
import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignChecker;
|
||||
import org.eclipse.hawkbit.repository.jpa.autoassign.AutoAssignScheduler;
|
||||
@@ -80,10 +82,55 @@ import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactio
|
||||
import org.eclipse.hawkbit.repository.jpa.event.JpaEventEntityManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitDefaultServiceExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaConfirmationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetInvalidationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaDistributionSetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaRolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaRolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSoftwareModuleTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaSystemManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTargetTypeManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.management.JpaTenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutTargetGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.HawkBitBaseRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.RolloutScheduler;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.PauseRolloutGroupAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.RolloutGroupActionEvaluator;
|
||||
@@ -116,7 +163,10 @@ import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
import org.hibernate.validator.BaseHibernateValidatorConfiguration;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -135,6 +185,7 @@ import org.springframework.data.domain.AuditorAware;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.integration.support.locks.LockRegistry;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
|
||||
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
|
||||
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
|
||||
@@ -152,7 +203,7 @@ import com.google.common.collect.Maps;
|
||||
* General configuration for hawkBit's Repository.
|
||||
*
|
||||
*/
|
||||
@EnableJpaRepositories(value = "org.eclipse.hawkbit.repository.jpa", repositoryFactoryBeanClass = CustomBaseRepositoryFactoryBean.class)
|
||||
@EnableJpaRepositories(value = "org.eclipse.hawkbit.repository.jpa.repository", repositoryFactoryBeanClass = CustomBaseRepositoryFactoryBean.class)
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaAuditing
|
||||
@EnableAspectJAutoProxy
|
||||
@@ -174,7 +225,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
PauseRolloutGroupAction pauseRolloutGroupAction(final RolloutManagement rolloutManagement,
|
||||
final RolloutGroupRepository rolloutGroupRepository, final SystemSecurityContext systemSecurityContext) {
|
||||
final RolloutGroupRepository rolloutGroupRepository, final SystemSecurityContext systemSecurityContext) {
|
||||
return new PauseRolloutGroupAction(rolloutManagement, rolloutGroupRepository, systemSecurityContext);
|
||||
}
|
||||
|
||||
@@ -266,8 +317,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* @param dsTypeManagement
|
||||
* for loading
|
||||
* {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||
* for loading {@link TargetType#getCompatibleDistributionSetTypes()}
|
||||
* @return TargetTypeBuilder bean
|
||||
*/
|
||||
@Bean
|
||||
@@ -282,10 +332,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareManagement
|
||||
* for loading
|
||||
* {@link DistributionSetType#getMandatoryModuleTypes()} and
|
||||
* {@link DistributionSetType#getOptionalModuleTypes()}
|
||||
* @param softwareModuleTypeManagement
|
||||
* for loading {@link DistributionSetType#getMandatoryModuleTypes()}
|
||||
* and {@link DistributionSetType#getOptionalModuleTypes()}
|
||||
* @return DistributionSetTypeBuilder bean
|
||||
*/
|
||||
@Bean
|
||||
@@ -327,8 +376,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* @return the {@link SystemSecurityContext} singleton bean which make it
|
||||
* accessible in beans which cannot access the service directly,
|
||||
* e.g. JPA entities.
|
||||
* accessible in beans which cannot access the service directly, e.g.
|
||||
* JPA entities.
|
||||
*/
|
||||
@Bean
|
||||
SystemSecurityContextHolder systemSecurityContextHolder() {
|
||||
@@ -336,9 +385,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TenantConfigurationManagement} singleton bean which
|
||||
* make it accessible in beans which cannot access the service
|
||||
* directly, e.g. JPA entities.
|
||||
* @return the {@link TenantConfigurationManagement} singleton bean which make
|
||||
* it accessible in beans which cannot access the service directly, e.g.
|
||||
* JPA entities.
|
||||
*/
|
||||
@Bean
|
||||
TenantConfigurationManagementHolder tenantConfigurationManagementHolder() {
|
||||
@@ -347,9 +396,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* @return the {@link SystemManagementHolder} singleton bean which holds the
|
||||
* current {@link SystemManagement} service and make it accessible
|
||||
* in beans which cannot access the service directly, e.g. JPA
|
||||
* entities.
|
||||
* current {@link SystemManagement} service and make it accessible in
|
||||
* beans which cannot access the service directly, e.g. JPA entities.
|
||||
*/
|
||||
@Bean
|
||||
SystemManagementHolder systemManagementHolder() {
|
||||
@@ -357,10 +405,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link TenantAwareHolder} singleton bean which holds the
|
||||
* current {@link TenantAware} service and make it accessible in
|
||||
* beans which cannot access the service directly, e.g. JPA
|
||||
* entities.
|
||||
* @return the {@link TenantAwareHolder} singleton bean which holds the current
|
||||
* {@link TenantAware} service and make it accessible in beans which
|
||||
* cannot access the service directly, e.g. JPA entities.
|
||||
*/
|
||||
@Bean
|
||||
TenantAwareHolder tenantAwareHolder() {
|
||||
@@ -368,10 +415,9 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SecurityTokenGeneratorHolder} singleton bean which
|
||||
* holds the current {@link SecurityTokenGenerator} service and make
|
||||
* it accessible in beans which cannot access the service via
|
||||
* injection
|
||||
* @return the {@link SecurityTokenGeneratorHolder} singleton bean which holds
|
||||
* the current {@link SecurityTokenGenerator} service and make it
|
||||
* accessible in beans which cannot access the service via injection
|
||||
*/
|
||||
@Bean
|
||||
SecurityTokenGeneratorHolder securityTokenGeneratorHolder() {
|
||||
@@ -404,6 +450,8 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
public MethodValidationPostProcessor methodValidationPostProcessor() {
|
||||
final MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
|
||||
// ValidatorFactory shall NOT be closed because after closing the generated Validator
|
||||
// methods shall not be called - we need the validator in future
|
||||
processor.setValidator(Validation.byDefaultProvider().configure()
|
||||
.addProperty(BaseHibernateValidatorConfiguration.ALLOW_PARALLEL_METHODS_DEFINE_PARAMETER_CONSTRAINTS,
|
||||
"true")
|
||||
@@ -485,19 +533,21 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DistributionSetManagement distributionSetManagement(final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetTagManagement distributionSetTagManagement, final SystemManagement systemManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final QuotaManagement quotaManagement,
|
||||
final DistributionSetMetadataRepository distributionSetMetadataRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
|
||||
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final DistributionSetTagRepository distributionSetTagRepository,
|
||||
final AfterTransactionCommitExecutor afterCommit, final JpaProperties properties) {
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetTagManagement distributionSetTagManagement, final SystemManagement systemManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final QuotaManagement quotaManagement,
|
||||
final DistributionSetMetadataRepository distributionSetMetadataRepository,
|
||||
final TargetRepository targetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
|
||||
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final DistributionSetTagRepository distributionSetTagRepository,
|
||||
final AfterTransactionCommitExecutor afterCommit,
|
||||
final JpaProperties properties) {
|
||||
return new JpaDistributionSetManagement(entityManager, distributionSetRepository, distributionSetTagManagement,
|
||||
systemManagement, distributionSetTypeManagement, quotaManagement, distributionSetMetadataRepository,
|
||||
targetFilterQueryRepository, actionRepository, eventPublisherHolder, tenantAware,
|
||||
targetRepository, targetFilterQueryRepository, actionRepository, eventPublisherHolder, tenantAware,
|
||||
virtualPropertyReplacer, softwareModuleRepository, distributionSetTagRepository, afterCommit,
|
||||
properties.getDatabase());
|
||||
|
||||
@@ -566,16 +616,16 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
TargetManagement targetManagement(final EntityManager entityManager, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
|
||||
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
||||
final AfterTransactionCommitExecutor afterCommit, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final JpaProperties properties, final DistributionSetManagement distributionSetManagement) {
|
||||
final TargetRepository targetRepository, final TargetMetadataRepository targetMetadataRepository,
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetTypeRepository targetTypeRepository, final TargetTagRepository targetTagRepository,
|
||||
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final JpaProperties properties, final DistributionSetManagement distributionSetManagement) {
|
||||
return new JpaTargetManagement(entityManager, distributionSetManagement, quotaManagement, targetRepository,
|
||||
targetTypeRepository, targetMetadataRepository, rolloutGroupRepository, targetFilterQueryRepository,
|
||||
targetTagRepository, eventPublisherHolder, tenantAware, afterCommit, virtualPropertyReplacer,
|
||||
targetTagRepository, eventPublisherHolder, tenantAware, virtualPropertyReplacer,
|
||||
properties.getDatabase());
|
||||
}
|
||||
|
||||
@@ -594,8 +644,6 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
* to access quotas
|
||||
* @param properties
|
||||
* JPA properties
|
||||
* @param tenantAware
|
||||
* the {@link TenantAware} bean holding the tenant information
|
||||
*
|
||||
* @return a new {@link TargetFilterQueryManagement}
|
||||
*/
|
||||
@@ -606,12 +654,13 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final JpaProperties properties, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware) {
|
||||
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware) {
|
||||
return new JpaTargetFilterQueryManagement(targetFilterQueryRepository, targetManagement,
|
||||
virtualPropertyReplacer, distributionSetManagement, quotaManagement, properties.getDatabase(),
|
||||
tenantConfigurationManagement, systemSecurityContext, tenantAware);
|
||||
tenantConfigurationManagement, systemSecurityContext, contextAware);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link JpaTargetTagManagement} bean.
|
||||
*
|
||||
@@ -654,10 +703,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
|
||||
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties) {
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final JpaProperties properties) {
|
||||
return new JpaSoftwareModuleManagement(entityManager, distributionSetRepository, softwareModuleRepository,
|
||||
softwareModuleMetadataRepository, softwareModuleTypeRepository, auditorProvider, artifactManagement,
|
||||
quotaManagement, virtualPropertyReplacer, properties.getDatabase());
|
||||
quotaManagement, virtualPropertyReplacer,
|
||||
properties.getDatabase());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -671,17 +722,20 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final JpaProperties properties) {
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final JpaProperties properties) {
|
||||
return new JpaSoftwareModuleTypeManagement(distributionSetTypeRepository, softwareModuleTypeRepository,
|
||||
virtualPropertyReplacer, softwareModuleRepository, properties.getDatabase());
|
||||
virtualPropertyReplacer, softwareModuleRepository,
|
||||
properties.getDatabase());
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RolloutHandler rolloutHandler(final TenantAware tenantAware, final RolloutManagement rolloutManagement,
|
||||
final RolloutExecutor rolloutExecutor, final LockRegistry lockRegistry,
|
||||
final PlatformTransactionManager txManager) {
|
||||
return new JpaRolloutHandler(tenantAware, rolloutManagement, rolloutExecutor, lockRegistry, txManager);
|
||||
final PlatformTransactionManager txManager, final ContextAware contextAware) {
|
||||
return new JpaRolloutHandler(tenantAware, rolloutManagement, rolloutExecutor, lockRegistry, txManager,
|
||||
contextAware);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -708,10 +762,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final JpaProperties properties,
|
||||
final RolloutApprovalStrategy rolloutApprovalStrategy,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
final SystemSecurityContext systemSecurityContext,
|
||||
final ContextAware contextAware) {
|
||||
return new JpaRolloutManagement(targetManagement, distributionSetManagement, eventPublisherHolder,
|
||||
virtualPropertyReplacer, properties.getDatabase(), rolloutApprovalStrategy,
|
||||
tenantConfigurationManagement, systemSecurityContext);
|
||||
tenantConfigurationManagement, systemSecurityContext,
|
||||
contextAware);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -736,10 +792,10 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
RolloutGroupManagement rolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||
final TargetRepository targetRepository, final EntityManager entityManager,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
||||
final JpaProperties properties) {
|
||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||
final TargetRepository targetRepository, final EntityManager entityManager,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
||||
final JpaProperties properties) {
|
||||
return new JpaRolloutGroupManagement(rolloutGroupRepository, rolloutRepository, actionRepository,
|
||||
targetRepository, entityManager, virtualPropertyReplacer, rolloutStatusCache, properties.getDatabase());
|
||||
}
|
||||
@@ -752,14 +808,14 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
DeploymentManagement deploymentManagement(final EntityManager entityManager,
|
||||
final ActionRepository actionRepository, final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware,
|
||||
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
|
||||
final ActionRepository actionRepository, final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetManagement distributionSetManagement, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware,
|
||||
final JpaProperties properties, final RepositoryProperties repositoryProperties) {
|
||||
return new JpaDeploymentManagement(entityManager, actionRepository, distributionSetManagement,
|
||||
distributionSetRepository, targetRepository, actionStatusRepository, auditorProvider,
|
||||
eventPublisherHolder, afterCommit, virtualPropertyReplacer, txManager, tenantConfigurationManagement,
|
||||
@@ -792,10 +848,11 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ArtifactManagement artifactManagement(final LocalArtifactRepository localArtifactRepository,
|
||||
ArtifactManagement artifactManagement(
|
||||
final EntityManager entityManager, final LocalArtifactRepository localArtifactRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final ArtifactRepository artifactRepository,
|
||||
final QuotaManagement quotaManagement, final TenantAware tenantAware) {
|
||||
return new JpaArtifactManagement(localArtifactRepository, softwareModuleRepository, artifactRepository,
|
||||
return new JpaArtifactManagement(entityManager, localArtifactRepository, softwareModuleRepository, artifactRepository,
|
||||
quotaManagement, tenantAware);
|
||||
}
|
||||
|
||||
@@ -827,7 +884,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
* @param aware
|
||||
* the tenant aware
|
||||
* @param entityManager
|
||||
* the entitymanager
|
||||
* the entity manager
|
||||
* @return a new {@link EventEntityManager}
|
||||
*/
|
||||
@Bean
|
||||
@@ -853,24 +910,22 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@ConditionalOnMissingBean
|
||||
AutoAssignExecutor autoAssignExecutor(final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
|
||||
final PlatformTransactionManager transactionManager, final TenantAware tenantAware) {
|
||||
final PlatformTransactionManager transactionManager, final ContextAware contextAware) {
|
||||
return new AutoAssignChecker(targetFilterQueryManagement, targetManagement, deploymentManagement,
|
||||
transactionManager, tenantAware);
|
||||
transactionManager, contextAware);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AutoAssignScheduler} bean.
|
||||
*
|
||||
* <p/>
|
||||
* Note: does not activate in test profile, otherwise it is hard to test the
|
||||
* auto assign functionality.
|
||||
*
|
||||
* @param tenantAware
|
||||
* to run as specific tenant
|
||||
* @param systemManagement
|
||||
* to find all tenants
|
||||
* @param systemSecurityContext
|
||||
* to run as system
|
||||
* @param autoAssignChecker
|
||||
* @param autoAssignExecutor
|
||||
* to run a check as tenant
|
||||
* @param lockRegistry
|
||||
* to lock the tenant for auto assignment
|
||||
@@ -930,7 +985,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* {@link RolloutScheduler} bean.
|
||||
*
|
||||
* <p/>
|
||||
* Note: does not activate in test profile, otherwise it is hard to test the
|
||||
* rollout handling functionality.
|
||||
*
|
||||
@@ -946,7 +1001,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@ConditionalOnMissingBean
|
||||
@Profile("!test")
|
||||
@ConditionalOnProperty(prefix = "hawkbit.rollout.scheduler", name = "enabled", matchIfMissing = true)
|
||||
RolloutScheduler rolloutScheduler(final TenantAware tenantAware, final SystemManagement systemManagement,
|
||||
RolloutScheduler rolloutScheduler(final SystemManagement systemManagement,
|
||||
final RolloutHandler rolloutHandler, final SystemSecurityContext systemSecurityContext) {
|
||||
return new RolloutScheduler(systemManagement, rolloutHandler, systemSecurityContext);
|
||||
}
|
||||
@@ -982,16 +1037,18 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
JpaDistributionSetInvalidationManagement distributionSetInvalidationManagement(
|
||||
final DistributionSetManagement distributionSetManagement, final RolloutManagement rolloutManagement,
|
||||
final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final PlatformTransactionManager txManager,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final ActionRepository actionRepository,
|
||||
final PlatformTransactionManager txManager,
|
||||
final RepositoryProperties repositoryProperties, final TenantAware tenantAware,
|
||||
final LockRegistry lockRegistry) {
|
||||
return new JpaDistributionSetInvalidationManagement(distributionSetManagement, rolloutManagement,
|
||||
deploymentManagement, targetFilterQueryManagement, txManager, repositoryProperties, tenantAware,
|
||||
deploymentManagement, targetFilterQueryManagement, actionRepository,
|
||||
txManager, repositoryProperties, tenantAware,
|
||||
lockRegistry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Our default {@link BaseRepositoryTypeProvider} bean always provides the
|
||||
* Default {@link BaseRepositoryTypeProvider} bean always provides the
|
||||
* NoCountBaseRepository
|
||||
*
|
||||
* @return a {@link BaseRepositoryTypeProvider} bean
|
||||
@@ -999,14 +1056,13 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
BaseRepositoryTypeProvider baseRepositoryTypeProvider() {
|
||||
return new NoCountBaseRepositoryTypeProvider();
|
||||
|
||||
return new HawkBitBaseRepository.RepositoryTypeProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default artifact encryption service bean that internally uses
|
||||
* {@link ArtifactEncryption} and {@link ArtifactEncryptionSecretsStore}
|
||||
* beans for {@link SoftwareModule} artifacts encryption/decryption
|
||||
* {@link ArtifactEncryption} and {@link ArtifactEncryptionSecretsStore} beans
|
||||
* for {@link SoftwareModule} artifacts encryption/decryption
|
||||
*
|
||||
* @return a {@link ArtifactEncryptionService} bean
|
||||
*/
|
||||
@@ -1015,4 +1071,36 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
ArtifactEncryptionService artifactEncryptionService() {
|
||||
return ArtifactEncryptionService.getInstance();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BeanPostProcessor entityManagerBeanPostProcessor(
|
||||
@Autowired(required = false) final AccessController<JpaArtifact> artifactAccessController,
|
||||
@Autowired(required = false) final AccessController<JpaSoftwareModuleType> softwareModuleTypeAccessController,
|
||||
@Autowired(required = false) final AccessController<JpaSoftwareModule> softwareModuleAccessController,
|
||||
@Autowired(required = false) final AccessController<JpaDistributionSetType> distributionSetTypeAccessController,
|
||||
@Autowired(required = false) final AccessController<JpaDistributionSet> distributionSetAccessController,
|
||||
@Autowired(required = false) final AccessController<JpaTargetType> targetTypeAccessControlManager,
|
||||
@Autowired(required = false) final AccessController<JpaTarget> targetAccessControlManager) {
|
||||
return new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName) throws BeansException {
|
||||
if (bean instanceof LocalArtifactRepository repo) {
|
||||
return repo.withACM(artifactAccessController);
|
||||
} else if (bean instanceof SoftwareModuleTypeRepository repo) {
|
||||
return repo.withACM(softwareModuleTypeAccessController);
|
||||
} else if (bean instanceof SoftwareModuleRepository repo) {
|
||||
return repo.withACM(softwareModuleAccessController);
|
||||
} else if (bean instanceof DistributionSetTypeRepository repo) {
|
||||
return repo.withACM(distributionSetTypeAccessController);
|
||||
} else if (bean instanceof DistributionSetRepository repo) {
|
||||
return repo.withACM(distributionSetAccessController);
|
||||
} else if (bean instanceof TargetTypeRepository repo) {
|
||||
return repo.withACM(targetTypeAccessControlManager);
|
||||
} else if (bean instanceof TargetRepository repo) {
|
||||
return repo.withACM(targetAccessControlManager);
|
||||
}
|
||||
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
|
||||
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Repository implementation that allows findAll with disabled count query.
|
||||
*
|
||||
* @param <T>
|
||||
* entity type
|
||||
* @param <I>
|
||||
* key or ID type
|
||||
*/
|
||||
public class SimpleJpaWithNoCountRepository<T, I extends Serializable> extends SimpleJpaRepository<T, I>
|
||||
implements NoCountSliceRepository<T> {
|
||||
|
||||
public SimpleJpaWithNoCountRepository(final Class<T> domainClass, final EntityManager em) {
|
||||
super(domainClass, em);
|
||||
}
|
||||
|
||||
public SimpleJpaWithNoCountRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
|
||||
super(entityInformation, entityManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<T> findAllWithoutCount(@Nullable Specification<T> spec, Pageable pageable) {
|
||||
TypedQuery<T> query = getQuery(spec, pageable);
|
||||
return pageable.isUnpaged() ? new PageImpl<>(query.getResultList()) : readPageWithoutCount(query, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<T> findAllWithoutCount(final Pageable pageable) {
|
||||
return findAllWithoutCount(null, pageable);
|
||||
}
|
||||
|
||||
protected <S extends T> Page<S> readPageWithoutCount(final TypedQuery<S> query, final Pageable pageable) {
|
||||
query.setFirstResult((int) pageable.getOffset());
|
||||
query.setMaxResults(pageable.getPageSize());
|
||||
|
||||
final List<S> content = query.getResultList();
|
||||
|
||||
return new PageImpl<>(content, pageable, content.size());
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link SoftwareModule} repository.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface SoftwareModuleRepository
|
||||
extends BaseEntityRepository<JpaSoftwareModule, Long>, JpaSpecificationExecutor<JpaSoftwareModule> {
|
||||
|
||||
/**
|
||||
* Counts all {@link SoftwareModule}s based on the given {@link Type}.
|
||||
*
|
||||
* @param type
|
||||
* to count for
|
||||
* @return number of {@link SoftwareModule}s
|
||||
*/
|
||||
Long countByType(JpaSoftwareModuleType type);
|
||||
|
||||
/**
|
||||
* Retrieves {@link SoftwareModule} by filtering on name AND version AND
|
||||
* type (which is unique per tenant.
|
||||
*
|
||||
* @param name
|
||||
* to be filtered on
|
||||
* @param version
|
||||
* to be filtered on
|
||||
* @param typeId
|
||||
* to be filtered on
|
||||
* @return the found {@link SoftwareModule} with the given name AND version
|
||||
* AND type
|
||||
*/
|
||||
Optional<SoftwareModule> findOneByNameAndVersionAndTypeId(String name, String version, Long typeId);
|
||||
|
||||
/**
|
||||
* deletes the {@link SoftwareModule}s with the given IDs.
|
||||
*
|
||||
* @param modifiedAt
|
||||
* current timestamp
|
||||
* @param modifiedBy
|
||||
* user name of current auditor
|
||||
* @param ids
|
||||
* to be deleted
|
||||
*
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE JpaSoftwareModule b SET b.deleted = 1, b.lastModifiedAt = :lastModifiedAt, b.lastModifiedBy = :lastModifiedBy WHERE b.id IN :ids")
|
||||
void deleteSoftwareModule(@Param("lastModifiedAt") Long modifiedAt, @Param("lastModifiedBy") String modifiedBy,
|
||||
@Param("ids") Long... ids);
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param setId
|
||||
* to search for
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet}.
|
||||
*/
|
||||
Page<SoftwareModule> findByAssignedToId(Pageable pageable, Long setId);
|
||||
|
||||
/**
|
||||
* Count the software modules which are assigned to the distribution set
|
||||
* with the given ID.
|
||||
*
|
||||
* @param setId
|
||||
* the distribution set ID
|
||||
*
|
||||
* @return the number of software modules matching the given distribution
|
||||
* set ID.
|
||||
*/
|
||||
long countByAssignedToId(Long setId);
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* the page request to page the result set
|
||||
* @param set
|
||||
* to search for
|
||||
* @param type
|
||||
* to filter
|
||||
* @return all {@link SoftwareModule}s that are assigned to given
|
||||
* {@link DistributionSet} filtered by {@link SoftwareModuleType}.
|
||||
*/
|
||||
Page<SoftwareModule> findByAssignedToAndType(Pageable pageable, JpaDistributionSet set, SoftwareModuleType type);
|
||||
|
||||
/**
|
||||
* retrieves all software modules with a given
|
||||
* {@link SoftwareModule#getId()}.
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
* @return {@link List} of found {@link SoftwareModule}s
|
||||
*/
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT sm FROM JpaSoftwareModule sm WHERE sm.id IN ?1")
|
||||
List<JpaSoftwareModule> findByIdIn(Iterable<Long> ids);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
* manually to query even if this will by done by {@link EntityManager}
|
||||
* anyhow. The DB should take care of optimizing this away.
|
||||
*
|
||||
* @param tenant
|
||||
* to delete data from
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaSoftwareModule t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link Target} repository.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetRepository extends BaseEntityRepository<JpaTarget, Long>, JpaSpecificationExecutor<JpaTarget> {
|
||||
/**
|
||||
* Sets {@link JpaTarget#getAssignedDistributionSet()}.
|
||||
*
|
||||
* @param set
|
||||
* to use
|
||||
* @param status
|
||||
* to set
|
||||
* @param modifiedAt
|
||||
* current time
|
||||
* @param modifiedBy
|
||||
* current auditor
|
||||
* @param targets
|
||||
* to update
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE JpaTarget t SET t.assignedDistributionSet = :set, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy, t.updateStatus = :status WHERE t.id IN :targets")
|
||||
void setAssignedDistributionSetAndUpdateStatus(@Param("status") TargetUpdateStatus status,
|
||||
@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
|
||||
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
|
||||
|
||||
/**
|
||||
* Sets {@link JpaTarget#getAssignedDistributionSet()},
|
||||
* {@link JpaTarget#getInstalledDistributionSet()} and
|
||||
* {@link JpaTarget#getInstallationDate()}
|
||||
*
|
||||
* @param set
|
||||
* to use
|
||||
* @param status
|
||||
* to set
|
||||
* @param modifiedAt
|
||||
* current time
|
||||
* @param modifiedBy
|
||||
* current auditor
|
||||
* @param targets
|
||||
* to update
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE JpaTarget t SET t.assignedDistributionSet = :set, t.installedDistributionSet = :set, t.installationDate = :lastModifiedAt, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy, t.updateStatus = :status WHERE t.id IN :targets")
|
||||
void setAssignedAndInstalledDistributionSetAndUpdateStatus(@Param("status") TargetUpdateStatus status,
|
||||
@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
|
||||
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
|
||||
|
||||
/**
|
||||
* Deletes the {@link Target}s with the given target IDs.
|
||||
*
|
||||
* @param targetIDs
|
||||
* to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("DELETE FROM JpaTarget t WHERE t.id IN ?1")
|
||||
void deleteByIdIn(Collection<Long> targetIDs);
|
||||
|
||||
/**
|
||||
* Finds all {@link Target}s in the repository.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @return {@link List} of {@link Target}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default List<JpaTarget> findAll() {
|
||||
return this.findAll(Specification.where(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all {@link Target}s in the repository sorted.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @param sort instructions to sort result by
|
||||
* @return {@link List} of {@link Target}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Iterable<JpaTarget> findAll(@NonNull Sort sort) {
|
||||
return this.findAll(Specification.where(null), sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a page of {@link Target}s in the repository.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @param pageable paging context
|
||||
* @return {@link List} of {@link Target}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Page<JpaTarget> findAll(@NonNull Pageable pageable) {
|
||||
return this.findAll(Specification.where(null), pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds {@link Target}s in the repository matching a list of ids.
|
||||
*
|
||||
* Calls version based on spec to allow injecting further specs
|
||||
*
|
||||
* @param ids ids to filter for
|
||||
* @return {@link List} of {@link Target}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default List<JpaTarget> findAllById(Iterable<Long> ids) {
|
||||
final List<Long> collectedIds = StreamSupport.stream(ids.spliterator(), true).collect(Collectors.toList());
|
||||
return this.findAll(Specification.where(TargetSpecifications.hasIdIn(collectedIds)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds {@link Target} in the repository matching an id.
|
||||
*
|
||||
* Calls version based on spec to allow injecting further specs
|
||||
*
|
||||
* @param id id to filter for
|
||||
* @return {@link Optional} of {@link Target}
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Optional<JpaTarget> findById(@NonNull Long id) {
|
||||
return this.findOne(Specification.where(TargetSpecifications.hasId(id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether {@link Target} in the repository matching an id exists or not.
|
||||
*
|
||||
* Calls version based on spec to allow injecting further specs
|
||||
*
|
||||
* @param id id to check for
|
||||
* @return true if target with id exists
|
||||
*/
|
||||
@Override
|
||||
default boolean existsById(@NonNull Long id) {
|
||||
return this.exists(TargetSpecifications.hasId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether {@link Target} in the repository matching a spec exists or not.
|
||||
*
|
||||
* @param spec to check for existence
|
||||
* @return true if target with id exists
|
||||
*/
|
||||
default boolean exists(@NonNull Specification<JpaTarget> spec) {
|
||||
return this.count(spec) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count number of {@link Target}s in the repository.
|
||||
*
|
||||
* Calls version with an empty spec to allow injecting further specs
|
||||
*
|
||||
* @return number of targets in the repository
|
||||
*/
|
||||
@Override
|
||||
default long count() {
|
||||
return this.count(Specification.where(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts {@link Target} instances of given type in the repository.
|
||||
*
|
||||
* @param targetTypeId
|
||||
* to search for
|
||||
* @return number of found {@link Target}s
|
||||
*/
|
||||
long countByTargetTypeId(Long targetTypeId);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
* manually to query even if this will by done by {@link EntityManager} anyhow.
|
||||
* The DB should take care of optimizing this away.
|
||||
*
|
||||
* @param tenant
|
||||
* to delete data from
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTarget t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link PagingAndSortingRepository} and {@link org.springframework.data.repository.CrudRepository} for
|
||||
* {@link JpaTargetType}.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetTypeRepository
|
||||
extends BaseEntityRepository<JpaTargetType, Long>, JpaSpecificationExecutor<JpaTargetType> {
|
||||
|
||||
/**
|
||||
* Finds {@link TargetType} in the repository matching an id.
|
||||
*
|
||||
* Calls version based on spec to allow injecting further specs
|
||||
*
|
||||
* @param id
|
||||
* id to filter for
|
||||
* @return {@link Optional} of {@link TargetType}
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Optional<JpaTargetType> findById(@NonNull final Long id) {
|
||||
return this.findOne(Specification.where(TargetTypeSpecification.hasId(id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ids
|
||||
* List of ID
|
||||
* @return Target type list
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default List<JpaTargetType> findAllById(final Iterable<Long> ids) {
|
||||
final List<Long> collectedIds = StreamSupport.stream(ids.spliterator(), true).collect(Collectors.toList());
|
||||
return this.findAll(Specification.where(TargetTypeSpecification.hasIdIn(collectedIds)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the {@link TargetType}s with the given target IDs.
|
||||
*
|
||||
* @param targetTypeIDs
|
||||
* to be deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetType t WHERE t.id IN ?1")
|
||||
void deleteByIdIn(Collection<Long> targetTypeIDs);
|
||||
|
||||
/**
|
||||
* Finds all {@link TargetType}s in the repository.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @return {@link List} of {@link TargetType}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default List<JpaTargetType> findAll() {
|
||||
return this.findAll(Specification.where(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all {@link TargetType}s in the repository sorted.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @param sort
|
||||
* instructions to sort result by
|
||||
* @return {@link List} of {@link TargetType}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Iterable<JpaTargetType> findAll(@NonNull final Sort sort) {
|
||||
return this.findAll(Specification.where(null), sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a page of {@link TargetType}s in the repository.
|
||||
*
|
||||
* Calls version with (empty) spec to allow injecting further specs
|
||||
*
|
||||
* @param pageable
|
||||
* paging context
|
||||
* @return {@link List} of {@link TargetType}s
|
||||
*/
|
||||
@Override
|
||||
@NonNull
|
||||
default Page<JpaTargetType> findAll(@NonNull final Pageable pageable) {
|
||||
return this.findAll(Specification.where(null), pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether {@link TargetType} in the repository matching an id exists
|
||||
* or not.
|
||||
*
|
||||
* Calls version based on spec to allow injecting further specs
|
||||
*
|
||||
* @param id
|
||||
* id to check for
|
||||
* @return true if TargetType with id exists
|
||||
*/
|
||||
@Override
|
||||
default boolean existsById(@NonNull final Long id) {
|
||||
return this.exists(TargetTypeSpecification.hasId(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether {@link TargetType} in the repository matching a spec
|
||||
* exists or not.
|
||||
*
|
||||
* @param spec
|
||||
* to check for existence
|
||||
* @return true if target with id exists
|
||||
*/
|
||||
default boolean exists(@NonNull final Specification<JpaTargetType> spec) {
|
||||
return this.count(spec) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count number of {@link TargetType}s in the repository.
|
||||
*
|
||||
* Calls version with an empty spec to allow injecting further specs
|
||||
*
|
||||
* @return number of targetTypes in the repository
|
||||
*/
|
||||
@Override
|
||||
default long count() {
|
||||
return this.count(Specification.where(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tenant
|
||||
* Tenant
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetType t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
@Query(value = "SELECT COUNT (t.id) FROM JpaDistributionSetType t JOIN t.compatibleToTargetTypes tt WHERE tt.id = :id")
|
||||
long countDsSetTypesById(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dsTypeId
|
||||
* to search for
|
||||
* @return all {@link TargetType}s in the repository with given
|
||||
* {@link TargetType#getName()}
|
||||
*/
|
||||
default List<JpaTargetType> findByDsType(@Param("id") final Long dsTypeId) {
|
||||
return this.findAll(Specification.where(TargetTypeSpecification.hasDsSetType(dsTypeId)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* to search for
|
||||
* @return all {@link TargetType}s in the repository with given
|
||||
* {@link TargetType#getName()}
|
||||
*/
|
||||
default Optional<JpaTargetType> findByName(final String name) {
|
||||
return this.findOne(Specification.where(TargetTypeSpecification.hasName(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Count number of {@link TargetType}s in the repository by name.
|
||||
*
|
||||
* @param name
|
||||
* target type name
|
||||
* @return number of targetTypes in the repository by name
|
||||
*/
|
||||
default long countByName(final String name) {
|
||||
return this.count(TargetTypeSpecification.hasName(name));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.acm;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface of an extended access control by providing means or fine-grained access control.
|
||||
* Used by repository (and on few places by management) layer to verify the permission for CRUD operations
|
||||
* based on some access criteria.
|
||||
* <p/>
|
||||
* First the basic service based access control (hawkBit permissions) on the management layer is applied then
|
||||
* additional restrictions (e.g. entity based) could be applied.
|
||||
* <p/>
|
||||
* <b>Note</b>: Experimental, only
|
||||
*
|
||||
* @param <T> the domain type the repository manages
|
||||
*/
|
||||
public interface AccessController<T> {
|
||||
|
||||
/**
|
||||
* Introduce a new specification to limit the access to a specific entity.
|
||||
*
|
||||
* @return a new specification limiting the access, if empty no access restrictions
|
||||
* are to be applied
|
||||
*/
|
||||
Optional<Specification<T>> getAccessRules(Operation operation);
|
||||
|
||||
/**
|
||||
* Append the resource limitation on an already existing specification.
|
||||
*
|
||||
* @param specification
|
||||
* is the root specification which needs to be appended by the
|
||||
* resource limitation
|
||||
* @return a new appended specification
|
||||
*/
|
||||
@Nullable
|
||||
default Specification<T> appendAccessRules(final Operation operation, @Nullable final Specification<T> specification) {
|
||||
return getAccessRules(operation)
|
||||
.map(accessRules -> specification == null ? accessRules : specification.and(accessRules))
|
||||
.orElse(specification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the given {@link Operation} is permitted for the provided entity.
|
||||
*
|
||||
* @throws InsufficientPermissionException
|
||||
* if operation is not permitted for given entities
|
||||
*/
|
||||
void assertOperationAllowed(final Operation operation, final T entity) throws InsufficientPermissionException;
|
||||
|
||||
/**
|
||||
* Verify if the given {@link Operation} is permitted for the provided entities.
|
||||
*
|
||||
* @throws InsufficientPermissionException
|
||||
* if operation is not permitted for given entities
|
||||
*/
|
||||
default void assertOperationAllowed(final Operation operation, final Iterable<? extends T> entities) throws InsufficientPermissionException {
|
||||
for (final T entity : entities) {
|
||||
assertOperationAllowed(operation, entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enum to define the perform operation to verify
|
||||
*/
|
||||
enum Operation {
|
||||
|
||||
/**
|
||||
* Entity creation
|
||||
*/
|
||||
CREATE,
|
||||
|
||||
/**
|
||||
* Read entities
|
||||
*/
|
||||
READ,
|
||||
|
||||
/**
|
||||
* Entity modification (e.g. name/description change, tag/type assignment, etc.)
|
||||
*/
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* Entity deletion
|
||||
*/
|
||||
DELETE
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ public class ExceptionMappingAspectHandler implements Ordered {
|
||||
* the thrown and catched exception
|
||||
* @throws Throwable
|
||||
*/
|
||||
@AfterThrowing(pointcut = "execution( * org.eclipse.hawkbit.repository.jpa.*Management.*(..))", throwing = "ex")
|
||||
@AfterThrowing(pointcut = "execution( * org.eclipse.hawkbit.repository.jpa.management.*Management.*(..))", throwing = "ex")
|
||||
// Exception for squid:S00112, squid:S1162
|
||||
// It is a AspectJ proxy which deals with exceptions.
|
||||
@SuppressWarnings({ "squid:S00112", "squid:S1162" })
|
||||
|
||||
@@ -10,10 +10,9 @@
|
||||
package org.eclipse.hawkbit.repository.jpa.autoassign;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.autoassign.AutoAssignExecutor;
|
||||
@@ -39,8 +38,8 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAutoAssignExecutor.class);
|
||||
|
||||
/**
|
||||
* The message which is added to the action status when a distribution set
|
||||
* is assigned to an target. First %s is the name of the target filter.
|
||||
* The message which is added to the action status when a distribution set is
|
||||
* assigned to an target. First %s is the name of the target filter.
|
||||
*/
|
||||
private static final String ACTION_MESSAGE = "Auto assignment by target filter: %s";
|
||||
|
||||
@@ -55,7 +54,7 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
|
||||
private final PlatformTransactionManager transactionManager;
|
||||
|
||||
private final TenantAware tenantAware;
|
||||
private final ContextAware contextAware;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -66,20 +65,16 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
* to assign distribution sets to targets
|
||||
* @param transactionManager
|
||||
* to run transactions
|
||||
* @param tenantAware
|
||||
* to handle the tenant context
|
||||
* @param contextAware
|
||||
* to handle the context
|
||||
*/
|
||||
protected AbstractAutoAssignExecutor(final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final DeploymentManagement deploymentManagement, final PlatformTransactionManager transactionManager,
|
||||
final TenantAware tenantAware) {
|
||||
final ContextAware contextAware) {
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.transactionManager = transactionManager;
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
protected TargetFilterQueryManagement getTargetFilterQueryManagement() {
|
||||
return targetFilterQueryManagement;
|
||||
this.contextAware = contextAware;
|
||||
}
|
||||
|
||||
protected DeploymentManagement getDeploymentManagement() {
|
||||
@@ -90,10 +85,13 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
protected TenantAware getTenantAware() {
|
||||
return tenantAware;
|
||||
protected TenantAware getContextAware() {
|
||||
return contextAware;
|
||||
}
|
||||
|
||||
// run in the context the auto assignment is made in, i.e. if there is access control context it runs in it
|
||||
// otherwise in the tenant & user context built by createdBy
|
||||
// Note! It must be called in a tenant context, i.e. contextAware.getCurrentTenant() returns the tenant
|
||||
protected void forEachFilterWithAutoAssignDS(final Consumer<TargetFilterQuery> consumer) {
|
||||
Slice<TargetFilterQuery> filterQueries;
|
||||
Pageable query = PageRequest.of(0, PAGE_SIZE);
|
||||
@@ -103,7 +101,19 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
|
||||
filterQueries.forEach(filterQuery -> {
|
||||
try {
|
||||
runInUserContext(filterQuery, () -> consumer.accept(filterQuery));
|
||||
filterQuery.getAccessControlContext().ifPresentOrElse(
|
||||
context -> // has stored context - executes it with it
|
||||
contextAware.runInContext(
|
||||
context,
|
||||
() -> consumer.accept(filterQuery)),
|
||||
() -> // has no stored context - executes it in the tenant & user scope
|
||||
contextAware.runAsTenantAsUser(
|
||||
contextAware.getCurrentTenant(),
|
||||
getAutoAssignmentInitiatedBy(filterQuery), () -> {
|
||||
consumer.accept(filterQuery);
|
||||
return null;
|
||||
})
|
||||
);
|
||||
} catch (final RuntimeException ex) {
|
||||
LOGGER.debug(
|
||||
"Exception on forEachFilterWithAutoAssignDS execution for tenant {} with filter id {}. Continue with next filter query.",
|
||||
@@ -118,8 +128,8 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs target assignments within a dedicated transaction for a given list
|
||||
* of controllerIDs
|
||||
* Runs target assignments within a dedicated transaction for a given list of
|
||||
* controllerIDs
|
||||
*
|
||||
* @param targetFilterQuery
|
||||
* the target filter query
|
||||
@@ -147,8 +157,8 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of {@link DeploymentRequest} for given list of
|
||||
* controllerIds and {@link TargetFilterQuery}
|
||||
* Creates a list of {@link DeploymentRequest} for given list of controllerIds
|
||||
* and {@link TargetFilterQuery}
|
||||
*
|
||||
* @param controllerIds
|
||||
* list of controllerIds
|
||||
@@ -169,16 +179,12 @@ public abstract class AbstractAutoAssignExecutor implements AutoAssignExecutor {
|
||||
.deploymentRequest(controllerId, filterQuery.getAutoAssignDistributionSet().getId())
|
||||
.setActionType(autoAssignActionType).setWeight(filterQuery.getAutoAssignWeight().orElse(null))
|
||||
.setConfirmationRequired(filterQuery.isConfirmationRequired()).build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected void runInUserContext(final TargetFilterQuery targetFilterQuery, final Runnable handler) {
|
||||
DeploymentHelper.runInNonSystemContext(handler,
|
||||
() -> Objects.requireNonNull(getAutoAssignmentInitiatedBy(targetFilterQuery)), tenantAware);
|
||||
.toList();
|
||||
}
|
||||
|
||||
protected static String getAutoAssignmentInitiatedBy(final TargetFilterQuery targetFilterQuery) {
|
||||
return StringUtils.isEmpty(targetFilterQuery.getAutoAssignInitiatedBy()) ? targetFilterQuery.getCreatedBy()
|
||||
: targetFilterQuery.getAutoAssignInitiatedBy();
|
||||
return StringUtils.hasText(targetFilterQuery.getAutoAssignInitiatedBy())
|
||||
? targetFilterQuery.getAutoAssignInitiatedBy()
|
||||
: targetFilterQuery.getCreatedBy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ package org.eclipse.hawkbit.repository.jpa.autoassign;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.exception.AbstractServerRtException;
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
@@ -22,7 +22,6 @@ import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
@@ -54,36 +53,36 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
||||
* to assign distribution sets to targets
|
||||
* @param transactionManager
|
||||
* to run transactions
|
||||
* @param tenantAware
|
||||
* to handle the tenant context
|
||||
* @param contextAware
|
||||
* to handle the context
|
||||
*/
|
||||
public AutoAssignChecker(final TargetFilterQueryManagement targetFilterQueryManagement,
|
||||
final TargetManagement targetManagement, final DeploymentManagement deploymentManagement,
|
||||
final PlatformTransactionManager transactionManager, final TenantAware tenantAware) {
|
||||
super(targetFilterQueryManagement, deploymentManagement, transactionManager, tenantAware);
|
||||
final PlatformTransactionManager transactionManager, final ContextAware contextAware) {
|
||||
super(targetFilterQueryManagement, deploymentManagement, transactionManager, contextAware);
|
||||
this.targetManagement = targetManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void checkAllTargets() {
|
||||
LOGGER.debug("Auto assign check call for tenant {} started", getTenantAware().getCurrentTenant());
|
||||
LOGGER.debug("Auto assign check call for tenant {} started", getContextAware().getCurrentTenant());
|
||||
forEachFilterWithAutoAssignDS(this::checkByTargetFilterQueryAndAssignDS);
|
||||
LOGGER.debug("Auto assign check call for tenant {} finished", getTenantAware().getCurrentTenant());
|
||||
LOGGER.debug("Auto assign check call for tenant {} finished", getContextAware().getCurrentTenant());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSingleTarget(String controllerId) {
|
||||
LOGGER.debug("Auto assign check call for tenant {} and device {} started", getTenantAware().getCurrentTenant(),
|
||||
LOGGER.debug("Auto assign check call for tenant {} and device {} started", getContextAware().getCurrentTenant(),
|
||||
controllerId);
|
||||
forEachFilterWithAutoAssignDS(filter -> checkForDevice(controllerId, filter));
|
||||
LOGGER.debug("Auto assign check call for tenant {} and device {} finished", getTenantAware().getCurrentTenant(),
|
||||
LOGGER.debug("Auto assign check call for tenant {} and device {} finished", getContextAware().getCurrentTenant(),
|
||||
controllerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the distribution set, gets all controllerIds and assigns the DS
|
||||
* to them. Catches PersistenceException and own exceptions derived from
|
||||
* Fetches the distribution set, gets all controllerIds and assigns the DS to
|
||||
* them. Catches PersistenceException and own exceptions derived from
|
||||
* AbstractServerRtException
|
||||
*
|
||||
* @param targetFilterQuery
|
||||
@@ -91,34 +90,34 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
||||
*/
|
||||
private void checkByTargetFilterQueryAndAssignDS(final TargetFilterQuery targetFilterQuery) {
|
||||
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} started",
|
||||
getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
try {
|
||||
int count;
|
||||
do {
|
||||
final List<String> controllerIds = targetManagement
|
||||
.findByTargetFilterQueryAndNonDSAndCompatible(
|
||||
.findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(
|
||||
PageRequest.of(0, Constants.MAX_ENTRIES_IN_STATEMENT),
|
||||
targetFilterQuery.getAutoAssignDistributionSet().getId(), targetFilterQuery.getQuery())
|
||||
.getContent().stream().map(Target::getControllerId).collect(Collectors.toList());
|
||||
.getContent().stream().map(Target::getControllerId).toList();
|
||||
LOGGER.debug(
|
||||
"Retrieved {} auto assign targets for tenant {} and target filter query id {}, starting with assignment",
|
||||
controllerIds.size(), getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
controllerIds.size(), getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
|
||||
count = runTransactionalAssignment(targetFilterQuery, controllerIds);
|
||||
LOGGER.debug(
|
||||
"Assignment for {} auto assign targets for tenant {} and target filter query id {} finished",
|
||||
controllerIds.size(), getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
controllerIds.size(), getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
} while (count == Constants.MAX_ENTRIES_IN_STATEMENT);
|
||||
} catch (final PersistenceException | AbstractServerRtException e) {
|
||||
LOGGER.error("Error during auto assign check of target filter query id {}", targetFilterQuery.getId(), e);
|
||||
}
|
||||
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} finished",
|
||||
getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
}
|
||||
|
||||
private void checkForDevice(final String controllerId, final TargetFilterQuery targetFilterQuery) {
|
||||
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} for device {} started",
|
||||
getTenantAware().getCurrentTenant(), targetFilterQuery.getId(), controllerId);
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId(), controllerId);
|
||||
try {
|
||||
final boolean controllerIdMatches = targetManagement.isTargetMatchingQueryAndDSNotAssignedAndCompatible(
|
||||
controllerId, targetFilterQuery.getAutoAssignDistributionSet().getId(),
|
||||
@@ -132,6 +131,6 @@ public class AutoAssignChecker extends AbstractAutoAssignExecutor {
|
||||
LOGGER.error("Error during auto assign check of target filter query id {}", targetFilterQuery.getId(), e);
|
||||
}
|
||||
LOGGER.debug("Auto assign check call for tenant {} and target filter query id {} finished",
|
||||
getTenantAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
getContextAware().getCurrentTenant(), targetFilterQuery.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class AutoAssignScheduler {
|
||||
|
||||
/**
|
||||
* Scheduler method called by the spring-async mechanism. Retrieves all
|
||||
* tenants from the {@link SystemManagement#findTenants()} and runs for each
|
||||
* tenants and runs for each
|
||||
* tenant the auto assignments defined in the target filter queries
|
||||
* {@link SystemSecurityContext}.
|
||||
*/
|
||||
@@ -83,7 +83,7 @@ public class AutoAssignScheduler {
|
||||
}
|
||||
|
||||
try {
|
||||
LOGGER.debug("Auto assign scheduled execution has aquired lock and started for each tenant.");
|
||||
LOGGER.debug("Auto assign scheduled execution has acquired lock and started for each tenant.");
|
||||
systemManagement.forEachTenant(tenant -> autoAssignExecutor.checkAllTargets());
|
||||
} finally {
|
||||
lock.unlock();
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -25,8 +25,14 @@ import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -42,6 +48,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.persistence.criteria.JoinType;
|
||||
|
||||
/**
|
||||
* {@link DistributionSet} to {@link Target} assignment strategy as utility for
|
||||
* {@link JpaDeploymentManagement}.
|
||||
@@ -61,10 +69,10 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
private final BooleanSupplier confirmationFlowConfig;
|
||||
|
||||
AbstractDsAssignmentStrategy(final TargetRepository targetRepository,
|
||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||
final BooleanSupplier confirmationFlowConfig) {
|
||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||
final BooleanSupplier confirmationFlowConfig) {
|
||||
this.targetRepository = targetRepository;
|
||||
this.afterCommit = afterCommit;
|
||||
this.eventPublisherHolder = eventPublisherHolder;
|
||||
@@ -141,17 +149,23 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
/**
|
||||
* Cancels {@link Action}s that are no longer necessary and sends
|
||||
* cancellations to the controller.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param targetsIds
|
||||
* to override {@link Action}s
|
||||
* @param targetsIds to override {@link Action}s
|
||||
*/
|
||||
protected List<Long> overrideObsoleteUpdateActions(final Collection<Long> targetsIds) {
|
||||
|
||||
// Figure out if there are potential target/action combinations that
|
||||
// need to be considered for cancellation
|
||||
final List<JpaAction> activeActions = actionRepository
|
||||
.findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetNotRequiredMigrationStep(
|
||||
targetsIds, Action.Status.CANCELING);
|
||||
final List<JpaAction> activeActions = actionRepository.findAll((root, query, cb) -> {
|
||||
root.fetch(JpaAction_.target, JoinType.LEFT);
|
||||
return cb.and(
|
||||
cb.equal(root.get(JpaAction_.active), true),
|
||||
cb.equal(root.get(JpaAction_.distributionSet).get(JpaDistributionSet_.requiredMigrationStep), false),
|
||||
cb.notEqual(root.get(JpaAction_.status), Action.Status.CANCELING),
|
||||
root.get(JpaAction_.target).get(JpaTarget_.id).in(targetsIds)
|
||||
);
|
||||
});
|
||||
|
||||
final List<Long> targetIds = activeActions.stream().map(action -> {
|
||||
action.setStatus(Status.CANCELING);
|
||||
@@ -174,16 +188,22 @@ public abstract class AbstractDsAssignmentStrategy {
|
||||
/**
|
||||
* Closes {@link Action}s that are no longer necessary without sending a
|
||||
* hint to the controller.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param targetsIds
|
||||
* to override {@link Action}s
|
||||
* @param targetsIds to override {@link Action}s
|
||||
*/
|
||||
protected List<Long> closeObsoleteUpdateActions(final Collection<Long> targetsIds) {
|
||||
|
||||
// Figure out if there are potential target/action combinations that
|
||||
// need to be considered for cancellation
|
||||
final List<JpaAction> activeActions = actionRepository
|
||||
.findByActiveAndTargetIdInAndDistributionSetNotRequiredMigrationStep(targetsIds);
|
||||
final List<JpaAction> activeActions = actionRepository.findAll((root, query, cb) -> {
|
||||
root.fetch(JpaAction_.target, JoinType.LEFT);
|
||||
return cb.and(
|
||||
cb.equal(root.get(JpaAction_.active), true),
|
||||
cb.equal(root.get(JpaAction_.distributionSet).get(JpaDistributionSet_.requiredMigrationStep), false),
|
||||
root.get(JpaAction_.target).get(JpaTarget_.id).in(targetsIds)
|
||||
);
|
||||
});
|
||||
|
||||
return activeActions.stream().map(action -> {
|
||||
action.setStatus(Status.CANCELED);
|
||||
@@ -7,10 +7,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -21,6 +20,10 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
@@ -28,6 +31,7 @@ import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.model.Action.ActionType.DOWNLOAD_ONLY;
|
||||
import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED;
|
||||
@@ -44,7 +48,7 @@ public class JpaActionManagement {
|
||||
protected final QuotaManagement quotaManagement;
|
||||
protected final RepositoryProperties repositoryProperties;
|
||||
|
||||
protected JpaActionManagement(final ActionRepository actionRepository,
|
||||
public JpaActionManagement(final ActionRepository actionRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final QuotaManagement quotaManagement,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
this.actionRepository = actionRepository;
|
||||
@@ -53,30 +57,37 @@ public class JpaActionManagement {
|
||||
this.repositoryProperties = repositoryProperties;
|
||||
}
|
||||
|
||||
protected List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId,
|
||||
List<Action> findActiveActionsWithHighestWeightConsideringDefault(final String controllerId,
|
||||
final int maxActionCount) {
|
||||
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final List<Action> actions = new ArrayList<>();
|
||||
final PageRequest pageable = PageRequest.of(0, maxActionCount);
|
||||
actions.addAll(actionRepository
|
||||
.findByTargetControllerIdAndActiveIsTrueAndWeightIsNotNullOrderByWeightDescIdAsc(pageable, controllerId)
|
||||
.getContent());
|
||||
actions.addAll(actionRepository
|
||||
.findByTargetControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(pageable, controllerId)
|
||||
.getContent());
|
||||
actions.addAll(
|
||||
actionRepository
|
||||
.findAll(
|
||||
ActionSpecifications.byTargetControllerIdAndActiveAndWeightIsNullFetchDS(controllerId, false),
|
||||
PageRequest.of(
|
||||
0, maxActionCount,
|
||||
Sort.by(
|
||||
Sort.Order.desc(JpaAction_.WEIGHT),
|
||||
Sort.Order.asc(JpaAction_.ID))))
|
||||
.getContent());
|
||||
|
||||
actions.addAll(
|
||||
actionRepository
|
||||
.findAll(
|
||||
ActionSpecifications.byTargetControllerIdAndActiveAndWeightIsNullFetchDS(controllerId, true),
|
||||
PageRequest.of(
|
||||
0, maxActionCount,
|
||||
Sort.by(
|
||||
Sort.Order.asc(JpaAction_.ID))))
|
||||
.getContent());
|
||||
final Comparator<Action> actionImportance = Comparator.comparingInt(this::getWeightConsideringDefault)
|
||||
.reversed().thenComparing(Action::getId);
|
||||
return actions.stream().sorted(actionImportance).limit(maxActionCount).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected List<JpaAction> findActiveActionsHavingStatus(final String controllerId, final Action.Status status) {
|
||||
if (!actionRepository.activeActionExistsForControllerId(controllerId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections
|
||||
.unmodifiableList(actionRepository.findByTargetIdAndIsActiveAndActionStatus(controllerId, status));
|
||||
return actionRepository.findAll(
|
||||
ActionSpecifications.byTargetControllerIdAndIsActiveAndStatus(controllerId, status));
|
||||
}
|
||||
|
||||
protected Action addActionStatus(final JpaActionStatusCreate statusCreate) {
|
||||
@@ -100,7 +111,7 @@ public class JpaActionManagement {
|
||||
* Status.FINISHED are allowed. In the case of a DOWNLOAD_ONLY action, we accept
|
||||
* status updates only once.
|
||||
*/
|
||||
protected boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) {
|
||||
private boolean isUpdatingActionStatusAllowed(final JpaAction action, final JpaActionStatus actionStatus) {
|
||||
|
||||
final boolean isIntermediateFeedback = (FINISHED != actionStatus.getStatus())
|
||||
&& (Action.Status.ERROR != actionStatus.getStatus());
|
||||
@@ -113,7 +124,7 @@ public class JpaActionManagement {
|
||||
return action.isActive() || isAllowedByRepositoryConfiguration || isAllowedForDownloadOnlyActions;
|
||||
}
|
||||
|
||||
protected int getWeightConsideringDefault(final Action action) {
|
||||
public int getWeightConsideringDefault(final Action action) {
|
||||
return action.getWeight().orElse(repositoryProperties.getActionWeightIfAbsent());
|
||||
}
|
||||
|
||||
@@ -130,7 +141,7 @@ public class JpaActionManagement {
|
||||
/**
|
||||
* Sets {@link TargetUpdateStatus} based on given {@link ActionStatus}.
|
||||
*/
|
||||
protected Action handleAddUpdateActionStatus(final JpaActionStatus actionStatus, final JpaAction action) {
|
||||
private Action handleAddUpdateActionStatus(final JpaActionStatus actionStatus, final JpaAction action) {
|
||||
// information status entry - check for a potential DOS attack
|
||||
assertActionStatusQuota(action);
|
||||
assertActionStatusMessageQuota(actionStatus);
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -19,6 +19,7 @@ import org.eclipse.hawkbit.artifact.repository.HashNotMatchException;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifactHash;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.repository.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
@@ -26,12 +27,19 @@ import org.eclipse.hawkbit.repository.exception.ArtifactDeleteFailedException;
|
||||
import org.eclipse.hawkbit.repository.exception.ArtifactUploadFailedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidMD5HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA1HashException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidSHA256HashException;
|
||||
import org.eclipse.hawkbit.repository.jpa.EncryptionAwareDbArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ArtifactSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.FileSizeAndStorageQuotaCheckingInputStream;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
@@ -45,9 +53,14 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* JPA based {@link ArtifactManagement} implementation.
|
||||
*
|
||||
@@ -58,6 +71,8 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JpaArtifactManagement.class);
|
||||
|
||||
private final EntityManager entityManager;
|
||||
|
||||
private final LocalArtifactRepository localArtifactRepository;
|
||||
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
@@ -68,9 +83,11 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
JpaArtifactManagement(final LocalArtifactRepository localArtifactRepository,
|
||||
public JpaArtifactManagement(final EntityManager entityManager,
|
||||
final LocalArtifactRepository localArtifactRepository,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final ArtifactRepository artifactRepository,
|
||||
final QuotaManagement quotaManagement, final TenantAware tenantAware) {
|
||||
this.entityManager = entityManager;
|
||||
this.localArtifactRepository = localArtifactRepository;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
this.artifactRepository = artifactRepository;
|
||||
@@ -78,37 +95,39 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
private static Artifact checkForExistingArtifact(final String filename, final boolean overrideExisting,
|
||||
final SoftwareModule softwareModule) {
|
||||
final Optional<Artifact> artifact = softwareModule.getArtifactByFilename(filename);
|
||||
|
||||
if (artifact.isPresent()) {
|
||||
if (overrideExisting) {
|
||||
LOG.debug("overriding existing artifact with new filename {}", filename);
|
||||
return artifact.get();
|
||||
} else {
|
||||
throw new EntityAlreadyExistsException("File with that name already exists in the Software Module");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Artifact create(final ArtifactUpload artifactUpload) {
|
||||
final String filename = artifactUpload.getFilename();
|
||||
final long moduleId = artifactUpload.getModuleId();
|
||||
|
||||
final SoftwareModule softwareModule = getModuleAndThrowExceptionIfThatFails(moduleId);
|
||||
|
||||
final Artifact existing = checkForExistingArtifact(filename, artifactUpload.overrideExisting(), softwareModule);
|
||||
|
||||
assertArtifactQuota(moduleId, 1);
|
||||
final JpaSoftwareModule softwareModule =
|
||||
softwareModuleRepository
|
||||
.findById(moduleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, moduleId));
|
||||
|
||||
final String filename = artifactUpload.getFilename();
|
||||
final Artifact existing = softwareModule.getArtifactByFilename(filename).orElse(null);
|
||||
if (existing != null) {
|
||||
if (artifactUpload.overrideExisting()) {
|
||||
LOG.debug("overriding existing artifact with new filename {}", filename);
|
||||
} else {
|
||||
throw new EntityAlreadyExistsException("File with that name already exists in the Software Module");
|
||||
}
|
||||
}
|
||||
|
||||
// touch it to update the lock revision because we are modifying the
|
||||
// DS indirectly, it will, also check UPDATE access
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, softwareModule);
|
||||
|
||||
final AbstractDbArtifact artifact = storeArtifact(artifactUpload, softwareModule.isEncrypted());
|
||||
return storeArtifactMetadata(softwareModule, filename, artifact, existing);
|
||||
try {
|
||||
return storeArtifactMetadata(softwareModule, filename, artifact, existing);
|
||||
} catch (final Exception e) {
|
||||
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), artifact.getHashes().getSha1());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractDbArtifact storeArtifact(final ArtifactUpload artifactUpload, final boolean isSmEncrypted) {
|
||||
@@ -142,39 +161,57 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
return ArtifactEncryptionService.getInstance().encryptSoftwareModuleArtifact(smId, stream);
|
||||
}
|
||||
|
||||
private void assertArtifactQuota(final long id, final int requested) {
|
||||
QuotaHelper.assertAssignmentQuota(id, requested, quotaManagement.getMaxArtifactsPerSoftwareModule(),
|
||||
Artifact.class, SoftwareModule.class, localArtifactRepository::countBySoftwareModuleId);
|
||||
private void assertArtifactQuota(final long moduleId, final int requested) {
|
||||
QuotaHelper.assertAssignmentQuota(
|
||||
moduleId, requested, quotaManagement.getMaxArtifactsPerSoftwareModule(),
|
||||
Artifact.class, SoftwareModule.class,
|
||||
// get all artifacts without user context
|
||||
softwareModuleId -> localArtifactRepository
|
||||
.count(null, ArtifactSpecifications.bySoftwareModuleId(softwareModuleId)));
|
||||
}
|
||||
|
||||
private InputStream wrapInQuotaStream(final InputStream in) {
|
||||
final long maxArtifactSize = quotaManagement.getMaxArtifactSize();
|
||||
|
||||
final long currentlyUsed = localArtifactRepository.getSumOfUndeletedArtifactSize().orElse(0L);
|
||||
final long currentlyUsed = localArtifactRepository.sumOfNonDeletedArtifactSize().orElse(0L);
|
||||
final long maxArtifactSizeTotal = quotaManagement.getMaxArtifactStorage();
|
||||
|
||||
return new FileSizeAndStorageQuotaCheckingInputStream(in, maxArtifactSize,
|
||||
maxArtifactSizeTotal - currentlyUsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public boolean clearArtifactBinary(final String sha1Hash, final long moduleId) {
|
||||
final long count = localArtifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(sha1Hash,
|
||||
tenantAware.getCurrentTenant());
|
||||
if (count > 1) {
|
||||
// there are still other artifacts that need the binary
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
LOG.debug("deleting artifact from repository {}", sha1Hash);
|
||||
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash);
|
||||
return true;
|
||||
} catch (final ArtifactStoreException e) {
|
||||
throw new ArtifactDeleteFailedException(e);
|
||||
}
|
||||
/**
|
||||
* Garbage collects artifact binaries if only referenced by given
|
||||
* {@link SoftwareModule#getId()} or {@link SoftwareModule}'s that are
|
||||
* marked as deleted.
|
||||
* <p/>
|
||||
* Software module related UPDATE permission shall be checked by the callers!
|
||||
*
|
||||
* @param sha1Hash no longer needed
|
||||
* @param softwareModuleId the garbage collection call is made for
|
||||
*/
|
||||
@PreAuthorize(SpPermission.SpringEvalExpressions.HAS_AUTH_DELETE_REPOSITORY)
|
||||
void clearArtifactBinary(final String sha1Hash) {
|
||||
// countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse will skip ACM checks and
|
||||
// will return total count as it should be
|
||||
final long count = localArtifactRepository.countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(
|
||||
sha1Hash,
|
||||
tenantAware.getCurrentTenant());
|
||||
if (count <= 1) { // 1 artifact is the one being deleted!
|
||||
// removes the real artifact ONLY AFTER the delete of artifact or software module
|
||||
// in local history has passed successfully (caller has permission and no errors)
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
@Override
|
||||
public void afterCommit() {
|
||||
try {
|
||||
LOG.debug("deleting artifact from repository {}", sha1Hash);
|
||||
artifactRepository.deleteBySha1(tenantAware.getCurrentTenant(), sha1Hash);
|
||||
} catch (final ArtifactStoreException e) {
|
||||
throw new ArtifactDeleteFailedException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} // else there are still other artifacts that need the binary
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -182,24 +219,28 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long id) {
|
||||
final JpaArtifact existing = (JpaArtifact) get(id)
|
||||
final JpaArtifact toDelete = (JpaArtifact) get(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Artifact.class, id));
|
||||
|
||||
clearArtifactBinary(existing.getSha1Hash(), existing.getSoftwareModule().getId());
|
||||
// clearArtifactBinary checks (unconditionally) software module UPDATE access
|
||||
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
||||
accessController.assertOperationAllowed(AccessController.Operation.UPDATE,
|
||||
(JpaSoftwareModule) toDelete.getSoftwareModule()));
|
||||
((JpaSoftwareModule) toDelete.getSoftwareModule()).removeArtifact(toDelete);
|
||||
softwareModuleRepository.save((JpaSoftwareModule) toDelete.getSoftwareModule());
|
||||
|
||||
((JpaSoftwareModule) existing.getSoftwareModule()).removeArtifact(existing);
|
||||
softwareModuleRepository.save((JpaSoftwareModule) existing.getSoftwareModule());
|
||||
localArtifactRepository.deleteById(id);
|
||||
clearArtifactBinary(toDelete.getSha1Hash());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Artifact> get(final long id) {
|
||||
return Optional.ofNullable(localArtifactRepository.findById(id).orElse(null));
|
||||
return localArtifactRepository.findById(id).map(Artifact.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Artifact> getByFilenameAndSoftwareModule(final String filename, final long softwareModuleId) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(softwareModuleId);
|
||||
assertSoftwareModuleExists(softwareModuleId);
|
||||
|
||||
return localArtifactRepository.findFirstByFilenameAndSoftwareModuleId(filename, softwareModuleId);
|
||||
}
|
||||
@@ -215,30 +256,38 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Artifact> findBySoftwareModule(final Pageable pageReq, final long swId) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(swId);
|
||||
public Page<Artifact> findBySoftwareModule(final Pageable pageReq, final long softwareModuleId) {
|
||||
assertSoftwareModuleExists(softwareModuleId);
|
||||
|
||||
return localArtifactRepository.findBySoftwareModuleId(pageReq, swId);
|
||||
return localArtifactRepository
|
||||
.findAll(ArtifactSpecifications.bySoftwareModuleId(softwareModuleId), pageReq)
|
||||
.map(Artifact.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countBySoftwareModule(final long swId) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(swId);
|
||||
public long countBySoftwareModule(final long softwareModuleId) {
|
||||
assertSoftwareModuleExists(softwareModuleId);
|
||||
|
||||
return localArtifactRepository.countBySoftwareModuleId(swId);
|
||||
return localArtifactRepository.count(ArtifactSpecifications.bySoftwareModuleId(softwareModuleId));
|
||||
}
|
||||
|
||||
private void throwExceptionIfSoftwareModuleDoesNotExist(final Long swId) {
|
||||
if (!softwareModuleRepository.existsById(swId)) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, swId);
|
||||
}
|
||||
@Override
|
||||
public long count() {
|
||||
return localArtifactRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DbArtifact> loadArtifactBinary(final String sha1Hash, final long softwareModuleId,
|
||||
final boolean isEncrypted) {
|
||||
assertSoftwareModuleExists(softwareModuleId);
|
||||
|
||||
final String tenant = tenantAware.getCurrentTenant();
|
||||
if (artifactRepository.existsByTenantAndSha1(tenant, sha1Hash)) {
|
||||
// assert artifact exists and belongs to the software module
|
||||
findFirstBySHA1(sha1Hash)
|
||||
// if not found no assertOperationAllowed shall fail
|
||||
.orElseThrow(InsufficientPermissionException::new);
|
||||
|
||||
final DbArtifact dbArtifact = artifactRepository.getArtifactBySha1(tenant, sha1Hash);
|
||||
return Optional.ofNullable(
|
||||
isEncrypted ? wrapInEncryptionAwareDbArtifact(softwareModuleId, dbArtifact) : dbArtifact);
|
||||
@@ -247,39 +296,36 @@ public class JpaArtifactManagement implements ArtifactManagement {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private final DbArtifact wrapInEncryptionAwareDbArtifact(final long smId, final DbArtifact dbArtifact) {
|
||||
private DbArtifact wrapInEncryptionAwareDbArtifact(final long softwareModuleId, final DbArtifact dbArtifact) {
|
||||
if (dbArtifact == null) {
|
||||
return null;
|
||||
}
|
||||
final ArtifactEncryptionService encryptionService = ArtifactEncryptionService.getInstance();
|
||||
return new EncryptionAwareDbArtifact(dbArtifact,
|
||||
stream -> encryptionService.decryptSoftwareModuleArtifact(smId, stream),
|
||||
stream -> encryptionService.decryptSoftwareModuleArtifact(softwareModuleId, stream),
|
||||
encryptionService.encryptionSizeOverhead());
|
||||
}
|
||||
|
||||
private Artifact storeArtifactMetadata(final SoftwareModule softwareModule, final String providedFilename,
|
||||
final AbstractDbArtifact result, final Artifact existing) {
|
||||
JpaArtifact artifact = (JpaArtifact) existing;
|
||||
final JpaArtifact artifact;
|
||||
if (existing == null) {
|
||||
artifact = new JpaArtifact(result.getHashes().getSha1(), providedFilename, softwareModule);
|
||||
} else {
|
||||
artifact = (JpaArtifact) existing;
|
||||
artifact.setSha1Hash(result.getHashes().getSha1());
|
||||
}
|
||||
artifact.setMd5Hash(result.getHashes().getMd5());
|
||||
artifact.setSha256Hash(result.getHashes().getSha256());
|
||||
artifact.setSha1Hash(result.getHashes().getSha1());
|
||||
artifact.setSize(result.getSize());
|
||||
|
||||
LOG.debug("storing new artifact into repository {}", artifact);
|
||||
return localArtifactRepository.save(artifact);
|
||||
return localArtifactRepository.save(AccessController.Operation.CREATE, artifact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return localArtifactRepository.count();
|
||||
private void assertSoftwareModuleExists(final long softwareModuleId) {
|
||||
if (!softwareModuleRepository.existsById(softwareModuleId)) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, softwareModuleId);
|
||||
}
|
||||
}
|
||||
|
||||
private SoftwareModule getModuleAndThrowExceptionIfThatFails(final Long moduleId) {
|
||||
return softwareModuleRepository.findById(moduleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, moduleId));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -31,6 +31,9 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAutoConfirmationStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -64,10 +67,10 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
protected JpaConfirmationManagement(final TargetRepository targetRepository,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
public JpaConfirmationManagement(final TargetRepository targetRepository,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final RepositoryProperties repositoryProperties, final QuotaManagement quotaManagement,
|
||||
final EntityFactory entityFactory) {
|
||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||
this.targetRepository = targetRepository;
|
||||
this.entityFactory = entityFactory;
|
||||
@@ -208,7 +211,7 @@ public class JpaConfirmationManagement extends JpaActionManagement implements Co
|
||||
action.getId(), autoConfirmationStatus.getInitiator(), autoConfirmationStatus.getCreatedBy());
|
||||
|
||||
// do not make use of
|
||||
// org.eclipse.hawkbit.repository.jpa.JpaActionManagement.handleAddUpdateActionStatus
|
||||
// org.eclipse.hawkbit.repository.jpa.management.JpaActionManagement.handleAddUpdateActionStatus
|
||||
// to bypass the quota check. Otherwise the action will not be confirmed in case
|
||||
// of exceeded action status quota.
|
||||
action.setStatus(Status.RUNNING);
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.model.Action.Status.DOWNLOADED;
|
||||
import static org.eclipse.hawkbit.repository.model.Action.Status.FINISHED;
|
||||
@@ -56,6 +56,7 @@ import org.eclipse.hawkbit.repository.exception.CancelActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidTargetAttributeException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaActionStatusCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -66,6 +67,11 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
@@ -155,8 +161,8 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
private ConfirmationManagement confirmationManagement;
|
||||
|
||||
public JpaControllerManagement(final ScheduledExecutorService executorService,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final RepositoryProperties repositoryProperties) {
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final RepositoryProperties repositoryProperties) {
|
||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||
|
||||
if (!repositoryProperties.isEagerPollPersistence()) {
|
||||
@@ -302,13 +308,20 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(moduleId);
|
||||
|
||||
final List<Action> action = actionRepository.findActionByTargetAndSoftwareModule(controllerId, moduleId);
|
||||
|
||||
if (action.isEmpty() || action.get(0).isCancelingOrCanceled()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.ofNullable(action.get(0));
|
||||
// TODO AC - REVIEW
|
||||
// it used to perform 3-table join query
|
||||
// @Query("Select a from JpaAction a join a.distributionSet ds join ds.modules modul where a.target.controllerId = :target and modul.id = :module order by a.id desc")
|
||||
// final List<Action> actions = actionRepository.findActionByTargetAndSoftwareModule(controllerId, moduleId);
|
||||
// TODO AC - we could fetch distribution sets in order to skip calls to serarch for modules
|
||||
return actionRepository
|
||||
.findAll(ActionSpecifications.byTargetControllerIdAndActive(controllerId, true))
|
||||
.stream()
|
||||
.filter(action -> !action.isCancelingOrCanceled())
|
||||
.filter(action -> action.getDistributionSet().getModules()
|
||||
.stream()
|
||||
.anyMatch(module -> module.getId() == moduleId))
|
||||
.map(Action.class::cast)
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private void throwExceptionIfTargetDoesNotExist(final String controllerId) {
|
||||
@@ -358,12 +371,7 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
|
||||
@Override
|
||||
public Optional<Action> findActionWithDetails(final long actionId) {
|
||||
return actionRepository.getActionById(actionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> getActiveActionsByExternalRef(@NotNull final List<String> externalRefs) {
|
||||
return actionRepository.findByExternalRefInAndActive(externalRefs, true);
|
||||
return actionRepository.findWithDetailsById(actionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1006,6 +1014,15 @@ public class JpaControllerManagement extends JpaActionManagement implements Cont
|
||||
|
||||
@Override
|
||||
public void updateActionExternalRef(final long actionId, @NotEmpty final String externalRef) {
|
||||
// if access control for target repository is present check that caller has
|
||||
// UPDATE access to the target of the action
|
||||
targetRepository.getAccessController().ifPresent(
|
||||
accessController -> accessController.assertOperationAllowed(
|
||||
AccessController.Operation.UPDATE,
|
||||
(JpaTarget) actionRepository
|
||||
.findById(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId))
|
||||
.getTarget()));
|
||||
actionRepository.updateExternalRef(actionId, externalRef);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.REPOSITORY_ACTIONS_AUTOCLOSE_ENABLED;
|
||||
|
||||
@@ -49,17 +49,23 @@ import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.ForceQuitActionNotAllowedException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompatibleTargetTypeException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.exception.MultiAssignmentIsNotEnabledException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.ActionSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
@@ -151,15 +157,15 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
private final Database database;
|
||||
private final RetryTemplate retryTemplate;
|
||||
|
||||
protected JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
public JpaDeploymentManagement(final EntityManager entityManager, final ActionRepository actionRepository,
|
||||
final DistributionSetManagement distributionSetManagement,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetRepository targetRepository,
|
||||
final ActionStatusRepository actionStatusRepository, final AuditorAware<String> auditorProvider,
|
||||
final EventPublisherHolder eventPublisherHolder, final AfterTransactionCommitExecutor afterCommit,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final PlatformTransactionManager txManager,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final QuotaManagement quotaManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware, final Database database,
|
||||
final RepositoryProperties repositoryProperties) {
|
||||
super(actionRepository, actionStatusRepository, quotaManagement, repositoryProperties);
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
@@ -185,13 +191,12 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
@Transactional(isolation = Isolation.READ_COMMITTED)
|
||||
public List<DistributionSetAssignmentResult> offlineAssignedDistributionSets(
|
||||
final Collection<Entry<String, Long>> assignments) {
|
||||
final Collection<Entry<String, Long>> distinctAssignments = assignments.stream().distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final Collection<Entry<String, Long>> distinctAssignments = assignments.stream().distinct().toList();
|
||||
enforceMaxAssignmentsPerRequest(distinctAssignments.size());
|
||||
|
||||
final List<DeploymentRequest> deploymentRequests = distinctAssignments.stream()
|
||||
.map(entry -> DeploymentManagement.deploymentRequest(entry.getKey(), entry.getValue()).build())
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
|
||||
return assignDistributionSets(tenantAware.getCurrentUsername(), deploymentRequests, null,
|
||||
offlineDsAssignmentStrategy);
|
||||
@@ -216,36 +221,56 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
private List<DistributionSetAssignmentResult> assignDistributionSets(final String initiatedBy,
|
||||
final List<DeploymentRequest> deploymentRequests, final String actionMessage,
|
||||
final AbstractDsAssignmentStrategy strategy) {
|
||||
final List<DeploymentRequest> validatedRequests = validateRequestForAssignments(deploymentRequests);
|
||||
final List<DeploymentRequest> validatedRequests = validateAndFilterRequestForAssignments(deploymentRequests);
|
||||
final Map<Long, List<TargetWithActionType>> assignmentsByDsIds = convertRequest(validatedRequests);
|
||||
|
||||
final List<DistributionSetAssignmentResult> results = assignmentsByDsIds.entrySet().stream()
|
||||
.map(entry -> assignDistributionSetToTargetsWithRetry(initiatedBy, entry.getKey(), entry.getValue(),
|
||||
actionMessage, strategy))
|
||||
.collect(Collectors.toList());
|
||||
.toList();
|
||||
strategy.sendDeploymentEvents(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<DeploymentRequest> validateRequestForAssignments(List<DeploymentRequest> deploymentRequests) {
|
||||
if (!isMultiAssignmentsEnabled()) {
|
||||
deploymentRequests = deploymentRequests.stream().distinct().collect(Collectors.toList());
|
||||
checkIfRequiresMultiAssignment(deploymentRequests);
|
||||
private List<DeploymentRequest> validateAndFilterRequestForAssignments(List<DeploymentRequest> deploymentRequests) {
|
||||
if (deploymentRequests.isEmpty()) {
|
||||
return deploymentRequests;
|
||||
}
|
||||
checkForTargetTypeCompatibility(deploymentRequests);
|
||||
|
||||
deploymentRequests = deploymentRequests.stream().distinct().toList();
|
||||
checkForMultiAssignment(deploymentRequests);
|
||||
checkQuotaForAssignment(deploymentRequests);
|
||||
return deploymentRequests;
|
||||
// validates READ access to deployment sets, throws exception if deployment set is not accessible
|
||||
checkForTargetTypeCompatibility(deploymentRequests);
|
||||
// filters only targets that are updatable
|
||||
// TODO - should assignments that contain non-existing/allowed devices be allowed anyway?
|
||||
return filterByTargetUpdatable(deploymentRequests);
|
||||
}
|
||||
|
||||
private void checkForMultiAssignment(final Collection<DeploymentRequest> deploymentRequests) {
|
||||
if (!isMultiAssignmentsEnabled()) {
|
||||
final long distinctTargetsInRequest = deploymentRequests.stream()
|
||||
.map(request -> request.getTargetWithActionType().getControllerId()).distinct().count();
|
||||
if (distinctTargetsInRequest < deploymentRequests.size()) {
|
||||
throw new MultiAssignmentIsNotEnabledException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkQuotaForAssignment(final Collection<DeploymentRequest> deploymentRequests) {
|
||||
enforceMaxAssignmentsPerRequest(deploymentRequests.size());
|
||||
enforceMaxActionsPerTarget(deploymentRequests);
|
||||
}
|
||||
|
||||
private void checkForTargetTypeCompatibility(final List<DeploymentRequest> deploymentRequests) {
|
||||
final List<String> controllerIds = deploymentRequests.stream().map(DeploymentRequest::getControllerId)
|
||||
.distinct().collect(Collectors.toList());
|
||||
.distinct().toList();
|
||||
final List<Long> distSetIds = deploymentRequests.stream().map(DeploymentRequest::getDistributionSetId)
|
||||
.distinct().collect(Collectors.toList());
|
||||
.distinct().toList();
|
||||
|
||||
if (controllerIds.size() > 1 && distSetIds.size() > 1) {
|
||||
throw new IllegalStateException(
|
||||
"Assigning multiple Targets to multiple Distribution Sets simultaneously is not allowed!");
|
||||
"Assigning multiple Distribution Sets to multiple Targets simultaneously is not allowed!");
|
||||
}
|
||||
|
||||
if (distSetIds.size() == 1) {
|
||||
@@ -287,20 +312,30 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
}
|
||||
|
||||
private List<DeploymentRequest> filterByTargetUpdatable(final List<DeploymentRequest> deploymentRequests) {
|
||||
final List<String> controllerIds =
|
||||
deploymentRequests.stream()
|
||||
.map(DeploymentRequest::getControllerId)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
final List<String> found = targetRepository.findAll(
|
||||
AccessController.Operation.UPDATE,
|
||||
TargetSpecifications.hasControllerIdIn(controllerIds)
|
||||
).stream().map(JpaTarget::getControllerId).toList();
|
||||
if (found.size() != controllerIds.size()) {
|
||||
return deploymentRequests.stream()
|
||||
.filter(deploymentRequest -> found.contains(deploymentRequest.getControllerId())).toList();
|
||||
}
|
||||
return deploymentRequests;
|
||||
}
|
||||
|
||||
private static Map<Long, List<TargetWithActionType>> convertRequest(
|
||||
final Collection<DeploymentRequest> deploymentRequests) {
|
||||
return deploymentRequests.stream().collect(Collectors.groupingBy(DeploymentRequest::getDistributionSetId,
|
||||
Collectors.mapping(DeploymentRequest::getTargetWithActionType, Collectors.toList())));
|
||||
}
|
||||
|
||||
private static void checkIfRequiresMultiAssignment(final Collection<DeploymentRequest> deploymentRequests) {
|
||||
final long distinctTargetsInRequest = deploymentRequests.stream()
|
||||
.map(request -> request.getTargetWithActionType().getControllerId()).distinct().count();
|
||||
if (distinctTargetsInRequest < deploymentRequests.size()) {
|
||||
throw new MultiAssignmentIsNotEnabledException();
|
||||
}
|
||||
}
|
||||
|
||||
private DistributionSetAssignmentResult assignDistributionSetToTargetsWithRetry(final String initiatedBy,
|
||||
final Long dsID, final Collection<TargetWithActionType> targetsWithActionType, final String actionMessage,
|
||||
final AbstractDsAssignmentStrategy assignmentStrategy) {
|
||||
@@ -310,17 +345,16 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
/**
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s by
|
||||
* their IDs with a specific {@link ActionType} and {@code forcetime}.
|
||||
*
|
||||
*
|
||||
* method assigns the {@link DistributionSet} to all {@link Target}s by their
|
||||
* IDs with a specific {@link ActionType} and {@code forcetime}.
|
||||
* <p/>
|
||||
* In case the update was executed offline (i.e. not managed by hawkBit) the
|
||||
* handling differs my means that:<br/>
|
||||
* A. it ignores targets completely that are in
|
||||
* {@link TargetUpdateStatus#PENDING}.<br/>
|
||||
* B. it created completed actions.<br/>
|
||||
* C. sets both installed and assigned DS on the target and switches the
|
||||
* status to {@link TargetUpdateStatus#IN_SYNC} <br/>
|
||||
* C. sets both installed and assigned DS on the target and switches the status
|
||||
* to {@link TargetUpdateStatus#IN_SYNC} <br/>
|
||||
* D. does not send a {@link TargetAssignDistributionSetEvent}.<br/>
|
||||
*
|
||||
* @param initiatedBy
|
||||
@@ -346,11 +380,13 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
final JpaDistributionSet distributionSetEntity = (JpaDistributionSet) distributionSetManagement
|
||||
.getValidAndComplete(dsID);
|
||||
final List<String> providedTargetIds = targetsWithActionType.stream().map(TargetWithActionType::getControllerId)
|
||||
.distinct().collect(Collectors.toList());
|
||||
.distinct().toList();
|
||||
|
||||
final List<String> existingTargetIds = Lists.partition(providedTargetIds, Constants.MAX_ENTRIES_IN_STATEMENT)
|
||||
.stream().map(ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids)))
|
||||
.flatMap(List::stream).map(JpaTarget::getControllerId).collect(Collectors.toList());
|
||||
.stream()
|
||||
.map(ids -> targetRepository.findAll(
|
||||
AccessController.Operation.UPDATE, TargetSpecifications.hasControllerIdIn(ids)))
|
||||
.flatMap(List::stream).map(JpaTarget::getControllerId).toList();
|
||||
|
||||
final List<JpaTarget> targetEntities = assignmentStrategy.findTargetsForAssignment(existingTargetIds,
|
||||
distributionSetEntity.getId());
|
||||
@@ -360,7 +396,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
final List<TargetWithActionType> existingTargetsWithActionType = targetsWithActionType.stream()
|
||||
.filter(target -> existingTargetIds.contains(target.getControllerId())).collect(Collectors.toList());
|
||||
.filter(target -> existingTargetIds.contains(target.getControllerId())).toList();
|
||||
|
||||
final List<JpaAction> assignedActions = doAssignDistributionSetToTargets(initiatedBy,
|
||||
existingTargetsWithActionType, actionMessage, assignmentStrategy, distributionSetEntity,
|
||||
@@ -405,9 +441,9 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
/**
|
||||
* split tIDs length into max entries in-statement because many database
|
||||
* have constraint of max entries in in-statements e.g. Oracle with maximum
|
||||
* 1000 elements, so we need to split the entries here and execute multiple
|
||||
* split tIDs length into max entries in-statement because many database have
|
||||
* constraint of max entries in in-statements e.g. Oracle with maximum 1000
|
||||
* elements, so we need to split the entries here and execute multiple
|
||||
* statements
|
||||
*/
|
||||
private static List<List<Long>> getTargetEntitiesAsChunks(final List<JpaTarget> targetEntities) {
|
||||
@@ -422,13 +458,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return new DistributionSetAssignmentResult(distributionSet, alreadyAssignedTargetsCount, assignedActions);
|
||||
}
|
||||
|
||||
private void checkQuotaForAssignment(final Collection<DeploymentRequest> deploymentRequests) {
|
||||
if (!deploymentRequests.isEmpty()) {
|
||||
enforceMaxAssignmentsPerRequest(deploymentRequests.size());
|
||||
enforceMaxActionsPerTarget(deploymentRequests);
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceMaxAssignmentsPerRequest(final int requestedActions) {
|
||||
QuotaHelper.assertAssignmentRequestSizeQuota(requestedActions,
|
||||
quotaManagement.getMaxTargetDistributionSetAssignmentsPerManualAssignment());
|
||||
@@ -437,11 +466,11 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
private void enforceMaxActionsPerTarget(final Collection<DeploymentRequest> deploymentRequests) {
|
||||
final int quota = quotaManagement.getMaxActionsPerTarget();
|
||||
|
||||
final Map<String, Long> countOfTargtInRequest = deploymentRequests.stream()
|
||||
final Map<String, Long> countOfTargetInRequest = deploymentRequests.stream()
|
||||
.map(DeploymentRequest::getControllerId)
|
||||
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
|
||||
|
||||
countOfTargtInRequest.forEach((controllerId, count) -> QuotaHelper.assertAssignmentQuota(controllerId, count,
|
||||
countOfTargetInRequest.forEach((controllerId, count) -> QuotaHelper.assertAssignmentQuota(controllerId, count,
|
||||
quota, Action.class, Target.class, actionRepository::countByTargetControllerId));
|
||||
}
|
||||
|
||||
@@ -460,6 +489,11 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void cancelInactiveScheduledActionsForTargets(final List<Long> targetIds) {
|
||||
if (!isMultiAssignmentsEnabled()) {
|
||||
targetRepository.getAccessController().ifPresent(v -> {
|
||||
if (targetRepository.count(AccessController.Operation.UPDATE, TargetSpecifications.hasIdIn(targetIds)) != targetIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, targetIds);
|
||||
}
|
||||
});
|
||||
actionRepository.switchStatus(Status.CANCELED, targetIds, false, Status.SCHEDULED);
|
||||
} else {
|
||||
LOG.debug("The Multi Assignments feature is enabled: No need to cancel inactive scheduled actions.");
|
||||
@@ -494,7 +528,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
final JpaActionStatus actionStatus = assignmentStrategy.createActionStatus(action, actionMessage);
|
||||
verifyAndAddConfirmationStatus(action, actionStatus, entry.getKey().isConfirmationRequired());
|
||||
return actionStatus;
|
||||
}).collect(Collectors.toList()));
|
||||
}).toList());
|
||||
}
|
||||
|
||||
private void setInitialActionStatusOfRolloutGroup(final List<JpaAction> actions) {
|
||||
@@ -554,6 +588,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
throw new CancelActionNotAllowedException("Actions in canceling or canceled state cannot be canceled");
|
||||
}
|
||||
|
||||
assertTargetUpdateAllowed(action);
|
||||
|
||||
if (action.isActive()) {
|
||||
LOG.debug("action ({}) was still active. Change to {}.", action, Status.CANCELING);
|
||||
action.setStatus(Status.CANCELING);
|
||||
@@ -588,6 +624,8 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
throw new ForceQuitActionNotAllowedException(action.getId() + " is not active and cannot be force quit");
|
||||
}
|
||||
|
||||
assertTargetUpdateAllowed(action);
|
||||
|
||||
LOG.warn("action ({}) was still active and has been force quite.", action);
|
||||
|
||||
// document that the status has been retrieved
|
||||
@@ -738,93 +776,85 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
@Override
|
||||
public Optional<Action> findAction(final long actionId) {
|
||||
return actionRepository.findById(actionId).map(a -> a);
|
||||
return actionRepository
|
||||
.findById(actionId)
|
||||
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())))
|
||||
.map(JpaAction.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Action> findActionWithDetails(final long actionId) {
|
||||
return actionRepository.getActionById(actionId);
|
||||
return actionRepository
|
||||
.findWithDetailsById(actionId)
|
||||
.filter(action -> targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Action> findActionsByTarget(final String controllerId, final Pageable pageable) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
return actionRepository.findByTargetControllerId(pageable, controllerId);
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return actionRepository
|
||||
.findAll(ActionSpecifications.byTargetControllerId(controllerId), pageable)
|
||||
.map(Action.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Action> findActionsByTarget(final String rsqlParam, final String controllerId,
|
||||
final Pageable pageable) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
assertTargetReadAllowed(controllerId);
|
||||
|
||||
final List<Specification<JpaAction>> specList = Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database),
|
||||
byControllerIdSpec(controllerId));
|
||||
ActionSpecifications.byTargetControllerId(controllerId));
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(actionRepository, pageable, specList);
|
||||
}
|
||||
|
||||
private Specification<JpaAction> byControllerIdSpec(final String controllerId) {
|
||||
return (root, query, cb) -> cb.equal(root.get(JpaAction_.target).get(JpaTarget_.controllerId), controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Action> findActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
return actionRepository.findByActiveAndTarget(pageable, controllerId, true);
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return actionRepository
|
||||
.findAll(ActionSpecifications.byTargetControllerIdAndActive(controllerId, true), pageable)
|
||||
.map(Action.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Action> findInActiveActionsByTarget(final Pageable pageable, final String controllerId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
|
||||
return actionRepository.findByActiveAndTarget(pageable, controllerId, false);
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return actionRepository
|
||||
.findAll(ActionSpecifications.byTargetControllerIdAndActive(controllerId, false), pageable)
|
||||
.map(Action.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Action> findActiveActionsWithHighestWeight(final String controllerId, final int maxActionCount) {
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return findActiveActionsWithHighestWeightConsideringDefault(controllerId, maxActionCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeightConsideringDefault(final Action action) {
|
||||
return super.getWeightConsideringDefault(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsByTarget(final String controllerId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return actionRepository.countByTargetControllerId(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsByTarget(final String rsqlParam, final String controllerId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
assertTargetReadAllowed(controllerId);
|
||||
|
||||
final List<Specification<JpaAction>> specList = Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database),
|
||||
byControllerIdSpec(controllerId));
|
||||
ActionSpecifications.byTargetControllerId(controllerId));
|
||||
|
||||
return JpaManagementHelper.countBySpec(actionRepository, specList);
|
||||
}
|
||||
|
||||
private void throwExceptionIfTargetDoesNotExist(final String controllerId) {
|
||||
if (!targetRepository.exists(TargetSpecifications.hasControllerId(controllerId))) {
|
||||
throw new EntityNotFoundException(Target.class, controllerId);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwExceptionIfDistributionSetDoesNotExist(final Long dsId) {
|
||||
if (!distributionSetRepository.existsById(dsId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, dsId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Action forceTargetAction(final long actionId) {
|
||||
final JpaAction action = actionRepository.findById(actionId)
|
||||
.map(this::assertTargetUpdateAllowed)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
if (!action.isForcedOrTimeForced()) {
|
||||
@@ -836,24 +866,20 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
@Override
|
||||
public Page<ActionStatus> findActionStatusByAction(final Pageable pageReq, final long actionId) {
|
||||
verifyActionExists(actionId);
|
||||
assertActionExistsAndAccessible(actionId);
|
||||
|
||||
return actionStatusRepository.findByActionId(pageReq, actionId);
|
||||
}
|
||||
|
||||
private void verifyActionExists(final long actionId) {
|
||||
if (!actionRepository.existsById(actionId)) {
|
||||
throw new EntityNotFoundException(Action.class, actionId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionStatusByAction(final long actionId) {
|
||||
verifyActionExists(actionId);
|
||||
assertActionExistsAndAccessible(actionId);
|
||||
|
||||
return actionStatusRepository.countByActionId(actionId);
|
||||
}
|
||||
|
||||
// action is already got and there are checked read permissions - do not check permissions
|
||||
// and UI which is to be removed
|
||||
@Override
|
||||
public Page<String> findMessagesByActionStatusId(final Pageable pageable, final long actionStatusId) {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
@@ -883,16 +909,6 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return entityManager.createQuery(countMsgQuery).getSingleResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<ActionStatus> findActionStatusAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(actionStatusRepository, pageable, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionStatusAll() {
|
||||
return actionStatusRepository.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsAll() {
|
||||
return actionRepository.count();
|
||||
@@ -900,49 +916,37 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
@Override
|
||||
public long countActions(final String rsqlParam) {
|
||||
final List<Specification<JpaAction>> specList = Arrays.asList(
|
||||
final List<Specification<JpaAction>> specList = List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database));
|
||||
return JpaManagementHelper.countBySpec(actionRepository, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsByDistributionSetIdAndActiveIsTrue(final Long distributionSet) {
|
||||
return actionRepository.countByDistributionSetIdAndActiveIsTrue(distributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countActionsByDistributionSetIdAndActiveIsTrueAndStatusIsNot(final Long distributionSet,
|
||||
final Status status) {
|
||||
return actionRepository.countByDistributionSetIdAndActiveIsTrueAndStatusIsNot(distributionSet, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Action> findActionsByDistributionSet(final Pageable pageable, final long dsId) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(dsId);
|
||||
return actionRepository.findByDistributionSetId(pageable, dsId);
|
||||
}
|
||||
|
||||
// TODO - return via Mgmt API all actions (event for targets the use has no access - check if should and could
|
||||
// be limited
|
||||
@Override
|
||||
public Slice<Action> findActionsAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, pageable, null);
|
||||
}
|
||||
|
||||
// TODO - return via Mgmt API all actions (event for targets the use has no access - check if should and could
|
||||
// be limited
|
||||
@Override
|
||||
public Slice<Action> findActions(final String rsqlParam, final Pageable pageable) {
|
||||
final List<Specification<JpaAction>> specList = Arrays.asList(
|
||||
final List<Specification<JpaAction>> specList = List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, ActionFields.class, virtualPropertyReplacer, database));
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(actionRepository, pageable, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getAssignedDistributionSet(final String controllerId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
// target access checked in assertTargetReadAllowed
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return distributionSetRepository.findAssignedToTarget(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getInstalledDistributionSet(final String controllerId) {
|
||||
throwExceptionIfTargetDoesNotExist(controllerId);
|
||||
assertTargetReadAllowed(controllerId);
|
||||
return distributionSetRepository.findInstalledAtTarget(controllerId);
|
||||
}
|
||||
|
||||
@@ -953,10 +957,10 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* We use a native query here because Spring JPA does not support to
|
||||
* specify a LIMIT clause on a DELETE statement. However, for this
|
||||
* specific use case (action cleanup), we must specify a row limit to
|
||||
* reduce the overall load on the database.
|
||||
* We use a native query here because Spring JPA does not support to specify a
|
||||
* LIMIT clause on a DELETE statement. However, for this specific use case
|
||||
* (action cleanup), we must specify a row limit to reduce the overall load on
|
||||
* the database.
|
||||
*/
|
||||
|
||||
final int statusCount = status.size();
|
||||
@@ -976,9 +980,11 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPendingCancellations(final String controllerId) {
|
||||
return actionRepository.existsByTargetControllerIdAndStatusAndActiveIsTrue(controllerId,
|
||||
Action.Status.CANCELING);
|
||||
public boolean hasPendingCancellations(final Long targetId) {
|
||||
// target access checked in assertTargetReadAllowed
|
||||
assertTargetReadAllowed(targetId);
|
||||
return actionRepository.exists(
|
||||
ActionSpecifications.byTargetIdAndIsActiveAndStatus(targetId, Action.Status.CANCELING));
|
||||
}
|
||||
|
||||
private static String getQueryForDeleteActionsByStatusAndLastModifiedBeforeString(final Database database) {
|
||||
@@ -1033,18 +1039,59 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void cancelActionsForDistributionSet(final CancelationType cancelationType, final DistributionSet set) {
|
||||
actionRepository.findByDistributionSetAndActiveIsTrueAndStatusIsNot(set, Status.CANCELING).forEach(action -> {
|
||||
final JpaAction jpaAction = (JpaAction) action;
|
||||
cancelAction(jpaAction.getId());
|
||||
LOG.debug("Action {} canceled", jpaAction.getId());
|
||||
});
|
||||
public void cancelActionsForDistributionSet(
|
||||
final CancelationType cancelationType, final DistributionSet distributionSet) {
|
||||
actionRepository
|
||||
.findAll(ActionSpecifications.byDistributionSetIdAndActiveAndStatusIsNot(distributionSet.getId(), Status.CANCELING))
|
||||
.forEach(action -> {
|
||||
try {
|
||||
assertTargetUpdateAllowed(action);
|
||||
cancelAction(action.getId());
|
||||
LOG.debug("Action {} canceled", action.getId());
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
// no access - skip it
|
||||
}
|
||||
});
|
||||
if (cancelationType == CancelationType.FORCE) {
|
||||
actionRepository.findByDistributionSetAndActiveIsTrue(set).forEach(action -> {
|
||||
final JpaAction jpaAction = (JpaAction) action;
|
||||
forceQuitAction(jpaAction.getId());
|
||||
LOG.debug("Action {} force canceled", jpaAction.getId());
|
||||
});
|
||||
actionRepository
|
||||
.findAll(ActionSpecifications.byDistributionSetIdAndActive(distributionSet.getId()))
|
||||
.forEach(action -> {
|
||||
try {
|
||||
assertTargetUpdateAllowed(action);
|
||||
forceQuitAction(action.getId());
|
||||
LOG.debug("Action {} force canceled", action.getId());
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
// no access - skip it
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTargetReadAllowed(final Long targetId) {
|
||||
if (!targetRepository.existsById(targetId)) {
|
||||
throw new EntityNotFoundException(Target.class, targetId);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTargetReadAllowed(final String controllerId) {
|
||||
if (!targetRepository.exists(TargetSpecifications.hasControllerId(controllerId))) {
|
||||
throw new EntityNotFoundException(Target.class, controllerId);
|
||||
}
|
||||
}
|
||||
|
||||
private JpaAction assertTargetUpdateAllowed(final JpaAction action) {
|
||||
if (!targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId()))) {
|
||||
throw new EntityNotFoundException(Action.class, action);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
private void assertActionExistsAndAccessible(final long actionId) {
|
||||
if (actionRepository.findById(actionId).filter(action -> {
|
||||
assertTargetReadAllowed(action.getTarget().getId());
|
||||
return true;
|
||||
}).isEmpty()) {
|
||||
throw new EntityNotFoundException(Action.class, actionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -20,6 +20,7 @@ import org.eclipse.hawkbit.repository.RepositoryProperties;
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.StopRolloutException;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -44,20 +45,23 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
private final RolloutManagement rolloutManagement;
|
||||
private final DeploymentManagement deploymentManagement;
|
||||
private final TargetFilterQueryManagement targetFilterQueryManagement;
|
||||
private final ActionRepository actionRepository;
|
||||
private final PlatformTransactionManager txManager;
|
||||
private final RepositoryProperties repositoryProperties;
|
||||
private final TenantAware tenantAware;
|
||||
private final LockRegistry lockRegistry;
|
||||
|
||||
protected JpaDistributionSetInvalidationManagement(final DistributionSetManagement distributionSetManagement,
|
||||
public JpaDistributionSetInvalidationManagement(final DistributionSetManagement distributionSetManagement,
|
||||
final RolloutManagement rolloutManagement, final DeploymentManagement deploymentManagement,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final PlatformTransactionManager txManager,
|
||||
final TargetFilterQueryManagement targetFilterQueryManagement, final ActionRepository actionRepository,
|
||||
final PlatformTransactionManager txManager,
|
||||
final RepositoryProperties repositoryProperties, final TenantAware tenantAware,
|
||||
final LockRegistry lockRegistry) {
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.rolloutManagement = rolloutManagement;
|
||||
this.deploymentManagement = deploymentManagement;
|
||||
this.targetFilterQueryManagement = targetFilterQueryManagement;
|
||||
this.actionRepository = actionRepository;
|
||||
this.txManager = txManager;
|
||||
this.repositoryProperties = repositoryProperties;
|
||||
this.tenantAware = tenantAware;
|
||||
@@ -155,12 +159,11 @@ public class JpaDistributionSetInvalidationManagement implements DistributionSet
|
||||
}
|
||||
|
||||
private long countActionsForForcedInvalidation(final Collection<Long> setIds) {
|
||||
return setIds.stream().mapToLong(deploymentManagement::countActionsByDistributionSetIdAndActiveIsTrue).sum();
|
||||
return setIds.stream().mapToLong(actionRepository::countByDistributionSetIdAndActiveIsTrue).sum();
|
||||
}
|
||||
|
||||
private long countActionsForSoftInvalidation(final Collection<Long> setIds) {
|
||||
return setIds.stream().mapToLong(distributionSet -> deploymentManagement
|
||||
.countActionsByDistributionSetIdAndActiveIsTrueAndStatusIsNot(distributionSet, Status.CANCELING)).sum();
|
||||
return setIds.stream().mapToLong(distributionSet -> actionRepository
|
||||
.countByDistributionSetIdAndActiveIsTrueAndStatusIsNot(distributionSet, Status.CANCELING)).sum();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,13 +7,16 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -35,7 +38,10 @@ import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.IncompleteDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidDistributionSetException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
@@ -45,9 +51,16 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
@@ -73,7 +86,7 @@ import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -99,6 +112,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
private final DistributionSetMetadataRepository distributionSetMetadataRepository;
|
||||
private final TargetRepository targetRepository;
|
||||
|
||||
private final TargetFilterQueryRepository targetFilterQueryRepository;
|
||||
|
||||
@@ -118,17 +132,19 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
private final Database database;
|
||||
|
||||
JpaDistributionSetManagement(final EntityManager entityManager,
|
||||
public JpaDistributionSetManagement(final EntityManager entityManager,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final DistributionSetTagManagement distributionSetTagManagement, final SystemManagement systemManagement,
|
||||
final DistributionSetTypeManagement distributionSetTypeManagement, final QuotaManagement quotaManagement,
|
||||
final DistributionSetMetadataRepository distributionSetMetadataRepository,
|
||||
final TargetRepository targetRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository, final ActionRepository actionRepository,
|
||||
final EventPublisherHolder eventPublisherHolder, final TenantAware tenantAware,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final DistributionSetTagRepository distributionSetTagRepository,
|
||||
final AfterTransactionCommitExecutor afterCommit, final Database database) {
|
||||
final AfterTransactionCommitExecutor afterCommit,
|
||||
final Database database) {
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.distributionSetTagManagement = distributionSetTagManagement;
|
||||
@@ -136,6 +152,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
this.distributionSetTypeManagement = distributionSetTypeManagement;
|
||||
this.quotaManagement = quotaManagement;
|
||||
this.distributionSetMetadataRepository = distributionSetMetadataRepository;
|
||||
this.targetRepository = targetRepository;
|
||||
this.targetFilterQueryRepository = targetFilterQueryRepository;
|
||||
this.actionRepository = actionRepository;
|
||||
this.eventPublisherHolder = eventPublisherHolder;
|
||||
@@ -148,9 +165,8 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getWithDetails(final long distid) {
|
||||
return distributionSetRepository.findOne(DistributionSetSpecification.byId(distid))
|
||||
.map(DistributionSet.class::cast);
|
||||
public Optional<DistributionSet> getWithDetails(final long id) {
|
||||
return distributionSetRepository.findById(id).map(DistributionSet.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,66 +175,99 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
throw new EntityNotFoundException(DistributionSetType.class, typeId);
|
||||
}
|
||||
|
||||
return distributionSetRepository.countByTypeId(typeId);
|
||||
return distributionSetRepository.count(DistributionSetSpecification.byType(typeId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Statistic> countRolloutsByStatusForDistributionSet(Long dsId) {
|
||||
return distributionSetRepository.countRolloutsByStatusForDistributionSet(dsId).stream().map(Statistic.class::cast).collect(Collectors.toList());
|
||||
public List<Statistic> countRolloutsByStatusForDistributionSet(final Long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetRepository.countRolloutsByStatusForDistributionSet(id).stream()
|
||||
.map(Statistic.class::cast).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Statistic> countActionsByStatusForDistributionSet(Long dsId) {
|
||||
return distributionSetRepository.countActionsByStatusForDistributionSet(dsId).stream().map(Statistic.class::cast).collect(Collectors.toList());
|
||||
public List<Statistic> countActionsByStatusForDistributionSet(final Long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetRepository.countActionsByStatusForDistributionSet(id).stream()
|
||||
.map(Statistic.class::cast).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countAutoAssignmentsForDistributionSet(Long dsId) {
|
||||
return distributionSetRepository.countAutoAssignmentsForDistributionSet(dsId);
|
||||
public Long countAutoAssignmentsForDistributionSet(final Long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetRepository.countAutoAssignmentsForDistributionSet(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetTagAssignmentResult toggleTagAssignment(final Collection<Long> dsIds, final String tagName) {
|
||||
final List<JpaDistributionSet> sets = findDistributionSetListWithDetails(dsIds);
|
||||
public DistributionSetTagAssignmentResult toggleTagAssignment(final Collection<Long> ids, final String tagName) {
|
||||
return updateTags(
|
||||
ids,
|
||||
() -> distributionSetTagManagement
|
||||
.getByName(tagName)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName)),
|
||||
(allDs, distributionSetTag) -> {
|
||||
final List<JpaDistributionSet> toBeChangedDSs = allDs.stream().filter(set -> set.addTag(distributionSetTag))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (sets.size() < dsIds.size()) {
|
||||
final DistributionSetTagAssignmentResult result;
|
||||
// un-assignment case
|
||||
if (toBeChangedDSs.isEmpty()) {
|
||||
for (final JpaDistributionSet set : allDs) {
|
||||
if (set.removeTag(distributionSetTag)) {
|
||||
toBeChangedDSs.add(set);
|
||||
}
|
||||
}
|
||||
result = new DistributionSetTagAssignmentResult(ids.size() - toBeChangedDSs.size(),
|
||||
Collections.emptyList(),
|
||||
Collections.unmodifiableList(
|
||||
toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())),
|
||||
distributionSetTag);
|
||||
} else {
|
||||
result = new DistributionSetTagAssignmentResult(ids.size() - toBeChangedDSs.size(),
|
||||
Collections.unmodifiableList(
|
||||
toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())),
|
||||
Collections.emptyList(), distributionSetTag);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSet> assignTag(final Collection<Long> ids, final long dsTagId) {
|
||||
return updateTags(
|
||||
ids,
|
||||
() -> distributionSetTagManagement.get(dsTagId).orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, dsTagId)),
|
||||
(allDs, distributionSetTag) -> {
|
||||
allDs.forEach(ds -> ds.addTag(distributionSetTag));
|
||||
return Collections.unmodifiableList(distributionSetRepository.saveAll(allDs));
|
||||
});
|
||||
}
|
||||
|
||||
private <T> T updateTags(
|
||||
final Collection<Long> dsIds, final Supplier<DistributionSetTag> tagSupplier,
|
||||
final BiFunction<List<JpaDistributionSet>, DistributionSetTag, T> updater) {
|
||||
final List<JpaDistributionSet> allDs = findDistributionSetListWithDetails(dsIds);
|
||||
if (allDs.size() < dsIds.size()) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, dsIds,
|
||||
sets.stream().map(DistributionSet::getId).collect(Collectors.toList()));
|
||||
allDs.stream().map(DistributionSet::getId).toList());
|
||||
}
|
||||
|
||||
final DistributionSetTag myTag = distributionSetTagManagement.getByName(tagName)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName));
|
||||
|
||||
DistributionSetTagAssignmentResult result;
|
||||
|
||||
final List<JpaDistributionSet> toBeChangedDSs = sets.stream().filter(set -> set.addTag(myTag))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// un-assignment case
|
||||
if (toBeChangedDSs.isEmpty()) {
|
||||
for (final JpaDistributionSet set : sets) {
|
||||
if (set.removeTag(myTag)) {
|
||||
toBeChangedDSs.add(set);
|
||||
}
|
||||
}
|
||||
result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(),
|
||||
Collections.emptyList(),
|
||||
Collections.unmodifiableList(
|
||||
toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())),
|
||||
myTag);
|
||||
} else {
|
||||
result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(),
|
||||
Collections.unmodifiableList(
|
||||
toBeChangedDSs.stream().map(distributionSetRepository::save).collect(Collectors.toList())),
|
||||
Collections.emptyList(), myTag);
|
||||
final DistributionSetTag distributionSetTag = tagSupplier.get();
|
||||
try {
|
||||
return updater.apply(allDs, distributionSetTag);
|
||||
} finally {
|
||||
// No reason to save the tag
|
||||
entityManager.detach(distributionSetTag);
|
||||
}
|
||||
|
||||
// no reason to persist the tag
|
||||
entityManager.detach(myTag);
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<JpaDistributionSet> findDistributionSetListWithDetails(final Collection<Long> distributionIdSet) {
|
||||
@@ -247,9 +296,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
return distributionSetRepository.save(set);
|
||||
}
|
||||
|
||||
private JpaSoftwareModule findSoftwareModuleAndThrowExceptionIfNotFound(final Long moduleId) {
|
||||
return softwareModuleRepository.findById(moduleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, moduleId));
|
||||
private JpaSoftwareModule findSoftwareModuleAndThrowExceptionIfNotFound(final Long softwareModuleId) {
|
||||
return softwareModuleRepository.findById(softwareModuleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, softwareModuleId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,11 +306,11 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> distributionSetIDs) {
|
||||
final List<DistributionSet> setsFound = get(distributionSetIDs);
|
||||
|
||||
getDistributionSets(distributionSetIDs); // throws EntityNotFoundException if any of these do not exists
|
||||
final List<JpaDistributionSet> setsFound = distributionSetRepository.findAll(
|
||||
AccessController.Operation.DELETE, distributionSetRepository.byIdsSpec(distributionSetIDs));
|
||||
if (setsFound.size() < distributionSetIDs.size()) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, distributionSetIDs,
|
||||
setsFound.stream().map(DistributionSet::getId).collect(Collectors.toList()));
|
||||
throw new InsufficientPermissionException("No DELETE access to some of distribution sets!");
|
||||
}
|
||||
|
||||
final List<Long> assigned = distributionSetRepository
|
||||
@@ -270,22 +319,21 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
// soft delete assigned
|
||||
if (!assigned.isEmpty()) {
|
||||
final Long[] dsIds = assigned.toArray(new Long[assigned.size()]);
|
||||
final Long[] dsIds = assigned.toArray(new Long[0]);
|
||||
distributionSetRepository.deleteDistributionSet(dsIds);
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionType(dsIds);
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(dsIds);
|
||||
}
|
||||
|
||||
// mark the rest as hard delete
|
||||
final List<Long> toHardDelete = distributionSetIDs.stream().filter(setId -> !assigned.contains(setId))
|
||||
.collect(Collectors.toList());
|
||||
final List<Long> toHardDelete = distributionSetIDs.stream().filter(setId -> !assigned.contains(setId)).toList();
|
||||
|
||||
// hard delete the rest if exists
|
||||
if (!toHardDelete.isEmpty()) {
|
||||
targetFilterQueryRepository
|
||||
.unsetAutoAssignDistributionSetAndActionType(toHardDelete.toArray(new Long[toHardDelete.size()]));
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(
|
||||
toHardDelete.toArray(new Long[0]));
|
||||
// don't give the delete statement an empty list, JPA/Oracle cannot
|
||||
// handle the empty list
|
||||
distributionSetRepository.deleteByIdIn(toHardDelete);
|
||||
distributionSetRepository.deleteAllById(toHardDelete);
|
||||
}
|
||||
|
||||
afterCommit.afterCommit(() -> distributionSetIDs.forEach(dsId -> eventPublisherHolder.getEventPublisher()
|
||||
@@ -299,11 +347,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet create(final DistributionSetCreate c) {
|
||||
final JpaDistributionSetCreate create = (JpaDistributionSetCreate) c;
|
||||
if (create.getType() == null) {
|
||||
create.type(systemManagement.getTenantMetadata().getDefaultDsType().getKey());
|
||||
}
|
||||
setDefaultTypeIfMissing(create);
|
||||
|
||||
return distributionSetRepository.save(create.build());
|
||||
return distributionSetRepository.save(AccessController.Operation.CREATE, create.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -311,28 +357,34 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSet> create(final Collection<DistributionSetCreate> creates) {
|
||||
return creates.stream().map(this::create).collect(Collectors.toList());
|
||||
final List<JpaDistributionSet> toCreate = creates.stream().map(JpaDistributionSetCreate.class::cast)
|
||||
.map(this::setDefaultTypeIfMissing).map(JpaDistributionSetCreate::build).toList();
|
||||
|
||||
return Collections.unmodifiableList(distributionSetRepository.saveAll(AccessController.Operation.CREATE, toCreate));
|
||||
}
|
||||
|
||||
private JpaDistributionSetCreate setDefaultTypeIfMissing(final JpaDistributionSetCreate create) {
|
||||
if (create.getType() == null) {
|
||||
create.type(systemManagement.getTenantMetadata().getDefaultDsType().getKey());
|
||||
}
|
||||
return create;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet assignSoftwareModules(final long setId, final Collection<Long> moduleIds) {
|
||||
public DistributionSet assignSoftwareModules(final long id, final Collection<Long> softwareModuleId) {
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(id);
|
||||
assertDistributionSetIsNotAssignedToTargets(id);
|
||||
assertSoftwareModuleQuota(id, softwareModuleId.size());
|
||||
|
||||
final Collection<JpaSoftwareModule> modules = softwareModuleRepository.findByIdIn(moduleIds);
|
||||
|
||||
if (modules.size() < moduleIds.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, moduleIds,
|
||||
modules.stream().map(SoftwareModule::getId).collect(Collectors.toList()));
|
||||
final Collection<JpaSoftwareModule> modules = softwareModuleRepository.findAllById(softwareModuleId);
|
||||
if (modules.size() < softwareModuleId.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, softwareModuleId,
|
||||
modules.stream().map(SoftwareModule::getId).toList());
|
||||
}
|
||||
|
||||
assertDistributionSetIsNotAssignedToTargets(setId);
|
||||
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(setId);
|
||||
|
||||
assertSoftwareModuleQuota(setId, modules.size());
|
||||
|
||||
modules.forEach(set::addModule);
|
||||
|
||||
return distributionSetRepository.save(set);
|
||||
@@ -342,12 +394,11 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet unassignSoftwareModule(final long setId, final long moduleId) {
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(setId);
|
||||
public DistributionSet unassignSoftwareModule(final long id, final long moduleId) {
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getValid(id);
|
||||
assertDistributionSetIsNotAssignedToTargets(id);
|
||||
|
||||
final JpaSoftwareModule module = findSoftwareModuleAndThrowExceptionIfNotFound(moduleId);
|
||||
|
||||
assertDistributionSetIsNotAssignedToTargets(setId);
|
||||
|
||||
set.removeModule(module);
|
||||
|
||||
return distributionSetRepository.save(set);
|
||||
@@ -372,20 +423,25 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSet> findByCompleted(final Pageable pageReq, final Boolean complete) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, pageReq,
|
||||
buildSpecsByComplete(complete));
|
||||
}
|
||||
final List<Specification<JpaDistributionSet>> specifications = buildSpecsByComplete(complete);
|
||||
|
||||
private List<Specification<JpaDistributionSet>> buildSpecsByComplete(final Boolean complete) {
|
||||
return complete != null
|
||||
? Arrays.asList(DistributionSetSpecification.isDeleted(false),
|
||||
DistributionSetSpecification.isCompleted(complete))
|
||||
: Collections.singletonList(DistributionSetSpecification.isDeleted(false));
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, pageReq, specifications);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByCompleted(final Boolean complete) {
|
||||
return JpaManagementHelper.countBySpec(distributionSetRepository, buildSpecsByComplete(complete));
|
||||
final List<Specification<JpaDistributionSet>> specifications = buildSpecsByComplete(complete);
|
||||
|
||||
return JpaManagementHelper.countBySpec(distributionSetRepository, specifications);
|
||||
}
|
||||
|
||||
private List<Specification<JpaDistributionSet>> buildSpecsByComplete(final Boolean complete) {
|
||||
final List<Specification<JpaDistributionSet>> specifications = new ArrayList<>();
|
||||
specifications.add(DistributionSetSpecification.isNotDeleted());
|
||||
if (complete != null) {
|
||||
specifications.add(DistributionSetSpecification.isCompleted(complete));
|
||||
}
|
||||
return specifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -404,37 +460,34 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getByNameAndVersion(final String distributionName, final String version) {
|
||||
final Specification<JpaDistributionSet> spec = DistributionSetSpecification
|
||||
.equalsNameAndVersionIgnoreCase(distributionName, version);
|
||||
return distributionSetRepository.findOne(spec).map(DistributionSet.class::cast);
|
||||
return distributionSetRepository
|
||||
.findOne(DistributionSetSpecification.equalsNameAndVersionIgnoreCase(distributionName, version))
|
||||
.map(DistributionSet.class::cast);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
final Specification<JpaDistributionSet> spec = DistributionSetSpecification.isDeleted(Boolean.FALSE);
|
||||
|
||||
return distributionSetRepository.count(SpecificationsBuilder.combineWithAnd(Arrays.asList(spec)));
|
||||
return distributionSetRepository.count(DistributionSetSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSetMetadata> createMetaData(final long dsId, final Collection<MetaData> md) {
|
||||
public List<DistributionSetMetadata> createMetaData(final long id, final Collection<MetaData> md) {
|
||||
final JpaDistributionSet distributionSet = (JpaDistributionSet)getValid(id);
|
||||
assertMetaDataQuota(id, md.size());
|
||||
|
||||
md.forEach(meta -> checkAndThrowIfDistributionSetMetadataAlreadyExists(
|
||||
new DsMetadataCompositeKey(dsId, meta.getKey())));
|
||||
new DsMetadataCompositeKey(id, meta.getKey())));
|
||||
|
||||
assertMetaDataQuota(dsId, md.size());
|
||||
JpaManagementHelper.touch(entityManager, distributionSetRepository, distributionSet);
|
||||
|
||||
final JpaDistributionSet set = JpaManagementHelper.touch(entityManager, distributionSetRepository,
|
||||
(JpaDistributionSet) getValid(dsId));
|
||||
|
||||
return Collections.unmodifiableList(md.stream()
|
||||
return md.stream()
|
||||
.map(meta -> distributionSetMetadataRepository
|
||||
.save(new JpaDistributionSetMetadata(meta.getKey(), set, meta.getValue())))
|
||||
.collect(Collectors.toList()));
|
||||
.save(new JpaDistributionSetMetadata(meta.getKey(), distributionSet, meta.getValue())))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
private void assertMetaDataQuota(final Long dsId, final int requested) {
|
||||
@@ -452,16 +505,16 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetMetadata updateMetaData(final long dsId, final MetaData md) {
|
||||
|
||||
public DistributionSetMetadata updateMetaData(final long id, final MetaData md) {
|
||||
// check if exists otherwise throw entity not found exception
|
||||
final JpaDistributionSetMetadata toUpdate = (JpaDistributionSetMetadata) getMetaDataByDistributionSetId(dsId,
|
||||
md.getKey()).orElseThrow(
|
||||
() -> new EntityNotFoundException(DistributionSetMetadata.class, dsId, md.getKey()));
|
||||
final JpaDistributionSetMetadata toUpdate = (JpaDistributionSetMetadata) getMetaDataByDistributionSetId(id,
|
||||
md.getKey())
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetMetadata.class, id, md.getKey()));
|
||||
toUpdate.setValue(md.getValue());
|
||||
|
||||
// touch it to update the lock revision because we are modifying the
|
||||
// DS indirectly
|
||||
JpaManagementHelper.touch(entityManager, distributionSetRepository, (JpaDistributionSet) getValid(dsId));
|
||||
// DS indirectly, it will, also check UPDATE access
|
||||
JpaManagementHelper.touch(entityManager, distributionSetRepository, (JpaDistributionSet) getValid(id));
|
||||
return distributionSetMetadataRepository.save(toUpdate);
|
||||
}
|
||||
|
||||
@@ -469,11 +522,13 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void deleteMetaData(final long distributionSetId, final String key) {
|
||||
public void deleteMetaData(final long id, final String key) {
|
||||
final JpaDistributionSetMetadata metadata = (JpaDistributionSetMetadata) getMetaDataByDistributionSetId(
|
||||
distributionSetId, key).orElseThrow(
|
||||
() -> new EntityNotFoundException(DistributionSetMetadata.class, distributionSetId, key));
|
||||
id, key)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetMetadata.class, id, key));
|
||||
|
||||
// touch it to update the lock revision because we are modifying the
|
||||
// DS indirectly, it will, also check UPDATE access
|
||||
JpaManagementHelper.touch(entityManager, distributionSetRepository,
|
||||
(JpaDistributionSet) metadata.getDistributionSet());
|
||||
distributionSetMetadataRepository.deleteById(metadata.getId());
|
||||
@@ -481,11 +536,11 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetMetadata> findMetaDataByDistributionSetId(final Pageable pageable,
|
||||
final long distributionSetId) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(distributionSetId);
|
||||
final long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetMetadataRepository, pageable,
|
||||
Collections.singletonList(byDsIdSpec(distributionSetId)));
|
||||
Collections.singletonList(byDsIdSpec(id)));
|
||||
}
|
||||
|
||||
private Specification<JpaDistributionSetMetadata> byDsIdSpec(final long dsId) {
|
||||
@@ -494,51 +549,62 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countMetaDataByDistributionSetId(final long setId) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(setId);
|
||||
public long countMetaDataByDistributionSetId(final long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetMetadataRepository.countByDistributionSetId(setId);
|
||||
return distributionSetMetadataRepository.countByDistributionSetId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetMetadata> findMetaDataByDistributionSetIdAndRsql(final Pageable pageable,
|
||||
final long distributionSetId, final String rsqlParam) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(distributionSetId);
|
||||
final long id, final String rsqlParam) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
final List<Specification<JpaDistributionSetMetadata>> specList = Arrays
|
||||
.asList(RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetMetadataFields.class,
|
||||
virtualPropertyReplacer, database), byDsIdSpec(distributionSetId));
|
||||
virtualPropertyReplacer, database), byDsIdSpec(id));
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetMetadataRepository, pageable, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetMetadata> getMetaDataByDistributionSetId(final long setId, final String key) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(setId);
|
||||
public Optional<DistributionSetMetadata> getMetaDataByDistributionSetId(final long id, final String key) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return distributionSetMetadataRepository.findById(new DsMetadataCompositeKey(setId, key))
|
||||
return distributionSetMetadataRepository
|
||||
.findById(new DsMetadataCompositeKey(id, key))
|
||||
.map(DistributionSetMetadata.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> getByAction(final long actionId) {
|
||||
if (!actionRepository.existsById(actionId)) {
|
||||
throw new EntityNotFoundException(Action.class, actionId);
|
||||
}
|
||||
|
||||
return Optional.ofNullable(distributionSetRepository.findByActionId(actionId));
|
||||
return actionRepository
|
||||
.findById(actionId)
|
||||
.map(action -> {
|
||||
if (!targetRepository.exists(TargetSpecifications.hasId(action.getTarget().getId()))) {
|
||||
throw new InsufficientPermissionException("Target not accessible (or not found)!");
|
||||
}
|
||||
return distributionSetRepository
|
||||
.findOne(DistributionSetSpecification.byActionId(actionId))
|
||||
.orElseThrow(() ->
|
||||
new InsufficientPermissionException("DistributionSet not accessible (or not found)!"));
|
||||
})
|
||||
.map(DistributionSet.class::cast)
|
||||
.or(() -> {
|
||||
throw new EntityNotFoundException(Action.class, actionId);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInUse(final long setId) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(setId);
|
||||
public boolean isInUse(final long id) {
|
||||
assertDistributionSetExists(id);
|
||||
|
||||
return actionRepository.countByDistributionSetId(setId) > 0;
|
||||
return actionRepository.countByDistributionSetId(id) > 0;
|
||||
}
|
||||
|
||||
private static List<Specification<JpaDistributionSet>> buildDistributionSetSpecifications(
|
||||
final DistributionSetFilter distributionSetFilter) {
|
||||
final List<Specification<JpaDistributionSet>> specList = Lists.newArrayListWithExpectedSize(9);
|
||||
final List<Specification<JpaDistributionSet>> specList = Lists.newArrayListWithExpectedSize(10);
|
||||
|
||||
Specification<JpaDistributionSet> spec;
|
||||
|
||||
@@ -562,7 +628,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
specList.add(spec);
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(distributionSetFilter.getSearchText())) {
|
||||
if (!ObjectUtils.isEmpty(distributionSetFilter.getSearchText())) {
|
||||
final String[] dsFilterNameAndVersionEntries = JpaManagementHelper
|
||||
.getFilterNameAndVersionEntries(distributionSetFilter.getSearchText().trim());
|
||||
spec = DistributionSetSpecification.likeNameAndVersion(dsFilterNameAndVersionEntries[0],
|
||||
@@ -611,38 +677,12 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSet> assignTag(final Collection<Long> dsIds, final long dsTagId) {
|
||||
final List<JpaDistributionSet> allDs = findDistributionSetListWithDetails(dsIds);
|
||||
|
||||
if (allDs.size() < dsIds.size()) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, dsIds,
|
||||
allDs.stream().map(DistributionSet::getId).collect(Collectors.toList()));
|
||||
}
|
||||
public DistributionSet unAssignTag(final long id, final long dsTagId) {
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getWithDetails(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id));
|
||||
|
||||
final DistributionSetTag distributionSetTag = distributionSetTagManagement.get(dsTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, dsTagId));
|
||||
|
||||
allDs.forEach(ds -> ds.addTag(distributionSetTag));
|
||||
|
||||
final List<DistributionSet> result = Collections
|
||||
.unmodifiableList(allDs.stream().map(distributionSetRepository::save).collect(Collectors.toList()));
|
||||
|
||||
// No reason to save the tag
|
||||
entityManager.detach(distributionSetTag);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSet unAssignTag(final long dsId, final long dsTagId) {
|
||||
final JpaDistributionSet set = (JpaDistributionSet) getWithDetails(dsId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, dsId));
|
||||
|
||||
final DistributionSetTag distributionSetTag = distributionSetTagManagement.get(dsTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, dsTagId));
|
||||
|
||||
set.removeTag(distributionSetTag);
|
||||
|
||||
final JpaDistributionSet result = distributionSetRepository.save(set);
|
||||
@@ -656,69 +696,59 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long setId) {
|
||||
throwExceptionIfDistributionSetDoesNotExist(setId);
|
||||
|
||||
delete(Collections.singletonList(setId));
|
||||
}
|
||||
|
||||
private void throwExceptionIfDistributionSetDoesNotExist(final Long setId) {
|
||||
if (!distributionSetRepository.existsById(setId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, setId);
|
||||
}
|
||||
public void delete(final long id) {
|
||||
delete(List.of(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DistributionSet> get(final Collection<Long> ids) {
|
||||
return Collections.unmodifiableList(distributionSetRepository.findAllById(ids));
|
||||
return Collections.unmodifiableList(getDistributionSets(ids));
|
||||
}
|
||||
|
||||
private List<JpaDistributionSet> getDistributionSets(final Collection<Long> ids) {
|
||||
final List<JpaDistributionSet> foundDs = distributionSetRepository.findAllById(ids);
|
||||
if (foundDs.size() != ids.size()) {
|
||||
throw new EntityNotFoundException(
|
||||
DistributionSet.class, ids, foundDs.stream().map(JpaDistributionSet::getId).toList());
|
||||
}
|
||||
return foundDs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSet> findByTag(final Pageable pageable, final long tagId) {
|
||||
throwEntityNotFoundExceptionIfDsTagDoesNotExist(tagId);
|
||||
assertDsTagExists(tagId);
|
||||
|
||||
return JpaManagementHelper.convertPage(distributionSetRepository.findByTag(pageable, tagId), pageable);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void throwEntityNotFoundExceptionIfDsTagDoesNotExist(final Long tagId) {
|
||||
if (!distributionSetTagRepository.existsById(tagId)) {
|
||||
throw new EntityNotFoundException(DistributionSetTag.class, tagId);
|
||||
}
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, pageable, List.of(
|
||||
DistributionSetSpecification.hasTag(tagId)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSet> findByRsqlAndTag(final Pageable pageable, final String rsqlParam, final long tagId) {
|
||||
throwEntityNotFoundExceptionIfDsTagDoesNotExist(tagId);
|
||||
assertDsTagExists(tagId);
|
||||
|
||||
final List<Specification<JpaDistributionSet>> specList = Arrays.asList(
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, pageable, List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isDeleted(false));
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, pageable, specList);
|
||||
DistributionSetSpecification.hasTag(tagId), DistributionSetSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSet> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, pageable,
|
||||
Collections.singletonList(DistributionSetSpecification.isDeleted(false)));
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetRepository, pageable, List.of(
|
||||
DistributionSetSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSet> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||
final List<Specification<JpaDistributionSet>> specList = Arrays.asList(RSQLUtility
|
||||
.buildRsqlSpecification(rsqlParam, DistributionSetFields.class, virtualPropertyReplacer, database),
|
||||
DistributionSetSpecification.isDeleted(false));
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, pageable, specList);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetRepository, pageable, List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
DistributionSetSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSet> get(final long id) {
|
||||
return distributionSetRepository.findById(id).map(d -> d);
|
||||
return distributionSetRepository.findById(id).map(DistributionSet.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -728,7 +758,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
public DistributionSet getOrElseThrowException(final long id) {
|
||||
return get(id).orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id));
|
||||
return getById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -757,10 +787,27 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void invalidate(final DistributionSet set) {
|
||||
final JpaDistributionSet jpaSet = (JpaDistributionSet) set;
|
||||
public void invalidate(final DistributionSet distributionSet) {
|
||||
final JpaDistributionSet jpaSet = (JpaDistributionSet) distributionSet;
|
||||
jpaSet.invalidate();
|
||||
distributionSetRepository.save(jpaSet);
|
||||
distributionSetRepository.save(AccessController.Operation.DELETE, jpaSet);
|
||||
}
|
||||
|
||||
private JpaDistributionSet getById(final long id) {
|
||||
return distributionSetRepository
|
||||
.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSet.class, id));
|
||||
}
|
||||
|
||||
private void assertDistributionSetExists(final long id) {
|
||||
if (!distributionSetRepository.existsById(id)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, id);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertDsTagExists(final Long tagId) {
|
||||
if (!distributionSetTagRepository.existsById(tagId)) {
|
||||
throw new EntityNotFoundException(DistributionSetTag.class, tagId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -17,16 +17,21 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagFields;
|
||||
import org.eclipse.hawkbit.repository.DistributionSetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.TagFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTagUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTagSpecifications;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
@@ -58,7 +63,7 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
||||
|
||||
private final Database database;
|
||||
|
||||
JpaDistributionSetTagManagement(final DistributionSetTagRepository distributionSetTagRepository,
|
||||
public JpaDistributionSetTagManagement(final DistributionSetTagRepository distributionSetTagRepository,
|
||||
final DistributionSetRepository distributionSetRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
|
||||
this.distributionSetTagRepository = distributionSetTagRepository;
|
||||
@@ -95,7 +100,7 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetTag create(final TagCreate c) {
|
||||
final JpaTagCreate create = (JpaTagCreate) c;
|
||||
return distributionSetTagRepository.save(create.buildDistributionSetTag());
|
||||
return distributionSetTagRepository.save(AccessController.Operation.CREATE, create.buildDistributionSetTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,13 +108,10 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSetTag> create(final Collection<TagCreate> dst) {
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
final Collection<JpaTagCreate> creates = (Collection) dst;
|
||||
|
||||
return Collections.unmodifiableList(
|
||||
creates.stream().map(create -> distributionSetTagRepository.save(create.buildDistributionSetTag()))
|
||||
.collect(Collectors.toList()));
|
||||
final List<JpaDistributionSetTag> toCreate = dst.stream().map(JpaTagCreate.class::cast)
|
||||
.map(JpaTagCreate::buildDistributionSetTag).toList();
|
||||
return Collections
|
||||
.unmodifiableList(distributionSetTagRepository.saveAll(AccessController.Operation.CREATE, toCreate));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,11 +119,11 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final String tagName) {
|
||||
if (!distributionSetTagRepository.existsByName(tagName)) {
|
||||
throw new EntityNotFoundException(DistributionSetTag.class, tagName);
|
||||
}
|
||||
final JpaDistributionSetTag dsTag = distributionSetTagRepository
|
||||
.findOne(DistributionSetTagSpecifications.byName(tagName))
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetTag.class, tagName));
|
||||
|
||||
distributionSetTagRepository.deleteByName(tagName);
|
||||
distributionSetTagRepository.delete(dsTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,13 +141,13 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetTag> findByDistributionSet(final Pageable pageable, final long setId) {
|
||||
if (!distributionSetRepository.existsById(setId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, setId);
|
||||
public Page<DistributionSetTag> findByDistributionSet(final Pageable pageable, final long distributionSetId) {
|
||||
if (!distributionSetRepository.existsById(distributionSetId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
||||
}
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTagRepository, pageable,
|
||||
Collections.singletonList(TagSpecification.ofDistributionSet(setId)));
|
||||
Collections.singletonList(TagSpecification.ofDistributionSet(distributionSetId)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,5 +192,4 @@ public class JpaDistributionSetTagManagement implements DistributionSetTagManage
|
||||
public long count() {
|
||||
return distributionSetTagRepository.count();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,9 +7,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -29,11 +28,17 @@ import org.eclipse.hawkbit.repository.builder.GenericDistributionSetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaDistributionSetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.DistributionSetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
@@ -73,7 +78,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
JpaDistributionSetTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
public JpaDistributionSetTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final DistributionSetRepository distributionSetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
|
||||
@@ -100,7 +105,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
update.getColour().ifPresent(type::setColour);
|
||||
|
||||
if (hasModuleChanges(update)) {
|
||||
checkDistributionSetTypeSoftwareModuleTypesIsAllowedToModify(update.getId());
|
||||
checkDistributionSetTypeNotAssigned(update.getId());
|
||||
|
||||
final Collection<Long> currentMandatorySmTypeIds = type.getMandatoryModuleTypes().stream()
|
||||
.map(SoftwareModuleType::getId).collect(Collectors.toSet());
|
||||
@@ -148,45 +153,35 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType assignMandatorySoftwareModuleTypes(final long dsTypeId,
|
||||
final Collection<Long> softwareModulesTypeIds) {
|
||||
final Collection<JpaSoftwareModuleType> modules = softwareModuleTypeRepository
|
||||
.findAllById(softwareModulesTypeIds);
|
||||
|
||||
if (modules.size() < softwareModulesTypeIds.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModuleType.class, softwareModulesTypeIds,
|
||||
modules.stream().map(SoftwareModuleType::getId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(dsTypeId);
|
||||
checkDistributionSetTypeSoftwareModuleTypesIsAllowedToModify(dsTypeId);
|
||||
assertSoftwareModuleTypeQuota(dsTypeId, softwareModulesTypeIds.size());
|
||||
|
||||
modules.forEach(type::addMandatoryModuleType);
|
||||
|
||||
return distributionSetTypeRepository.save(type);
|
||||
public DistributionSetType assignMandatorySoftwareModuleTypes(final long id,
|
||||
final Collection<Long> softwareModuleTypeIds) {
|
||||
return assignSoftwareModuleTypes(id, softwareModuleTypeIds, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType assignOptionalSoftwareModuleTypes(final long dsTypeId,
|
||||
public DistributionSetType assignOptionalSoftwareModuleTypes(final long id,
|
||||
final Collection<Long> softwareModulesTypeIds) {
|
||||
return assignSoftwareModuleTypes(id, softwareModulesTypeIds, false);
|
||||
}
|
||||
|
||||
final Collection<JpaSoftwareModuleType> modules = softwareModuleTypeRepository
|
||||
.findAllById(softwareModulesTypeIds);
|
||||
|
||||
if (modules.size() < softwareModulesTypeIds.size()) {
|
||||
private DistributionSetType assignSoftwareModuleTypes(
|
||||
final long dsTypeId, final Collection<Long> softwareModulesTypeIds, final boolean mandatory) {
|
||||
final Collection<JpaSoftwareModuleType> foundModules =
|
||||
softwareModuleTypeRepository.findAllById(softwareModulesTypeIds);
|
||||
if (foundModules.size() < softwareModulesTypeIds.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModuleType.class, softwareModulesTypeIds,
|
||||
modules.stream().map(SoftwareModuleType::getId).collect(Collectors.toList()));
|
||||
foundModules.stream().map(SoftwareModuleType::getId).toList());
|
||||
}
|
||||
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(dsTypeId);
|
||||
checkDistributionSetTypeSoftwareModuleTypesIsAllowedToModify(dsTypeId);
|
||||
|
||||
checkDistributionSetTypeNotAssigned(dsTypeId);
|
||||
assertSoftwareModuleTypeQuota(dsTypeId, softwareModulesTypeIds.size());
|
||||
|
||||
modules.forEach(type::addOptionalModuleType);
|
||||
foundModules.forEach(mandatory ? type::addMandatoryModuleType : type::addOptionalModuleType);
|
||||
|
||||
return distributionSetTypeRepository.save(type);
|
||||
}
|
||||
@@ -213,10 +208,10 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType unassignSoftwareModuleType(final long dsTypeId, final long softwareModuleTypeId) {
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(dsTypeId);
|
||||
public DistributionSetType unassignSoftwareModuleType(final long id, final long softwareModuleTypeId) {
|
||||
final JpaDistributionSetType type = findDistributionSetTypeAndThrowExceptionIfNotFound(id);
|
||||
|
||||
checkDistributionSetTypeSoftwareModuleTypesIsAllowedToModify(dsTypeId);
|
||||
checkDistributionSetTypeNotAssigned(id);
|
||||
|
||||
type.removeModuleType(softwareModuleTypeId);
|
||||
|
||||
@@ -225,35 +220,33 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
@Override
|
||||
public Page<DistributionSetType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||
return JpaManagementHelper
|
||||
.findAllWithCountBySpec(distributionSetTypeRepository, pageable,
|
||||
Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTypeFields.class,
|
||||
virtualPropertyReplacer, database),
|
||||
DistributionSetTypeSpecification.isDeleted(false)));
|
||||
return JpaManagementHelper.findAllWithCountBySpec(distributionSetTypeRepository, pageable, List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, DistributionSetTypeFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
DistributionSetTypeSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<DistributionSetType> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTypeRepository, pageable,
|
||||
Collections.singletonList(DistributionSetTypeSpecification.isDeleted(false)));
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(distributionSetTypeRepository, pageable, List.of(
|
||||
DistributionSetTypeSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return distributionSetTypeRepository.countByDeleted(false);
|
||||
return distributionSetTypeRepository.count(DistributionSetTypeSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> getByName(final String name) {
|
||||
return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byName(name))
|
||||
.map(dst -> (DistributionSetType) dst);
|
||||
return distributionSetTypeRepository
|
||||
.findOne(DistributionSetTypeSpecification.byName(name)).map(DistributionSetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> getByKey(final String key) {
|
||||
return distributionSetTypeRepository.findOne(DistributionSetTypeSpecification.byKey(key))
|
||||
.map(dst -> (DistributionSetType) dst);
|
||||
return distributionSetTypeRepository
|
||||
.findOne(DistributionSetTypeSpecification.byKey(key)).map(DistributionSetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -261,26 +254,26 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public DistributionSetType create(final DistributionSetTypeCreate c) {
|
||||
final JpaDistributionSetTypeCreate create = (JpaDistributionSetTypeCreate) c;
|
||||
final JpaDistributionSetType distributionSetType = ((JpaDistributionSetTypeCreate) c).build();
|
||||
|
||||
return distributionSetTypeRepository.save(create.build());
|
||||
return distributionSetTypeRepository.save(AccessController.Operation.CREATE, distributionSetType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long typeId) {
|
||||
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(typeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, typeId));
|
||||
public void delete(final long id) {
|
||||
final JpaDistributionSetType toDelete = distributionSetTypeRepository.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, id));
|
||||
|
||||
unassignDsTypeFromTargetTypes(typeId);
|
||||
unassignDsTypeFromTargetTypes(id);
|
||||
|
||||
if (distributionSetRepository.countByTypeId(typeId) > 0) {
|
||||
if (distributionSetRepository.countByTypeId(id) > 0) {
|
||||
toDelete.setDeleted(true);
|
||||
distributionSetTypeRepository.save(toDelete);
|
||||
distributionSetTypeRepository.save(AccessController.Operation.DELETE, toDelete);
|
||||
} else {
|
||||
distributionSetTypeRepository.deleteById(typeId);
|
||||
distributionSetTypeRepository.deleteById(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +290,11 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<DistributionSetType> create(final Collection<DistributionSetTypeCreate> types) {
|
||||
return types.stream().map(this::create).collect(Collectors.toList());
|
||||
final List<JpaDistributionSetType> typesToCreate = types.stream().map(JpaDistributionSetTypeCreate.class::cast)
|
||||
.map(JpaDistributionSetTypeCreate::build).toList();
|
||||
|
||||
return Collections.unmodifiableList(
|
||||
distributionSetTypeRepository.saveAll(AccessController.Operation.CREATE, typesToCreate));
|
||||
}
|
||||
|
||||
private JpaDistributionSetType findDistributionSetTypeAndThrowExceptionIfNotFound(final Long setId) {
|
||||
@@ -309,10 +306,10 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
return update.getOptional().isPresent() || update.getMandatory().isPresent();
|
||||
}
|
||||
|
||||
private void checkDistributionSetTypeSoftwareModuleTypesIsAllowedToModify(final Long type) {
|
||||
if (distributionSetRepository.countByTypeId(type) > 0) {
|
||||
private void checkDistributionSetTypeNotAssigned(final Long id) {
|
||||
if (distributionSetRepository.countByTypeId(id) > 0) {
|
||||
throw new EntityReadOnlyException(String.format(
|
||||
"distribution set type %s is already assigned to distribution sets and cannot be changed", type));
|
||||
"Distribution set type %s is already assigned to distribution sets and cannot be changed!", id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,14 +318,7 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
final List<JpaDistributionSetType> setsFound = distributionSetTypeRepository.findAllById(ids);
|
||||
|
||||
if (setsFound.size() < ids.size()) {
|
||||
throw new EntityNotFoundException(DistributionSetType.class, ids,
|
||||
setsFound.stream().map(DistributionSetType::getId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
distributionSetTypeRepository.deleteAll(setsFound);
|
||||
distributionSetTypeRepository.deleteAllById(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -338,12 +328,11 @@ public class JpaDistributionSetTypeManagement implements DistributionSetTypeMana
|
||||
|
||||
@Override
|
||||
public Optional<DistributionSetType> get(final long id) {
|
||||
return distributionSetTypeRepository.findById(id).map(dst -> (DistributionSetType) dst);
|
||||
return distributionSetTypeRepository.findById(id).map(DistributionSetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(final long id) {
|
||||
return distributionSetTypeRepository.existsById(id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -31,6 +31,7 @@ import org.eclipse.hawkbit.repository.RolloutGroupManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.TargetFields;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
@@ -40,6 +41,10 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
@@ -85,11 +90,11 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
|
||||
|
||||
private final Database database;
|
||||
|
||||
JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||
final TargetRepository targetRepository, final EntityManager entityManager,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
||||
final Database database) {
|
||||
public JpaRolloutGroupManagement(final RolloutGroupRepository rolloutGroupRepository,
|
||||
final RolloutRepository rolloutRepository, final ActionRepository actionRepository,
|
||||
final TargetRepository targetRepository, final EntityManager entityManager,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final RolloutStatusCache rolloutStatusCache,
|
||||
final Database database) {
|
||||
|
||||
this.rolloutGroupRepository = rolloutGroupRepository;
|
||||
this.rolloutRepository = rolloutRepository;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate.addSuccessAndErrorConditionsAndActions;
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericRolloutUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.RolloutGroupCreate;
|
||||
@@ -41,12 +42,16 @@ import org.eclipse.hawkbit.repository.event.remote.entity.RolloutGroupCreatedEve
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityReadOnlyException;
|
||||
import org.eclipse.hawkbit.repository.exception.RolloutIllegalStateException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaRolloutGroupCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rollout.condition.StartNextGroupRolloutGroupSuccessAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.RolloutSpecification;
|
||||
@@ -132,6 +137,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
private final EventPublisherHolder eventPublisherHolder;
|
||||
private final ContextAware contextAware;
|
||||
private final Database database;
|
||||
|
||||
public JpaRolloutManagement(final TargetManagement targetManagement,
|
||||
@@ -139,22 +145,23 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database,
|
||||
final RolloutApprovalStrategy rolloutApprovalStrategy,
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
final SystemSecurityContext systemSecurityContext,
|
||||
final ContextAware contextAware) {
|
||||
this.targetManagement = targetManagement;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
this.database = database;
|
||||
this.rolloutApprovalStrategy = rolloutApprovalStrategy;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.eventPublisherHolder = eventPublisherHolder;
|
||||
this.database = database;
|
||||
this.contextAware = contextAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Rollout> findAll(final Pageable pageable, final boolean deleted) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable,
|
||||
Collections
|
||||
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
|
||||
return JpaManagementHelper.findAllWithCountBySpec(rolloutRepository, pageable, Collections
|
||||
.singletonList(RolloutSpecification.isDeletedWithDistributionSet(deleted, pageable.getSort())));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -212,6 +219,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
throw new ValidationException(errMsg);
|
||||
}
|
||||
rollout.setTotalTargets(totalTargets);
|
||||
contextAware.getCurrentContext().ifPresent(rollout::setAccessControlContext);
|
||||
return rolloutRepository.save(rollout);
|
||||
}
|
||||
|
||||
@@ -301,8 +309,8 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
}
|
||||
|
||||
/**
|
||||
* In case the given group is missing conditions or actions, they will be
|
||||
* set from the supplied default conditions.
|
||||
* In case the given group is missing conditions or actions, they will be set
|
||||
* from the supplied default conditions.
|
||||
*
|
||||
* @param create
|
||||
* group to check
|
||||
@@ -500,7 +508,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
update.getActionType().ifPresent(rollout::setActionType);
|
||||
update.getForcedTime().ifPresent(rollout::setForcedTime);
|
||||
update.getWeight().ifPresent(rollout::setWeight);
|
||||
// reseting back to manual start is done by setting start at time to
|
||||
// resetting back to manual start is done by setting start at time to
|
||||
// null
|
||||
rollout.setStartAt(update.getStartAt().orElse(null));
|
||||
update.getSet().ifPresent(setId -> {
|
||||
@@ -586,6 +594,7 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
|
||||
return fromCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRolloutStatusDetails(final Slice<Rollout> rollouts) {
|
||||
final List<Long> rolloutIds = rollouts.getContent().stream().map(Rollout::getId).collect(Collectors.toList());
|
||||
@@ -768,5 +777,4 @@ public class JpaRolloutManagement implements RolloutManagement {
|
||||
}
|
||||
|
||||
private record TargetCount(long total, String filter) {}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -32,7 +32,6 @@ import javax.persistence.criteria.Order;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.repository.ArtifactEncryptionService;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
@@ -48,6 +47,9 @@ import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleMetadataCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
@@ -58,6 +60,10 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleMetadata_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.SwMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
@@ -81,13 +87,10 @@ import org.springframework.data.jpa.repository.query.QueryUtils;
|
||||
import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link SoftwareModuleManagement}.
|
||||
*
|
||||
@@ -97,23 +100,14 @@ import com.google.common.collect.Lists;
|
||||
public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
|
||||
private final EntityManager entityManager;
|
||||
|
||||
private final DistributionSetRepository distributionSetRepository;
|
||||
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
private final SoftwareModuleMetadataRepository softwareModuleMetadataRepository;
|
||||
|
||||
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
|
||||
private final AuditorAware<String> auditorProvider;
|
||||
|
||||
private final ArtifactManagement artifactManagement;
|
||||
|
||||
private final QuotaManagement quotaManagement;
|
||||
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
private final Database database;
|
||||
|
||||
public JpaSoftwareModuleManagement(final EntityManager entityManager,
|
||||
@@ -122,7 +116,8 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
final SoftwareModuleMetadataRepository softwareModuleMetadataRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository, final AuditorAware<String> auditorProvider,
|
||||
final ArtifactManagement artifactManagement, final QuotaManagement quotaManagement,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final Database database) {
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetRepository = distributionSetRepository;
|
||||
this.softwareModuleRepository = softwareModuleRepository;
|
||||
@@ -158,7 +153,7 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
public SoftwareModule create(final SoftwareModuleCreate c) {
|
||||
final JpaSoftwareModuleCreate create = (JpaSoftwareModuleCreate) c;
|
||||
|
||||
final JpaSoftwareModule sm = softwareModuleRepository.save(create.build());
|
||||
final JpaSoftwareModule sm = softwareModuleRepository.save(AccessController.Operation.CREATE, create.build());
|
||||
if (create.isEncrypted()) {
|
||||
// flush sm creation in order to get an Id
|
||||
entityManager.flush();
|
||||
@@ -173,25 +168,31 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<SoftwareModule> create(final Collection<SoftwareModuleCreate> swModules) {
|
||||
return swModules.stream().map(this::create).collect(Collectors.toList());
|
||||
final List<JpaSoftwareModule> modulesToCreate = swModules.stream().map(JpaSoftwareModuleCreate.class::cast)
|
||||
.map(JpaSoftwareModuleCreate::build).toList();
|
||||
|
||||
final List<SoftwareModule> createdModules = Collections
|
||||
.unmodifiableList(softwareModuleRepository.saveAll(AccessController.Operation.CREATE, modulesToCreate));
|
||||
|
||||
if (createdModules.stream().anyMatch(SoftwareModule::isEncrypted)) {
|
||||
entityManager.flush();
|
||||
createdModules.stream().filter(SoftwareModule::isEncrypted).map(SoftwareModule::getId)
|
||||
.forEach(encryptedModuleId -> ArtifactEncryptionService.getInstance()
|
||||
.addSoftwareModuleEncryptionSecrets(encryptedModuleId));
|
||||
}
|
||||
return createdModules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModule> findByType(final Pageable pageable, final long typeId) {
|
||||
throwExceptionIfSoftwareModuleTypeDoesNotExist(typeId);
|
||||
assertSoftwareModuleTypeExists(typeId);
|
||||
|
||||
final List<Specification<JpaSoftwareModule>> specList = Lists.newArrayListWithExpectedSize(2);
|
||||
|
||||
specList.add(SoftwareModuleSpecification.equalType(typeId));
|
||||
specList.add(SoftwareModuleSpecification.isDeletedFalse());
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, pageable, specList);
|
||||
}
|
||||
|
||||
private void throwExceptionIfSoftwareModuleTypeDoesNotExist(final Long typeId) {
|
||||
if (!softwareModuleTypeRepository.existsById(typeId)) {
|
||||
throw new EntityNotFoundException(SoftwareModuleType.class, typeId);
|
||||
}
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(
|
||||
softwareModuleRepository,
|
||||
pageable,
|
||||
List.of(
|
||||
SoftwareModuleSpecification.equalType(typeId),
|
||||
SoftwareModuleSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -202,19 +203,24 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Override
|
||||
public Optional<SoftwareModule> getByNameAndVersionAndType(final String name, final String version,
|
||||
final long typeId) {
|
||||
assertSoftwareModuleTypeExists(typeId);
|
||||
|
||||
throwExceptionIfSoftwareModuleTypeDoesNotExist(typeId);
|
||||
|
||||
return softwareModuleRepository.findOneByNameAndVersionAndTypeId(name, version, typeId);
|
||||
}
|
||||
|
||||
private boolean isUnassigned(final Long moduleId) {
|
||||
return distributionSetRepository.countByModulesId(moduleId) <= 0;
|
||||
// TODO AC - Access is restricted. This could have problem with UI when access control is enabled.
|
||||
// Vaadin UI use this for validation. May need to be called via elevated access
|
||||
return JpaManagementHelper
|
||||
.findOneBySpec(softwareModuleRepository, List.of(
|
||||
SoftwareModuleSpecification.likeNameAndVersion(name, version),
|
||||
SoftwareModuleSpecification.equalType(typeId),
|
||||
SoftwareModuleSpecification.fetchType()))
|
||||
.map(SoftwareModule.class::cast);
|
||||
}
|
||||
|
||||
private void deleteGridFsArtifacts(final JpaSoftwareModule swModule) {
|
||||
softwareModuleRepository.getAccessController().ifPresent(accessController ->
|
||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, swModule));
|
||||
for (final Artifact localArtifact : swModule.getArtifacts()) {
|
||||
artifactManagement.clearArtifactBinary(localArtifact.getSha1Hash(), swModule.getId());
|
||||
((JpaArtifactManagement)artifactManagement)
|
||||
.clearArtifactBinary(localArtifact.getSha1Hash());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,11 +229,10 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
final List<JpaSoftwareModule> swModulesToDelete = softwareModuleRepository.findByIdIn(ids);
|
||||
|
||||
final List<JpaSoftwareModule> swModulesToDelete = softwareModuleRepository.findAllById(ids);
|
||||
if (swModulesToDelete.size() < ids.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, ids,
|
||||
swModulesToDelete.stream().map(SoftwareModule::getId).collect(Collectors.toList()));
|
||||
swModulesToDelete.stream().map(SoftwareModule::getId).toList());
|
||||
}
|
||||
|
||||
final Set<Long> assignedModuleIds = new HashSet<>();
|
||||
@@ -236,7 +241,9 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
// delete binary data of artifacts
|
||||
deleteGridFsArtifacts(swModule);
|
||||
|
||||
if (isUnassigned(swModule.getId())) {
|
||||
// execute this count operation without access limitations since we have to
|
||||
// ensure it's not assigned when deleting it.
|
||||
if (distributionSetRepository.countByModulesId(swModule.getId()) <= 0) {
|
||||
softwareModuleRepository.deleteById(swModule.getId());
|
||||
} else {
|
||||
assignedModuleIds.add(swModule.getId());
|
||||
@@ -248,55 +255,61 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
if (auditorProvider != null) {
|
||||
currentUser = auditorProvider.getCurrentAuditor().orElse(null);
|
||||
}
|
||||
softwareModuleRepository.deleteSoftwareModule(System.currentTimeMillis(), currentUser,
|
||||
assignedModuleIds.toArray(new Long[0]));
|
||||
|
||||
/*
|
||||
TODO AC - could use single update query as before via entity manager directly (considers tenant!):
|
||||
maybe it will be possible, via specification when migrate to Spring Boot 3
|
||||
"UPDATE JpaSoftwareModule b SET b.deleted = 1, b.lastModifiedAt = :lastModifiedAt, b.lastModifiedBy = :lastModifiedBy WHERE b.tenant = :tenant AND b.id IN :ids"
|
||||
*/
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
final List<JpaSoftwareModule> toDelete = softwareModuleRepository.findAll(
|
||||
AccessController.Operation.DELETE, softwareModuleRepository.byIdsSpec(assignedModuleIds));
|
||||
for (final JpaSoftwareModule softwareModule : toDelete) {
|
||||
softwareModule.setDeleted(true);
|
||||
softwareModule.setLastModifiedAt(timestamp);
|
||||
softwareModule.setLastModifiedBy(currentUser);
|
||||
}
|
||||
softwareModuleRepository.saveAll(toDelete);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModule> findAll(final Pageable pageable) {
|
||||
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(2);
|
||||
specList.add(SoftwareModuleSpecification.isDeletedFalse());
|
||||
specList.add(SoftwareModuleSpecification.fetchType());
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, pageable, specList);
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleRepository, pageable, List.of(
|
||||
SoftwareModuleSpecification.isNotDeleted(),
|
||||
SoftwareModuleSpecification.fetchType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
final Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
|
||||
return JpaManagementHelper.countBySpec(softwareModuleRepository, Collections.singletonList(spec));
|
||||
return softwareModuleRepository.count(SoftwareModuleSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModule> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||
final List<Specification<JpaSoftwareModule>> specList = Lists.newArrayListWithExpectedSize(2);
|
||||
specList.add(RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleFields.class, virtualPropertyReplacer,
|
||||
database));
|
||||
specList.add(SoftwareModuleSpecification.isDeletedFalse());
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, pageable, specList);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, pageable, List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
SoftwareModuleSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||
public List<SoftwareModule> get(final Collection<Long> ids) {
|
||||
return Collections.unmodifiableList(softwareModuleRepository.findByIdIn(ids));
|
||||
return Collections.unmodifiableList(softwareModuleRepository.findAllById(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModule> findByTextAndType(final Pageable pageable, final String searchText,
|
||||
final Long typeId) {
|
||||
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(4);
|
||||
specList.add(SoftwareModuleSpecification.isDeletedFalse());
|
||||
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
|
||||
specList.add(SoftwareModuleSpecification.isNotDeleted());
|
||||
|
||||
if (!StringUtils.isEmpty(searchText)) {
|
||||
if (!ObjectUtils.isEmpty(searchText)) {
|
||||
specList.add(buildSmSearchQuerySpec(searchText));
|
||||
}
|
||||
|
||||
if (null != typeId) {
|
||||
throwExceptionIfSoftwareModuleTypeDoesNotExist(typeId);
|
||||
assertSoftwareModuleTypeExists(typeId);
|
||||
specList.add(SoftwareModuleSpecification.equalType(typeId));
|
||||
}
|
||||
|
||||
@@ -312,13 +325,17 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
smFilterNameAndVersionEntries[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Used only in UI which is to be removed
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@Override
|
||||
// In the interface org.springframework.data.domain.Pageable.getSort the
|
||||
// return value is not guaranteed to be non-null, therefore a null check is
|
||||
// necessary otherwise we rely on the implementation but this could change.
|
||||
@SuppressWarnings({ "squid:S2583", "squid:S2589" })
|
||||
public Slice<AssignedSoftwareModule> findAllOrderBySetAssignmentAndModuleNameAscModuleVersionAsc(
|
||||
final Pageable pageable, final long dsId, final String searchText, final Long smTypeId) {
|
||||
final Pageable pageable, final long orderByDistributionSetId, final String searchText, final Long typeId) {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Tuple> query = cb.createTupleQuery();
|
||||
final Root<JpaSoftwareModule> smRoot = query.from(JpaSoftwareModule.class);
|
||||
@@ -327,11 +344,11 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
.join(JpaSoftwareModule_.assignedTo, JoinType.LEFT);
|
||||
|
||||
final Expression<Integer> assignedCaseMax = cb.max(
|
||||
cb.<Long, Integer> selectCase(assignedDsList.get(JpaDistributionSet_.id)).when(dsId, 1).otherwise(0));
|
||||
cb.<Long, Integer> selectCase(assignedDsList.get(JpaDistributionSet_.id)).when(orderByDistributionSetId, 1).otherwise(0));
|
||||
|
||||
query.multiselect(smRoot.alias("sm"), assignedCaseMax.alias("assigned"));
|
||||
|
||||
final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, smTypeId),
|
||||
final Predicate[] specPredicate = specificationsToPredicate(buildSpecificationList(searchText, typeId),
|
||||
smRoot, query, cb);
|
||||
|
||||
if (specPredicate.length > 0) {
|
||||
@@ -358,25 +375,41 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
|
||||
final List<AssignedSoftwareModule> resultList = new ArrayList<>();
|
||||
|
||||
smWithAssignedFlagList.forEach(smWithAssignedFlag -> resultList
|
||||
.add(new AssignedSoftwareModule(smWithAssignedFlag.get("sm", JpaSoftwareModule.class),
|
||||
smWithAssignedFlag.get("assigned", Number.class).longValue() == 1)));
|
||||
smWithAssignedFlagList.forEach(smWithAssignedFlag -> {
|
||||
final JpaSoftwareModule softwareModule = smWithAssignedFlag.get("sm", JpaSoftwareModule.class);
|
||||
try {
|
||||
// check read access
|
||||
if (softwareModuleRepository.getAccessController().map(accessController -> {
|
||||
try {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.READ, softwareModule);
|
||||
return true;
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
return false;
|
||||
}
|
||||
}).orElse(true)) {
|
||||
resultList.add(new AssignedSoftwareModule(softwareModule,
|
||||
smWithAssignedFlag.get("assigned", Number.class).longValue() == 1));
|
||||
}
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
// skip the entry
|
||||
}
|
||||
});
|
||||
|
||||
return new SliceImpl<>(Collections.unmodifiableList(resultList), pageable, hasNext);
|
||||
}
|
||||
|
||||
private List<Specification<JpaSoftwareModule>> buildSpecificationList(final String searchText, final Long typeId) {
|
||||
final List<Specification<JpaSoftwareModule>> specList = Lists.newArrayListWithExpectedSize(3);
|
||||
if (!StringUtils.isEmpty(searchText)) {
|
||||
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
|
||||
if (!ObjectUtils.isEmpty(searchText)) {
|
||||
specList.add(buildSmSearchQuerySpec(searchText));
|
||||
}
|
||||
|
||||
if (typeId != null) {
|
||||
throwExceptionIfSoftwareModuleTypeDoesNotExist(typeId);
|
||||
assertSoftwareModuleTypeExists(typeId);
|
||||
|
||||
specList.add(SoftwareModuleSpecification.equalType(typeId));
|
||||
}
|
||||
specList.add(SoftwareModuleSpecification.isDeletedFalse());
|
||||
specList.add(SoftwareModuleSpecification.isNotDeleted());
|
||||
return specList;
|
||||
}
|
||||
|
||||
@@ -388,19 +421,25 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
Arrays.stream(additionalPredicates)).toArray(Predicate[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* No access control applied
|
||||
*
|
||||
* @deprecated Used only in UI which is to be removed
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@Override
|
||||
public long countByTextAndType(final String searchText, final Long typeId) {
|
||||
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
|
||||
|
||||
Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
|
||||
Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.isNotDeleted();
|
||||
specList.add(spec);
|
||||
|
||||
if (!StringUtils.isEmpty(searchText)) {
|
||||
if (!ObjectUtils.isEmpty(searchText)) {
|
||||
specList.add(buildSmSearchQuerySpec(searchText));
|
||||
}
|
||||
|
||||
if (null != typeId) {
|
||||
throwExceptionIfSoftwareModuleTypeDoesNotExist(typeId);
|
||||
assertSoftwareModuleTypeExists(typeId);
|
||||
|
||||
spec = SoftwareModuleSpecification.equalType(typeId);
|
||||
specList.add(spec);
|
||||
@@ -410,21 +449,18 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModule> findByAssignedTo(final Pageable pageable, final long setId) {
|
||||
if (!distributionSetRepository.existsById(setId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, setId);
|
||||
}
|
||||
public Page<SoftwareModule> findByAssignedTo(final Pageable pageable, final long distributionSetId) {
|
||||
assertDistributionSetExists(distributionSetId);
|
||||
|
||||
return softwareModuleRepository.findByAssignedToId(pageable, setId);
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleRepository, pageable,
|
||||
Collections.singletonList(SoftwareModuleSpecification.byAssignedToDs(distributionSetId)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByAssignedTo(final long setId) {
|
||||
if (!distributionSetRepository.existsById(setId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, setId);
|
||||
}
|
||||
public long countByAssignedTo(final long distributionSetId) {
|
||||
assertDistributionSetExists(distributionSetId);
|
||||
|
||||
return softwareModuleRepository.countByAssignedToId(setId);
|
||||
return softwareModuleRepository.count(SoftwareModuleSpecification.byAssignedToDs(distributionSetId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -432,12 +468,15 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public SoftwareModuleMetadata createMetaData(final SoftwareModuleMetadataCreate c) {
|
||||
|
||||
final JpaSoftwareModuleMetadataCreate create = (JpaSoftwareModuleMetadataCreate) c;
|
||||
final Long moduleId = create.getSoftwareModuleId();
|
||||
assertSoftwareModuleExists(moduleId);
|
||||
assertMetaDataQuota(moduleId, 1);
|
||||
final Long id = create.getSoftwareModuleId();
|
||||
|
||||
assertSoftwareModuleExists(id);
|
||||
assertMetaDataQuota(id, 1);
|
||||
|
||||
// touch to update revision and last modified timestamp
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, (JpaSoftwareModule) get(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
return saveMetadata(create);
|
||||
}
|
||||
|
||||
@@ -446,31 +485,30 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<SoftwareModuleMetadata> createMetaData(final Collection<SoftwareModuleMetadataCreate> create) {
|
||||
|
||||
if (!create.isEmpty()) {
|
||||
// check if all metadata entries refer to the same software module
|
||||
final Long id = ((JpaSoftwareModuleMetadataCreate) create.iterator().next()).getSoftwareModuleId();
|
||||
if (createJpaMetadataCreateStream(create).allMatch(c -> id.equals(c.getSoftwareModuleId()))) {
|
||||
assertSoftwareModuleExists(id);
|
||||
assertMetaDataQuota(id, create.size());
|
||||
|
||||
// check if all meta data entries refer to the same software module
|
||||
final Long moduleId = ((JpaSoftwareModuleMetadataCreate) create.iterator().next()).getSoftwareModuleId();
|
||||
if (createJpaMetadataCreateStream(create).allMatch(c -> moduleId.equals(c.getSoftwareModuleId()))) {
|
||||
|
||||
assertSoftwareModuleExists(moduleId);
|
||||
assertMetaDataQuota(moduleId, create.size());
|
||||
|
||||
// touch to update revision and last modified timestamp
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, (JpaSoftwareModule) get(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
return createJpaMetadataCreateStream(create).map(this::saveMetadata).collect(Collectors.toList());
|
||||
|
||||
} else {
|
||||
|
||||
// group by software module id to minimize database access
|
||||
final Map<Long, List<JpaSoftwareModuleMetadataCreate>> groups = createJpaMetadataCreateStream(create)
|
||||
.collect(Collectors.groupingBy(JpaSoftwareModuleMetadataCreate::getSoftwareModuleId));
|
||||
return groups.entrySet().stream().flatMap(e -> {
|
||||
|
||||
final Long id = e.getKey();
|
||||
final List<JpaSoftwareModuleMetadataCreate> group = e.getValue();
|
||||
|
||||
assertSoftwareModuleExists(id);
|
||||
assertMetaDataQuota(id, group.size());
|
||||
assertMetaDataQuota(e.getKey(), group.size());
|
||||
|
||||
// touch to update revision and last modified timestamp
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, (JpaSoftwareModule) get(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, id)));
|
||||
return group.stream().map(this::saveMetadata);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
@@ -489,29 +527,24 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
return softwareModuleMetadataRepository.save(create.build());
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleMetadataDoesNotExist(final Long moduleId,
|
||||
private void assertSoftwareModuleMetadataDoesNotExist(final Long id,
|
||||
final JpaSoftwareModuleMetadataCreate md) {
|
||||
if (softwareModuleMetadataRepository.existsById(new SwMetadataCompositeKey(moduleId, md.getKey()))) {
|
||||
throwMetadataKeyAlreadyExists(md.getKey());
|
||||
if (softwareModuleMetadataRepository.existsById(new SwMetadataCompositeKey(id, md.getKey()))) {
|
||||
throw new EntityAlreadyExistsException("Metadata entry with key '" + md.getKey() + "' already exists!");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleExists(final Long moduleId) {
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository, (JpaSoftwareModule) get(moduleId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModule.class, moduleId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts the meta data quota for the software module with the given ID.
|
||||
*
|
||||
* @param moduleId
|
||||
* @param id
|
||||
* The software module ID.
|
||||
* @param requested
|
||||
* Number of meta data entries to be created.
|
||||
*/
|
||||
private void assertMetaDataQuota(final Long moduleId, final int requested) {
|
||||
private void assertMetaDataQuota(final Long id, final int requested) {
|
||||
final int maxMetaData = quotaManagement.getMaxMetaDataEntriesPerSoftwareModule();
|
||||
QuotaHelper.assertAssignmentQuota(moduleId, requested, maxMetaData, SoftwareModuleMetadata.class,
|
||||
QuotaHelper.assertAssignmentQuota(id, requested, maxMetaData, SoftwareModuleMetadata.class,
|
||||
SoftwareModule.class, softwareModuleMetadataRepository::countBySoftwareModuleId);
|
||||
}
|
||||
|
||||
@@ -525,8 +558,8 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
// check if exists otherwise throw entity not found exception
|
||||
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) getMetaDataBySoftwareModuleId(
|
||||
update.getSoftwareModuleId(), update.getKey())
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleMetadata.class,
|
||||
update.getSoftwareModuleId(), update.getKey()));
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleMetadata.class,
|
||||
update.getSoftwareModuleId(), update.getKey()));
|
||||
|
||||
update.getValue().ifPresent(metadata::setValue);
|
||||
update.isTargetVisible().ifPresent(metadata::setTargetVisible);
|
||||
@@ -540,70 +573,55 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void deleteMetaData(final long moduleId, final String key) {
|
||||
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) getMetaDataBySoftwareModuleId(moduleId,
|
||||
key).orElseThrow(() -> new EntityNotFoundException(SoftwareModuleMetadata.class, moduleId, key));
|
||||
public void deleteMetaData(final long id, final String key) {
|
||||
final JpaSoftwareModuleMetadata metadata = (JpaSoftwareModuleMetadata) getMetaDataBySoftwareModuleId(id,
|
||||
key).orElseThrow(() -> new EntityNotFoundException(SoftwareModuleMetadata.class, id, key));
|
||||
|
||||
JpaManagementHelper.touch(entityManager, softwareModuleRepository,
|
||||
(JpaSoftwareModule) metadata.getSoftwareModule());
|
||||
softwareModuleMetadataRepository.deleteById(metadata.getId());
|
||||
}
|
||||
|
||||
private void throwExceptionIfSoftwareModuleDoesNotExist(final Long swId) {
|
||||
if (!softwareModuleRepository.existsById(swId)) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, swId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModuleMetadata> findMetaDataByRsql(final Pageable pageable, final long softwareModuleId,
|
||||
public Page<SoftwareModuleMetadata> findMetaDataByRsql(final Pageable pageable, final long id,
|
||||
final String rsqlParam) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(softwareModuleId);
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
final List<Specification<JpaSoftwareModuleMetadata>> specList = Arrays
|
||||
.asList(RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleMetadataFields.class,
|
||||
virtualPropertyReplacer, database), bySmIdSpec(softwareModuleId));
|
||||
virtualPropertyReplacer, database), metadataBySoftwareModuleIdSpec(id));
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleMetadataRepository, pageable, specList);
|
||||
}
|
||||
|
||||
private static Specification<JpaSoftwareModuleMetadata> bySmIdSpec(final long smId) {
|
||||
return (root, query, cb) -> cb
|
||||
.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id), smId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleId(final Pageable pageable, final long swId) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(swId);
|
||||
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleId(final Pageable pageable, final long id) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleMetadataRepository, pageable,
|
||||
Collections.singletonList(bySmIdSpec(swId)));
|
||||
Collections.singletonList(metadataBySoftwareModuleIdSpec(id)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countMetaDataBySoftwareModuleId(final long moduleId) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(moduleId);
|
||||
public long countMetaDataBySoftwareModuleId(final long id) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return softwareModuleMetadataRepository.countBySoftwareModuleId(moduleId);
|
||||
return softwareModuleMetadataRepository.countBySoftwareModuleId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModuleMetadata> getMetaDataBySoftwareModuleId(final long moduleId, final String key) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(moduleId);
|
||||
public Optional<SoftwareModuleMetadata> getMetaDataBySoftwareModuleId(final long id, final String key) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return softwareModuleMetadataRepository.findById(new SwMetadataCompositeKey(moduleId, key))
|
||||
return softwareModuleMetadataRepository.findById(new SwMetadataCompositeKey(id, key))
|
||||
.map(SoftwareModuleMetadata.class::cast);
|
||||
}
|
||||
|
||||
private static void throwMetadataKeyAlreadyExists(final String metadataKey) {
|
||||
throw new EntityAlreadyExistsException("Metadata entry with key '" + metadataKey + "' already exists");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long moduleId) {
|
||||
delete(Arrays.asList(moduleId));
|
||||
public void delete(final long id) {
|
||||
delete(List.of(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -613,11 +631,33 @@ public class JpaSoftwareModuleManagement implements SoftwareModuleManagement {
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModuleMetadata> findMetaDataBySoftwareModuleIdAndTargetVisible(final Pageable pageable,
|
||||
final long moduleId) {
|
||||
throwExceptionIfSoftwareModuleDoesNotExist(moduleId);
|
||||
final long id) {
|
||||
assertSoftwareModuleExists(id);
|
||||
|
||||
return JpaManagementHelper.convertPage(softwareModuleMetadataRepository.findBySoftwareModuleIdAndTargetVisible(
|
||||
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), moduleId, true), pageable);
|
||||
PageRequest.of(0, RepositoryConstants.MAX_META_DATA_COUNT), id, true), pageable);
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleExists(final Long id) {
|
||||
if (!softwareModuleRepository.existsById(id)) {
|
||||
throw new EntityNotFoundException(SoftwareModule.class, id);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertSoftwareModuleTypeExists(final Long typeId) {
|
||||
if (!softwareModuleTypeRepository.existsById(typeId)) {
|
||||
throw new EntityNotFoundException(SoftwareModuleType.class, typeId);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertDistributionSetExists(final long distributionSetId) {
|
||||
if (!distributionSetRepository.existsById(distributionSetId)) {
|
||||
throw new EntityNotFoundException(DistributionSet.class, distributionSetId);
|
||||
}
|
||||
}
|
||||
|
||||
private static Specification<JpaSoftwareModuleMetadata> metadataBySoftwareModuleIdSpec(final long id) {
|
||||
return (root, query, cb) -> cb
|
||||
.equal(root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id), id);
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,12 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeFields;
|
||||
import org.eclipse.hawkbit.repository.SoftwareModuleTypeManagement;
|
||||
@@ -22,9 +20,14 @@ import org.eclipse.hawkbit.repository.builder.GenericSoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.SoftwareModuleTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaSoftwareModuleTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
@@ -48,19 +51,16 @@ import org.springframework.validation.annotation.Validated;
|
||||
public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManagement {
|
||||
|
||||
private final DistributionSetTypeRepository distributionSetTypeRepository;
|
||||
|
||||
private final SoftwareModuleTypeRepository softwareModuleTypeRepository;
|
||||
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
private final SoftwareModuleRepository softwareModuleRepository;
|
||||
|
||||
private final Database database;
|
||||
|
||||
public JpaSoftwareModuleTypeManagement(final DistributionSetTypeRepository distributionSetTypeRepository,
|
||||
final SoftwareModuleTypeRepository softwareModuleTypeRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final SoftwareModuleRepository softwareModuleRepository, final Database database) {
|
||||
final SoftwareModuleRepository softwareModuleRepository,
|
||||
final Database database) {
|
||||
this.distributionSetTypeRepository = distributionSetTypeRepository;
|
||||
this.softwareModuleTypeRepository = softwareModuleTypeRepository;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
@@ -86,23 +86,22 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
||||
|
||||
@Override
|
||||
public Page<SoftwareModuleType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||
return JpaManagementHelper
|
||||
.findAllWithCountBySpec(softwareModuleTypeRepository, pageable,
|
||||
Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleTypeFields.class,
|
||||
virtualPropertyReplacer, database),
|
||||
SoftwareModuleTypeSpecification.isDeleted(false)));
|
||||
return JpaManagementHelper.findAllWithCountBySpec(softwareModuleTypeRepository, pageable,
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, SoftwareModuleTypeFields.class,
|
||||
virtualPropertyReplacer, database),
|
||||
SoftwareModuleTypeSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<SoftwareModuleType> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(softwareModuleTypeRepository, pageable,
|
||||
Collections.singletonList(SoftwareModuleTypeSpecification.isDeleted(false)));
|
||||
List.of(SoftwareModuleTypeSpecification.isNotDeleted()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return softwareModuleTypeRepository.countByDeleted(false);
|
||||
return softwareModuleTypeRepository.count(SoftwareModuleTypeSpecification.isNotDeleted());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,34 +119,31 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public SoftwareModuleType create(final SoftwareModuleTypeCreate c) {
|
||||
final JpaSoftwareModuleTypeCreate create = (JpaSoftwareModuleTypeCreate) c;
|
||||
final JpaSoftwareModuleTypeCreate create = (JpaSoftwareModuleTypeCreate) c;
|
||||
|
||||
return softwareModuleTypeRepository.save(create.build());
|
||||
return softwareModuleTypeRepository.save(AccessController.Operation.CREATE, create.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final long typeId) {
|
||||
final JpaSoftwareModuleType toDelete = softwareModuleTypeRepository.findById(typeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, typeId));
|
||||
public void delete(final long id) {
|
||||
final JpaSoftwareModuleType toDelete = softwareModuleTypeRepository.findById(id)
|
||||
.orElseThrow(() -> new EntityNotFoundException(SoftwareModuleType.class, id));
|
||||
|
||||
if (softwareModuleRepository.countByType(toDelete) > 0
|
||||
|| distributionSetTypeRepository.countByElementsSmType(toDelete) > 0) {
|
||||
toDelete.setDeleted(true);
|
||||
softwareModuleTypeRepository.save(toDelete);
|
||||
} else {
|
||||
softwareModuleTypeRepository.delete(toDelete);
|
||||
}
|
||||
delete(toDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<SoftwareModuleType> create(final Collection<SoftwareModuleTypeCreate> creates) {
|
||||
return creates.stream().map(this::create).collect(Collectors.toList());
|
||||
public List<SoftwareModuleType> create(final Collection<SoftwareModuleTypeCreate> c) {
|
||||
final List<JpaSoftwareModuleType> creates = c.stream().map(JpaSoftwareModuleTypeCreate.class::cast)
|
||||
.map(JpaSoftwareModuleTypeCreate::build).toList();
|
||||
return Collections.unmodifiableList(
|
||||
softwareModuleTypeRepository.saveAll(AccessController.Operation.CREATE, creates));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -155,14 +151,9 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> ids) {
|
||||
final List<JpaSoftwareModuleType> setsFound = softwareModuleTypeRepository.findAllById(ids);
|
||||
|
||||
if (setsFound.size() < ids.size()) {
|
||||
throw new EntityNotFoundException(SoftwareModuleType.class, ids,
|
||||
setsFound.stream().map(SoftwareModuleType::getId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
softwareModuleTypeRepository.deleteAll(setsFound);
|
||||
softwareModuleTypeRepository
|
||||
.findAll(AccessController.Operation.DELETE, softwareModuleTypeRepository.byIdsSpec(ids))
|
||||
.forEach(this::delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,7 +163,7 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
||||
|
||||
@Override
|
||||
public Optional<SoftwareModuleType> get(final long id) {
|
||||
return softwareModuleTypeRepository.findById(id).map(smt -> (SoftwareModuleType) smt);
|
||||
return softwareModuleTypeRepository.findById(id).map(SoftwareModuleType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -180,4 +171,13 @@ public class JpaSoftwareModuleTypeManagement implements SoftwareModuleTypeManage
|
||||
return softwareModuleTypeRepository.existsById(id);
|
||||
}
|
||||
|
||||
private void delete(JpaSoftwareModuleType toDelete) {
|
||||
if (softwareModuleRepository.countByType(toDelete) > 0
|
||||
|| distributionSetTypeRepository.countByElementsSmType(toDelete) > 0) {
|
||||
toDelete.setDeleted(true);
|
||||
softwareModuleTypeRepository.save(AccessController.Operation.DELETE, toDelete);
|
||||
} else {
|
||||
softwareModuleTypeRepository.delete(toDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
@@ -21,11 +21,25 @@ import org.eclipse.hawkbit.repository.RolloutStatusCache;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.CurrentTenantCacheKeyGenerator;
|
||||
import org.eclipse.hawkbit.repository.jpa.SystemManagementCacheKeyGenerator;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.SoftwareModuleTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TenantConfigurationRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TenantMetaDataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -22,6 +22,7 @@ import org.eclipse.hawkbit.repository.TargetFilterQueryFields;
|
||||
import org.eclipse.hawkbit.repository.TargetFilterQueryManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.ContextAware;
|
||||
import org.eclipse.hawkbit.repository.builder.AutoAssignDistributionSetUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTargetFilterQueryUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TargetFilterQueryCreate;
|
||||
@@ -29,10 +30,13 @@ import org.eclipse.hawkbit.repository.builder.TargetFilterQueryUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InvalidAutoAssignActionTypeException;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetFilterQueryCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetFilterQuerySpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
@@ -43,7 +47,6 @@ import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.utils.TenantConfigHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -56,7 +59,7 @@ import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -82,15 +85,15 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
private final QuotaManagement quotaManagement;
|
||||
private final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private final SystemSecurityContext systemSecurityContext;
|
||||
private final TenantAware tenantAware;
|
||||
private final ContextAware contextAware;
|
||||
|
||||
private final Database database;
|
||||
|
||||
JpaTargetFilterQueryManagement(final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
public JpaTargetFilterQueryManagement(final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetManagement targetManagement, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final Database database, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final SystemSecurityContext systemSecurityContext, final TenantAware tenantAware) {
|
||||
final SystemSecurityContext systemSecurityContext, final ContextAware contextAware) {
|
||||
this.targetFilterQueryRepository = targetFilterQueryRepository;
|
||||
this.targetManagement = targetManagement;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
@@ -99,7 +102,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
this.database = database;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.tenantAware = tenantAware;
|
||||
this.contextAware = contextAware;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,7 +125,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
});
|
||||
});
|
||||
|
||||
return targetFilterQueryRepository.save(create.build());
|
||||
return targetFilterQueryRepository.save(AccessController.Operation.CREATE, create.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,7 +157,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
@Override
|
||||
public Slice<TargetFilterQuery> findByName(final Pageable pageable, final String name) {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
if (ObjectUtils.isEmpty(name)) {
|
||||
return findAll(pageable);
|
||||
}
|
||||
|
||||
@@ -164,7 +167,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
@Override
|
||||
public long countByName(final String name) {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
if (ObjectUtils.isEmpty(name)) {
|
||||
return count();
|
||||
}
|
||||
|
||||
@@ -174,7 +177,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
@Override
|
||||
public Page<TargetFilterQuery> findByRsql(final Pageable pageable, final String rsqlFilter) {
|
||||
final List<Specification<JpaTargetFilterQuery>> specList = !StringUtils.isEmpty(rsqlFilter)
|
||||
final List<Specification<JpaTargetFilterQuery>> specList = !ObjectUtils.isEmpty(rsqlFilter)
|
||||
? Collections.singletonList(RSQLUtility.buildRsqlSpecification(rsqlFilter,
|
||||
TargetFilterQueryFields.class, virtualPropertyReplacer, database))
|
||||
: Collections.emptyList();
|
||||
@@ -184,7 +187,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
@Override
|
||||
public Slice<TargetFilterQuery> findByQuery(final Pageable pageable, final String query) {
|
||||
final List<Specification<JpaTargetFilterQuery>> specList = !StringUtils.isEmpty(query)
|
||||
final List<Specification<JpaTargetFilterQuery>> specList = !ObjectUtils.isEmpty(query)
|
||||
? Collections.singletonList(TargetFilterQuerySpecification.equalsQuery(query))
|
||||
: Collections.emptyList();
|
||||
|
||||
@@ -207,7 +210,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
final List<Specification<JpaTargetFilterQuery>> specList = Lists.newArrayListWithExpectedSize(2);
|
||||
specList.add(TargetFilterQuerySpecification.byAutoAssignDS(distributionSet));
|
||||
if (!StringUtils.isEmpty(rsqlFilter)) {
|
||||
if (!ObjectUtils.isEmpty(rsqlFilter)) {
|
||||
specList.add(RSQLUtility.buildRsqlSpecification(rsqlFilter, TargetFilterQueryFields.class,
|
||||
virtualPropertyReplacer, database));
|
||||
}
|
||||
@@ -228,7 +231,7 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
|
||||
@Override
|
||||
public Optional<TargetFilterQuery> get(final long targetFilterQueryId) {
|
||||
return targetFilterQueryRepository.findById(targetFilterQueryId).map(tfq -> (TargetFilterQuery) tfq);
|
||||
return targetFilterQueryRepository.findById(targetFilterQueryId).map(TargetFilterQuery.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -262,7 +265,9 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
public TargetFilterQuery updateAutoAssignDS(final AutoAssignDistributionSetUpdate update) {
|
||||
final JpaTargetFilterQuery targetFilterQuery = findTargetFilterQueryOrThrowExceptionIfNotFound(
|
||||
update.getTargetFilterId());
|
||||
|
||||
if (update.getDsId() == null) {
|
||||
targetFilterQuery.setAccessControlContext(null);
|
||||
targetFilterQuery.setAutoAssignDistributionSet(null);
|
||||
targetFilterQuery.setAutoAssignActionType(null);
|
||||
targetFilterQuery.setAutoAssignWeight(null);
|
||||
@@ -274,8 +279,10 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
final JpaDistributionSet ds = (JpaDistributionSet) distributionSetManagement
|
||||
.getValidAndComplete(update.getDsId());
|
||||
verifyDistributionSetAndThrowExceptionIfDeleted(ds);
|
||||
|
||||
targetFilterQuery.setAutoAssignDistributionSet(ds);
|
||||
targetFilterQuery.setAutoAssignInitiatedBy(tenantAware.getCurrentUsername());
|
||||
contextAware.getCurrentContext().ifPresent(targetFilterQuery::setAccessControlContext);
|
||||
targetFilterQuery.setAutoAssignInitiatedBy(contextAware.getCurrentUsername());
|
||||
targetFilterQuery.setAutoAssignActionType(sanitizeAutoAssignActionType(update.getActionType()));
|
||||
targetFilterQuery.setAutoAssignWeight(update.getWeight());
|
||||
final boolean confirmationRequired = update.isConfirmationRequired() == null ? isConfirmationFlowEnabled()
|
||||
@@ -325,14 +332,15 @@ public class JpaTargetFilterQueryManagement implements TargetFilterQueryManageme
|
||||
}
|
||||
|
||||
private void assertMaxTargetsQuota(final String query, final String filterName, final long dsId) {
|
||||
QuotaHelper.assertAssignmentQuota(filterName, targetManagement.countByRsqlAndNonDSAndCompatible(dsId, query),
|
||||
QuotaHelper.assertAssignmentQuota(filterName,
|
||||
targetManagement.countByRsqlAndNonDSAndCompatibleAndUpdatable(dsId, query),
|
||||
quotaManagement.getMaxTargetsPerAutoAssignment(), Target.class, TargetFilterQuery.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void cancelAutoAssignmentForDistributionSet(final long setId) {
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionType(setId);
|
||||
LOGGER.debug("Auto assignments for distribution sets {} deactivated", setId);
|
||||
public void cancelAutoAssignmentForDistributionSet(final long distributionSetId) {
|
||||
targetFilterQueryRepository.unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(distributionSetId);
|
||||
LOGGER.debug("Auto assignments for distribution sets {} deactivated", distributionSetId);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
@@ -43,6 +43,8 @@ import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetUpdate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
@@ -54,6 +56,12 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetFilterQueryRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetMetadataRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
@@ -83,7 +91,7 @@ import org.springframework.orm.jpa.vendor.Database;
|
||||
import org.springframework.retry.annotation.Backoff;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -118,12 +126,11 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
private final AfterTransactionCommitExecutor afterCommit;
|
||||
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
|
||||
private final Database database;
|
||||
|
||||
|
||||
public JpaTargetManagement(final EntityManager entityManager,
|
||||
final DistributionSetManagement distributionSetManagement, final QuotaManagement quotaManagement,
|
||||
final TargetRepository targetRepository, final TargetTypeRepository targetTypeRepository,
|
||||
@@ -131,7 +138,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final RolloutGroupRepository rolloutGroupRepository,
|
||||
final TargetFilterQueryRepository targetFilterQueryRepository,
|
||||
final TargetTagRepository targetTagRepository, final EventPublisherHolder eventPublisherHolder,
|
||||
final TenantAware tenantAware, final AfterTransactionCommitExecutor afterCommit,
|
||||
final TenantAware tenantAware,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer, final Database database) {
|
||||
this.entityManager = entityManager;
|
||||
this.distributionSetManagement = distributionSetManagement;
|
||||
@@ -144,7 +151,6 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
this.targetTagRepository = targetTagRepository;
|
||||
this.eventPublisherHolder = eventPublisherHolder;
|
||||
this.tenantAware = tenantAware;
|
||||
this.afterCommit = afterCommit;
|
||||
this.virtualPropertyReplacer = virtualPropertyReplacer;
|
||||
this.database = database;
|
||||
}
|
||||
@@ -155,7 +161,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
private JpaTarget getByControllerIdAndThrowIfNotFound(final String controllerId) {
|
||||
return targetRepository.findOne(TargetSpecifications.hasControllerId(controllerId))
|
||||
return targetRepository
|
||||
.findOne(TargetSpecifications.hasControllerId(controllerId))
|
||||
.orElseThrow(() -> new EntityNotFoundException(Target.class, controllerId));
|
||||
}
|
||||
|
||||
@@ -179,7 +186,6 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<TargetMetadata> createMetaData(final String controllerId, final Collection<MetaData> md) {
|
||||
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
|
||||
md.forEach(meta -> checkAndThrowIfTargetMetadataAlreadyExists(
|
||||
@@ -222,15 +228,16 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
// check if exists otherwise throw entity not found exception
|
||||
final JpaTargetMetadata updatedMetadata = (JpaTargetMetadata) getMetaDataByControllerId(controllerId,
|
||||
md.getKey()).orElseThrow(
|
||||
() -> new EntityNotFoundException(TargetMetadata.class, controllerId, md.getKey()));
|
||||
md.getKey())
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetMetadata.class, controllerId, md.getKey()));
|
||||
updatedMetadata.setValue(md.getValue());
|
||||
// touch it to update the lock revision because we are modifying the
|
||||
// target indirectly
|
||||
final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository,
|
||||
getByControllerIdAndThrowIfNotFound(controllerId));
|
||||
|
||||
final JpaTargetMetadata metadata = targetMetadataRepository.save(updatedMetadata);
|
||||
// target update event is set to ignore "lastModifiedAt" field so it is
|
||||
// target update event is set to ignore "lastModifiedAt" field, so it is
|
||||
// not send automatically within the touch() method
|
||||
eventPublisherHolder.getEventPublisher()
|
||||
.publishEvent(new TargetUpdatedEvent(target, eventPublisherHolder.getApplicationId()));
|
||||
@@ -247,6 +254,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
final JpaTarget target = JpaManagementHelper.touch(entityManager, targetRepository,
|
||||
getByControllerIdAndThrowIfNotFound(controllerId));
|
||||
|
||||
targetMetadataRepository.deleteById(metadata.getId());
|
||||
// target update event is set to ignore "lastModifiedAt" field, so it is
|
||||
// not send automatically within the touch() method
|
||||
@@ -256,10 +264,10 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Page<TargetMetadata> findMetaDataByControllerId(final Pageable pageable, final String controllerId) {
|
||||
final Long targetId = getByControllerIdAndThrowIfNotFound(controllerId).getId();
|
||||
final Long id = getByControllerIdAndThrowIfNotFound(controllerId).getId();
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetMetadataRepository, pageable,
|
||||
Collections.singletonList(metadataByTargetIdSpec(targetId)));
|
||||
Collections.singletonList(metadataByTargetIdSpec(id)));
|
||||
}
|
||||
|
||||
private Specification<JpaTargetMetadata> metadataByTargetIdSpec(final Long targetId) {
|
||||
@@ -295,7 +303,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable, null);
|
||||
return targetRepository.findAllWithoutCount(pageable).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -304,15 +312,17 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetFilterQuery.class, targetFilterQueryId));
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable,
|
||||
Collections.singletonList(RSQLUtility.buildRsqlSpecification(targetFilterQuery.getQuery(),
|
||||
TargetFields.class, virtualPropertyReplacer, database)));
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery.getQuery(), TargetFields.class,
|
||||
virtualPropertyReplacer, database)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByRsql(final Pageable pageable, final String targetFilterQuery) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageable,
|
||||
Collections.singletonList(RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
|
||||
virtualPropertyReplacer, database)));
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class,
|
||||
virtualPropertyReplacer, database)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -340,48 +350,38 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Collection<Long> targetIDs) {
|
||||
final List<JpaTarget> targets = targetRepository.findAll(TargetSpecifications.hasIdIn(targetIDs));
|
||||
|
||||
if (targets.size() < targetIDs.size()) {
|
||||
throw new EntityNotFoundException(Target.class, targetIDs,
|
||||
targets.stream().map(Target::getId).collect(Collectors.toList()));
|
||||
public void delete(final Collection<Long> ids) {
|
||||
final List<JpaTarget> targets = targetRepository.findAllById(ids);
|
||||
if (targets.size() < ids.size()) {
|
||||
throw new EntityNotFoundException(Target.class, ids,
|
||||
targets.stream().map(Target::getId).filter(id -> !ids.contains(id)).toList());
|
||||
}
|
||||
|
||||
targetRepository.deleteByIdIn(targetIDs);
|
||||
|
||||
afterCommit
|
||||
.afterCommit(() -> targets.forEach(target -> eventPublisherHolder.getEventPublisher()
|
||||
.publishEvent(new TargetDeletedEvent(tenantAware.getCurrentTenant(), target.getId(),
|
||||
target.getControllerId(),
|
||||
Optional.ofNullable(target.getAddress()).map(URI::toString).orElse(null),
|
||||
JpaTarget.class, eventPublisherHolder.getApplicationId()))));
|
||||
targetRepository.deleteAll(targets);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void deleteByControllerID(final String controllerID) {
|
||||
final Target target = getByControllerIdAndThrowIfNotFound(controllerID);
|
||||
|
||||
targetRepository.deleteById(target.getId());
|
||||
public void deleteByControllerID(final String controllerId) {
|
||||
targetRepository.delete(getByControllerIdAndThrowIfNotFound(controllerId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findByAssignedDistributionSet(final Pageable pageReq, final long distributionSetID) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetID);
|
||||
public Page<Target> findByAssignedDistributionSet(final Pageable pageReq, final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageReq,
|
||||
Collections.singletonList(TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId())));
|
||||
List.of(TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findByAssignedDistributionSetAndRsql(final Pageable pageReq, final long distributionSetID,
|
||||
public Page<Target> findByAssignedDistributionSetAndRsql(final Pageable pageReq, final long distributionSetId,
|
||||
final String rsqlParam) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetID);
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, TargetFields.class, virtualPropertyReplacer, database),
|
||||
TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId()));
|
||||
|
||||
@@ -389,11 +389,11 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Target> findByInstalledDistributionSet(final Pageable pageReq, final long distributionSetID) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetID);
|
||||
public Page<Target> findByInstalledDistributionSet(final Pageable pageReq, final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageReq,
|
||||
Collections.singletonList(TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId())));
|
||||
List.of(TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId())));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -401,7 +401,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final String rsqlParam) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RSQLUtility.buildRsqlSpecification(rsqlParam, TargetFields.class, virtualPropertyReplacer, database),
|
||||
TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId()));
|
||||
|
||||
@@ -411,7 +411,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Override
|
||||
public Page<Target> findByUpdateStatus(final Pageable pageable, final TargetUpdateStatus status) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageable,
|
||||
Collections.singletonList(TargetSpecifications.hasTargetUpdateStatus(status)));
|
||||
List.of(TargetSpecifications.hasTargetUpdateStatus(status)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -440,7 +440,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
specList.add(TargetSpecifications.hasInstalledOrAssignedDistributionSet(validDistSet.getId()));
|
||||
}
|
||||
if (!StringUtils.isEmpty(filterParams.getFilterBySearchText())) {
|
||||
if (!ObjectUtils.isEmpty(filterParams.getFilterBySearchText())) {
|
||||
specList.add(TargetSpecifications.likeControllerIdOrName(filterParams.getFilterBySearchText()));
|
||||
}
|
||||
if (hasTagsFilterActive(filterParams)) {
|
||||
@@ -481,11 +481,10 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
final TargetTag tag = targetTagRepository.findByNameEquals(tagName)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, tagName));
|
||||
final List<JpaTarget> allTargets = targetRepository
|
||||
.findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
|
||||
.findAll(AccessController.Operation.UPDATE, TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
if (allTargets.size() < controllerIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, controllerIds,
|
||||
allTargets.stream().map(Target::getControllerId).collect(Collectors.toList()));
|
||||
allTargets.stream().map(Target::getControllerId).toList());
|
||||
}
|
||||
|
||||
final List<JpaTarget> alreadyAssignedTargets = targetRepository.findAll(
|
||||
@@ -516,7 +515,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetTypeAssignmentResult assignType(final Collection<String> controllerIds, final Long typeId) {
|
||||
final TargetType type = targetTypeRepository.findById(typeId)
|
||||
final JpaTargetType type = targetTypeRepository.findById(typeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetType.class, typeId));
|
||||
|
||||
final List<JpaTarget> targetsWithSameType = findTargetsByInSpecification(controllerIds,
|
||||
@@ -529,9 +528,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
targetsWithoutSameType.forEach(target -> target.setTargetType(type));
|
||||
|
||||
final TargetTypeAssignmentResult result = new TargetTypeAssignmentResult(targetsWithSameType.size(),
|
||||
Collections.unmodifiableList(
|
||||
targetsWithoutSameType.stream().map(targetRepository::save).collect(Collectors.toList())),
|
||||
Collections.emptyList(), type);
|
||||
targetsWithoutSameType.stream().map(targetRepository::save).toList(), Collections.emptyList(), type);
|
||||
|
||||
// no reason to persist the type
|
||||
entityManager.detach(type);
|
||||
@@ -542,26 +539,25 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetTypeAssignmentResult unAssignType(final Collection<String> controllerIds) {
|
||||
public TargetTypeAssignmentResult unassignType(final Collection<String> controllerIds) {
|
||||
final List<JpaTarget> allTargets = findTargetsByInSpecification(controllerIds, null);
|
||||
|
||||
if (allTargets.size() < controllerIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, controllerIds,
|
||||
allTargets.stream().map(Target::getControllerId).collect(Collectors.toList()));
|
||||
allTargets.stream().map(Target::getControllerId).toList());
|
||||
}
|
||||
|
||||
// set new target type to null for all targets
|
||||
allTargets.forEach(target -> target.setTargetType(null));
|
||||
|
||||
return new TargetTypeAssignmentResult(0, Collections.emptyList(), Collections
|
||||
.unmodifiableList(allTargets.stream().map(targetRepository::save).collect(Collectors.toList())), null);
|
||||
return new TargetTypeAssignmentResult(0, Collections.emptyList(), targetRepository.saveAll(allTargets), null);
|
||||
}
|
||||
|
||||
private List<JpaTarget> findTargetsByInSpecification(final Collection<String> controllerIds,
|
||||
final Specification<JpaTarget> specification) {
|
||||
return Lists.partition(new ArrayList<>(controllerIds), Constants.MAX_ENTRIES_IN_STATEMENT).stream()
|
||||
.map(ids -> targetRepository.findAll(TargetSpecifications.hasControllerIdIn(ids).and(specification)))
|
||||
.flatMap(List::stream).collect(Collectors.toList());
|
||||
.flatMap(List::stream).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -569,13 +565,11 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<Target> assignTag(final Collection<String> controllerIds, final long tagId) {
|
||||
|
||||
final List<JpaTarget> allTargets = targetRepository
|
||||
.findAll(TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
|
||||
.findAll(AccessController.Operation.UPDATE, TargetSpecifications.byControllerIdWithTagsInJoin(controllerIds));
|
||||
if (allTargets.size() < controllerIds.size()) {
|
||||
throw new EntityNotFoundException(Target.class, controllerIds,
|
||||
allTargets.stream().map(Target::getControllerId).collect(Collectors.toList()));
|
||||
allTargets.stream().map(Target::getControllerId).toList());
|
||||
}
|
||||
|
||||
final JpaTargetTag tag = targetTagRepository.findById(tagId)
|
||||
@@ -583,8 +577,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
allTargets.forEach(target -> target.addTag(tag));
|
||||
|
||||
final List<Target> result = allTargets.stream().map(targetRepository::save)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
final List<Target> result = allTargets.stream().map(targetRepository::save).map(Target.class::cast).toList();
|
||||
|
||||
// No reason to save the tag
|
||||
entityManager.detach(tag);
|
||||
@@ -595,8 +588,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target unAssignTag(final String controllerID, final long targetTagId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerID);
|
||||
public Target unassignTag(final String controllerId, final long targetTagId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
|
||||
final TargetTag tag = targetTagRepository.findById(targetTagId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagId));
|
||||
@@ -614,8 +607,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target unAssignType(final String controllerID) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerID);
|
||||
public Target unassignType(final String controllerId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
target.setTargetType(null);
|
||||
return targetRepository.save(target);
|
||||
}
|
||||
@@ -624,8 +617,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target assignType(final String controllerID, final Long targetTypeId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerID);
|
||||
public Target assignType(final String controllerId, final Long targetTypeId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
final JpaTargetType targetType = getTargetTypeByIdAndThrowIfNotFound(targetTypeId);
|
||||
target.setTargetType(targetType);
|
||||
return targetRepository.save(target);
|
||||
@@ -633,64 +626,67 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByFilterOrderByLinkedDistributionSet(final Pageable pageable,
|
||||
final long orderByDistributionId, final FilterParams filterParams) {
|
||||
final long orderByDistributionSetId, final FilterParams filterParams) {
|
||||
// remove default sort from pageable to not overwrite sorted spec
|
||||
final OffsetBasedPageRequest unsortedPage = new OffsetBasedPageRequest(pageable.getOffset(),
|
||||
pageable.getPageSize(), Sort.unsorted());
|
||||
|
||||
final List<Specification<JpaTarget>> specList = buildSpecificationList(filterParams);
|
||||
specList.add(TargetSpecifications.orderedByLinkedDistributionSet(orderByDistributionId, pageable.getSort()));
|
||||
specList.add(TargetSpecifications.orderedByLinkedDistributionSet(orderByDistributionSetId, pageable.getSort()));
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, unsortedPage, specList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByAssignedDistributionSet(final long distId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distId));
|
||||
public long countByAssignedDistributionSet(final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
|
||||
|
||||
return targetRepository.count(TargetSpecifications.hasAssignedDistributionSet(validDistSet.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByInstalledDistributionSet(final long distId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distId));
|
||||
public long countByInstalledDistributionSet(final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
|
||||
|
||||
return targetRepository.count(TargetSpecifications.hasInstalledDistributionSet(validDistSet.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsByInstalledOrAssignedDistributionSet(final long distId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distId));
|
||||
public boolean existsByInstalledOrAssignedDistributionSet(final long distributionSetId) {
|
||||
final DistributionSet validDistSet = distributionSetManagement.getOrElseThrowException((distributionSetId));
|
||||
|
||||
return targetRepository
|
||||
.exists(TargetSpecifications.hasInstalledOrAssignedDistributionSet(validDistSet.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByTargetFilterQueryAndNonDSAndCompatible(final Pageable pageRequest,
|
||||
final long distributionSetId, final String targetFilterQuery) {
|
||||
public Slice<Target> findByTargetFilterQueryAndNonDSAndCompatibleAndUpdatable(final Pageable pageRequest,
|
||||
final long distributionSetId, final String targetFilterQuery) {
|
||||
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
final Long distSetTypeId = jpaDistributionSet.getType().getId();
|
||||
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId));
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageRequest, specList);
|
||||
return targetRepository.findAllWithoutCount(
|
||||
AccessController.Operation.UPDATE,
|
||||
JpaManagementHelper.combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))),
|
||||
pageRequest).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<Target> findByTargetFilterQueryAndNotInRolloutGroupsAndCompatible(final Pageable pageRequest,
|
||||
final Collection<Long> groups, final String targetFilterQuery, final DistributionSetType dsType) {
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()));
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageRequest, specList);
|
||||
public Slice<Target> findByTargetFilterQueryAndNotInRolloutGroupsAndCompatibleAndUpdatable(
|
||||
final Pageable pageRequest, final Collection<Long> groups, final String targetFilterQuery,
|
||||
final DistributionSetType dsType) {
|
||||
return targetRepository.findAllWithoutCount(
|
||||
AccessController.Operation.UPDATE,
|
||||
JpaManagementHelper.combineWithAnd(List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))),
|
||||
pageRequest).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -711,19 +707,18 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetRepository, pageRequest,
|
||||
Collections.singletonList(TargetSpecifications.hasNoActionInRolloutGroup(group)));
|
||||
List.of(TargetSpecifications.hasNoActionInRolloutGroup(group)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndNotInRolloutGroupsAndCompatible(final Collection<Long> groups,
|
||||
final String targetFilterQuery, final DistributionSetType dsType) {
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()));
|
||||
|
||||
return JpaManagementHelper.countBySpec(targetRepository, specList);
|
||||
public long countByRsqlAndNotInRolloutGroupsAndCompatibleAndUpdatable(final Collection<Long> groups,
|
||||
final String targetFilterQuery, final DistributionSetType dsType) {
|
||||
return targetRepository.count(AccessController.Operation.UPDATE, JpaManagementHelper.combineWithAnd(
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isNotInRolloutGroups(groups),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsType.getId()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -736,17 +731,17 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndNonDSAndCompatible(final long distributionSetId, final String targetFilterQuery) {
|
||||
public long countByRsqlAndNonDSAndCompatibleAndUpdatable(final long distributionSetId,
|
||||
final String targetFilterQuery) {
|
||||
final DistributionSet jpaDistributionSet = distributionSetManagement.getOrElseThrowException(distributionSetId);
|
||||
final Long distSetTypeId = jpaDistributionSet.getType().getId();
|
||||
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId));
|
||||
|
||||
return JpaManagementHelper.countBySpec(targetRepository, specList);
|
||||
return targetRepository.count(AccessController.Operation.UPDATE, JpaManagementHelper.combineWithAnd(
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.hasNotDistributionSetInActions(distributionSetId),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distSetTypeId))));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -755,7 +750,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public Target create(final TargetCreate c) {
|
||||
final JpaTargetCreate create = (JpaTargetCreate) c;
|
||||
return targetRepository.save(create.build());
|
||||
return targetRepository.save(AccessController.Operation.CREATE, create.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -764,8 +759,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<Target> create(final Collection<TargetCreate> targets) {
|
||||
final List<JpaTarget> targetList = targets.stream().map(JpaTargetCreate.class::cast).map(JpaTargetCreate::build)
|
||||
.collect(Collectors.toList());
|
||||
return Collections.unmodifiableList(targetRepository.saveAll(targetList));
|
||||
.toList();
|
||||
return Collections.unmodifiableList(targetRepository.saveAll(AccessController.Operation.CREATE, targetList));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -773,7 +768,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
throwEntityNotFoundExceptionIfTagDoesNotExist(tagId);
|
||||
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageable,
|
||||
Collections.singletonList(TargetSpecifications.hasTag(tagId)));
|
||||
List.of(TargetSpecifications.hasTag(tagId)));
|
||||
}
|
||||
|
||||
private void throwEntityNotFoundExceptionIfTagDoesNotExist(final Long tagId) {
|
||||
@@ -803,15 +798,19 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public long countByRsql(final String targetFilterQuery) {
|
||||
return JpaManagementHelper.countBySpec(targetRepository, Collections.singletonList(RSQLUtility
|
||||
.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database)));
|
||||
return JpaManagementHelper.countBySpec(
|
||||
targetRepository,
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(
|
||||
targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long countByRsqlAndCompatible(final String targetFilterQuery, final Long dsTypeId) {
|
||||
final List<Specification<JpaTarget>> specList = Arrays.asList(RSQLUtility
|
||||
.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer, database),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(dsTypeId));
|
||||
public long countByRsqlAndCompatible(final String targetFilterQuery, final Long distributionSetId) {
|
||||
final List<Specification<JpaTarget>> specList = List.of(
|
||||
RSQLUtility.buildRsqlSpecification(targetFilterQuery, TargetFields.class, virtualPropertyReplacer,
|
||||
database),
|
||||
TargetSpecifications.isCompatibleWithDistributionSetType(distributionSetId));
|
||||
|
||||
return JpaManagementHelper.countBySpec(targetRepository, specList);
|
||||
}
|
||||
@@ -826,7 +825,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Optional<Target> get(final long id) {
|
||||
return targetRepository.findById(id).map(t -> t);
|
||||
return targetRepository.findById(id).map(Target.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -836,6 +835,8 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
|
||||
@Override
|
||||
public Map<String, String> getControllerAttributes(final String controllerId) {
|
||||
getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Object[]> query = cb.createQuery(Object[].class);
|
||||
|
||||
@@ -855,9 +856,7 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Override
|
||||
public void requestControllerAttributes(final String controllerId) {
|
||||
final JpaTarget target = getByControllerIdAndThrowIfNotFound(controllerId);
|
||||
|
||||
target.setRequestControllerAttributes(true);
|
||||
|
||||
eventPublisherHolder.getEventPublisher()
|
||||
.publishEvent(new TargetAttributesRequestedEvent(tenantAware.getCurrentTenant(), target.getId(),
|
||||
target.getControllerId(), target.getAddress() != null ? target.getAddress().toString() : null,
|
||||
@@ -898,7 +897,6 @@ public class JpaTargetManagement implements TargetManagement {
|
||||
@Override
|
||||
public Page<Target> findByControllerAttributesRequested(final Pageable pageReq) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetRepository, pageReq,
|
||||
Collections.singletonList(TargetSpecifications.hasRequestControllerAttributesTrue()));
|
||||
List.of(TargetSpecifications.hasRequestControllerAttributesTrue()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,24 +7,27 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TagFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTagFields;
|
||||
import org.eclipse.hawkbit.repository.TargetTagManagement;
|
||||
import org.eclipse.hawkbit.repository.builder.GenericTagUpdate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagCreate;
|
||||
import org.eclipse.hawkbit.repository.builder.TagUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTagCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag_;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TagSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
@@ -49,14 +52,14 @@ import org.springframework.validation.annotation.Validated;
|
||||
public class JpaTargetTagManagement implements TargetTagManagement {
|
||||
|
||||
private final TargetTagRepository targetTagRepository;
|
||||
|
||||
private final TargetRepository targetRepository;
|
||||
|
||||
private final VirtualPropertyReplacer virtualPropertyReplacer;
|
||||
private final Database database;
|
||||
|
||||
public JpaTargetTagManagement(final TargetTagRepository targetTagRepository,
|
||||
final TargetRepository targetRepository, final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
public JpaTargetTagManagement(
|
||||
final TargetTagRepository targetTagRepository, final TargetRepository targetRepository,
|
||||
final VirtualPropertyReplacer virtualPropertyReplacer,
|
||||
final Database database) {
|
||||
this.targetTagRepository = targetTagRepository;
|
||||
this.targetRepository = targetRepository;
|
||||
@@ -76,7 +79,7 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
||||
public TargetTag create(final TagCreate c) {
|
||||
final JpaTagCreate create = (JpaTagCreate) c;
|
||||
|
||||
return targetTagRepository.save(create.buildTargetTag());
|
||||
return targetTagRepository.save(AccessController.Operation.CREATE, create.buildTargetTag());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,11 +87,10 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<TargetTag> create(final Collection<TagCreate> tt) {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
final Collection<JpaTagCreate> targetTags = (Collection) tt;
|
||||
|
||||
return Collections.unmodifiableList(targetTags.stream()
|
||||
.map(ttc -> targetTagRepository.save(ttc.buildTargetTag())).collect(Collectors.toList()));
|
||||
final List<JpaTargetTag> targetTagList = tt.stream().map(JpaTagCreate.class::cast)
|
||||
.map(JpaTagCreate::buildTargetTag).toList();
|
||||
return Collections.unmodifiableList(
|
||||
targetTagRepository.saveAll(AccessController.Operation.CREATE, targetTagList));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,12 +98,10 @@ public class JpaTargetTagManagement implements TargetTagManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final String targetTagName) {
|
||||
if (!targetTagRepository.existsByName(targetTagName)) {
|
||||
throw new EntityNotFoundException(TargetTag.class, targetTagName);
|
||||
}
|
||||
|
||||
// finally delete the tag itself
|
||||
targetTagRepository.deleteByName(targetTagName);
|
||||
targetTagRepository.delete(
|
||||
targetTagRepository
|
||||
.findOne(((root, query, cb) -> cb.equal(root.get(JpaTargetTag_.name), targetTagName)))
|
||||
.orElseThrow(() -> new EntityNotFoundException(TargetTag.class, targetTagName)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -7,13 +7,12 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetTypeFields;
|
||||
@@ -24,10 +23,15 @@ import org.eclipse.hawkbit.repository.builder.TargetTypeUpdate;
|
||||
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.TargetTypeInUseException;
|
||||
import org.eclipse.hawkbit.repository.jpa.JpaManagementHelper;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.builder.JpaTargetTypeCreate;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.DistributionSetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetTypeRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.rsql.RSQLUtility;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.QuotaHelper;
|
||||
@@ -87,7 +91,7 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> getByName(final String name) {
|
||||
return targetTypeRepository.findByName(name).map(TargetType.class::cast);
|
||||
return targetTypeRepository.findOne(TargetTypeSpecification.hasName(name)).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,7 +101,7 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
|
||||
@Override
|
||||
public long countByName(final String name) {
|
||||
return targetTypeRepository.countByName(name);
|
||||
return targetTypeRepository.count(TargetTypeSpecification.hasName(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,8 +109,8 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetType create(final TargetTypeCreate create) {
|
||||
final JpaTargetTypeCreate typeCreate = (JpaTargetTypeCreate) create;
|
||||
return targetTypeRepository.save(typeCreate.build());
|
||||
final JpaTargetType typeCreate = ((JpaTargetTypeCreate) create).build();
|
||||
return targetTypeRepository.save(AccessController.Operation.CREATE, typeCreate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,44 +118,47 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public List<TargetType> create(final Collection<TargetTypeCreate> creates) {
|
||||
return creates.stream().map(this::create).collect(Collectors.toList());
|
||||
final List<JpaTargetType> typeCreate =
|
||||
creates.stream().map(create -> ((JpaTargetTypeCreate) create).build()).toList();
|
||||
return Collections.unmodifiableList(targetTypeRepository.saveAll(AccessController.Operation.CREATE, typeCreate));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public void delete(final Long targetTypeId) {
|
||||
throwExceptionIfTargetTypeDoesNotExist(targetTypeId);
|
||||
public void delete(final Long id) {
|
||||
getByIdAndThrowIfNotFound(id);
|
||||
|
||||
if (targetRepository.countByTargetTypeId(targetTypeId) > 0) {
|
||||
if (targetRepository.countByTargetTypeId(id) > 0) {
|
||||
throw new TargetTypeInUseException("Cannot delete target type that is in use");
|
||||
}
|
||||
|
||||
targetTypeRepository.deleteById(targetTypeId);
|
||||
targetTypeRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<TargetType> findAll(final Pageable pageable) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetTypeRepository, pageable, null);
|
||||
return targetTypeRepository.findAllWithoutCount(pageable).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<TargetType> findByRsql(final Pageable pageable, final String rsqlParam) {
|
||||
return JpaManagementHelper.findAllWithCountBySpec(targetTypeRepository, pageable,
|
||||
Collections.singletonList(RSQLUtility.buildRsqlSpecification(rsqlParam, TargetTypeFields.class,
|
||||
virtualPropertyReplacer, database)));
|
||||
List.of(
|
||||
RSQLUtility.buildRsqlSpecification(
|
||||
rsqlParam, TargetTypeFields.class, virtualPropertyReplacer,database)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<TargetType> findByName(final Pageable pageable, final String name) {
|
||||
return JpaManagementHelper.findAllWithoutCountBySpec(targetTypeRepository, pageable,
|
||||
Collections.singletonList(TargetTypeSpecification.likeName(name)));
|
||||
List.of(TargetTypeSpecification.likeName(name)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> get(final long id) {
|
||||
return targetTypeRepository.findById(id).map(targetType -> targetType);
|
||||
return targetTypeRepository.findById(id).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,20 +168,21 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
|
||||
@Override
|
||||
public List<TargetType> findByTargetIds(final Collection<Long> targetIds) {
|
||||
return targetTypeRepository.findAll(TargetTypeSpecification.hasTarget(targetIds)).stream()
|
||||
.map(TargetType.class::cast).collect(Collectors.toList());
|
||||
return targetTypeRepository
|
||||
.findAll(TargetTypeSpecification.hasTarget(targetIds)).stream().map(TargetType.class::cast).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TargetType> findByTargetControllerId(final String controllerId) {
|
||||
return targetTypeRepository.findOne(TargetTypeSpecification.hasTargetControllerId(controllerId))
|
||||
.map(TargetType.class::cast);
|
||||
return targetTypeRepository
|
||||
.findOne(TargetTypeSpecification.hasTargetControllerId(controllerId)).map(TargetType.class::cast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TargetType> findByTargetControllerIds(final Collection<String> controllerIds) {
|
||||
return targetTypeRepository.findAll(TargetTypeSpecification.hasTargetControllerIdIn(controllerIds)).stream()
|
||||
.map(TargetType.class::cast).collect(Collectors.toList());
|
||||
return targetTypeRepository
|
||||
.findAll(TargetTypeSpecification.hasTargetControllerIdIn(controllerIds))
|
||||
.stream().map(TargetType.class::cast).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -189,7 +197,7 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
public TargetType update(final TargetTypeUpdate update) {
|
||||
final GenericTargetTypeUpdate typeUpdate = (GenericTargetTypeUpdate) update;
|
||||
|
||||
final JpaTargetType type = findTargetTypeAndThrowExceptionIfNotFound(typeUpdate.getId());
|
||||
final JpaTargetType type = getByIdAndThrowIfNotFound(typeUpdate.getId());
|
||||
|
||||
typeUpdate.getName().ifPresent((type::setName));
|
||||
typeUpdate.getDescription().ifPresent(type::setDescription);
|
||||
@@ -202,19 +210,18 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetType assignCompatibleDistributionSetTypes(final long targetTypeId,
|
||||
public TargetType assignCompatibleDistributionSetTypes(final long id,
|
||||
final Collection<Long> distributionSetTypeIds) {
|
||||
final Collection<JpaDistributionSetType> dsTypes = distributionSetTypeRepository
|
||||
.findAllById(distributionSetTypeIds);
|
||||
|
||||
if (dsTypes.size() < distributionSetTypeIds.size()) {
|
||||
throw new EntityNotFoundException(DistributionSetType.class, distributionSetTypeIds,
|
||||
dsTypes.stream().map(DistributionSetType::getId).collect(Collectors.toList()));
|
||||
dsTypes.stream().map(DistributionSetType::getId).toList());
|
||||
}
|
||||
|
||||
final JpaTargetType type = findTargetTypeAndThrowExceptionIfNotFound(targetTypeId);
|
||||
assertDistributionSetTypeQuota(targetTypeId, distributionSetTypeIds.size());
|
||||
|
||||
final JpaTargetType type = getByIdAndThrowIfNotFound(id);
|
||||
assertDistributionSetTypeQuota(id, distributionSetTypeIds.size());
|
||||
dsTypes.forEach(type::addCompatibleDistributionSetType);
|
||||
|
||||
return targetTypeRepository.save(type);
|
||||
@@ -224,27 +231,24 @@ public class JpaTargetTypeManagement implements TargetTypeManagement {
|
||||
@Transactional
|
||||
@Retryable(include = {
|
||||
ConcurrencyFailureException.class }, maxAttempts = Constants.TX_RT_MAX, backoff = @Backoff(delay = Constants.TX_RT_DELAY))
|
||||
public TargetType unassignDistributionSetType(final long targetTypeId, final long distributionSetTypeId) {
|
||||
final JpaTargetType type = findTargetTypeAndThrowExceptionIfNotFound(targetTypeId);
|
||||
findDsTypeAndThrowExceptionIfNotFound(distributionSetTypeId);
|
||||
public TargetType unassignDistributionSetType(final long id, final long distributionSetTypeId) {
|
||||
final JpaTargetType type = getByIdAndThrowIfNotFound(id);
|
||||
assertDistributionSetTypeExists(distributionSetTypeId);
|
||||
|
||||
type.removeDistributionSetType(distributionSetTypeId);
|
||||
|
||||
return targetTypeRepository.save(type);
|
||||
}
|
||||
|
||||
private JpaTargetType findTargetTypeAndThrowExceptionIfNotFound(final Long typeId) {
|
||||
return (JpaTargetType) get(typeId).orElseThrow(() -> new EntityNotFoundException(TargetType.class, typeId));
|
||||
}
|
||||
|
||||
private JpaDistributionSetType findDsTypeAndThrowExceptionIfNotFound(final Long typeId) {
|
||||
return distributionSetTypeRepository.findById(typeId)
|
||||
private void assertDistributionSetTypeExists(final Long typeId) {
|
||||
distributionSetTypeRepository
|
||||
.findById(typeId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(DistributionSetType.class, typeId));
|
||||
}
|
||||
|
||||
private void throwExceptionIfTargetTypeDoesNotExist(final Long typeId) {
|
||||
if (!targetTypeRepository.existsById(typeId)) {
|
||||
throw new EntityNotFoundException(TargetType.class, typeId);
|
||||
}
|
||||
private JpaTargetType getByIdAndThrowIfNotFound(final Long id) {
|
||||
return targetTypeRepository
|
||||
.findById(id).orElseThrow(() -> new EntityNotFoundException(TargetType.class, id));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.BATCH_ASSIGNMENTS_ENABLED;
|
||||
import static org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey.MULTI_ASSIGNMENTS_ENABLED;
|
||||
@@ -25,6 +25,7 @@ import org.eclipse.hawkbit.repository.exception.TenantConfigurationValueChangeNo
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantConfiguration;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TenantConfigurationRepository;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties;
|
||||
@@ -7,9 +7,12 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantStatsManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.LocalArtifactRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -45,11 +48,9 @@ public class JpaTenantStatsManagement implements TenantStatsManagement {
|
||||
|
||||
result.setTargets(targetRepository.count());
|
||||
result.setArtifacts(artifactRepository.countBySoftwareModuleDeleted(false));
|
||||
artifactRepository.getSumOfUndeletedArtifactSize().ifPresent(result::setOverallArtifactVolumeInBytes);
|
||||
artifactRepository.sumOfNonDeletedArtifactSize().ifPresent(result::setOverallArtifactVolumeInBytes);
|
||||
result.setActions(actionRepository.count());
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -19,12 +19,17 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.RepositoryConstants;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.SpecificationsBuilder;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -44,10 +49,10 @@ import com.google.common.collect.Lists;
|
||||
public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
|
||||
OfflineDsAssignmentStrategy(final TargetRepository targetRepository,
|
||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||
final BooleanSupplier confirmationFlowConfig) {
|
||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||
final BooleanSupplier confirmationFlowConfig) {
|
||||
super(targetRepository, afterCommit, eventPublisherHolder, actionRepository, actionStatusRepository,
|
||||
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig);
|
||||
}
|
||||
@@ -85,10 +90,30 @@ public class OfflineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds,
|
||||
final String currentUser) {
|
||||
targetIds.forEach(tIds -> targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus(
|
||||
TargetUpdateStatus.IN_SYNC, set, System.currentTimeMillis(), currentUser, tIds));
|
||||
public void setAssignedDistributionSetAndTargetStatus(
|
||||
final JpaDistributionSet set, final List<List<Long>> targetIds, final String currentUser) {
|
||||
final long now = System.currentTimeMillis();
|
||||
targetIds.forEach(targetIdsChunk -> {
|
||||
if (targetRepository.count(AccessController.Operation.UPDATE, targetRepository.byIdsSpec(targetIdsChunk)) != targetIdsChunk.size()) {
|
||||
throw new InsufficientPermissionException("No update access to all targets!");
|
||||
}
|
||||
targetRepository.setAssignedAndInstalledDistributionSetAndUpdateStatus(
|
||||
TargetUpdateStatus.IN_SYNC, set, now, currentUser, targetIdsChunk);
|
||||
// TODO AC - current problem with this approach is that the caller detach the targets and seems doesn't save them
|
||||
// targetRepository.saveAll(
|
||||
// targetRepository
|
||||
// .findAll(AccessController.Operation.UPDATE, targetRepository.byIdsSpec(targetIdsChunk))
|
||||
// .stream()
|
||||
// .peek(target -> {
|
||||
// target.setAssignedDistributionSet(set);
|
||||
// target.setInstalledDistributionSet(set);
|
||||
// target.setInstallationDate(now);
|
||||
// target.setLastModifiedAt(now);
|
||||
// target.setLastModifiedBy(currentUser);
|
||||
// target.setUpdateStatus(TargetUpdateStatus.IN_SYNC);
|
||||
// })
|
||||
// .toList());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -22,12 +22,17 @@ import org.eclipse.hawkbit.repository.QuotaManagement;
|
||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionAssignEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.MultiActionCancelEvent;
|
||||
import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.configuration.Constants;
|
||||
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionStatusRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetSpecifications;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
@@ -47,10 +52,10 @@ import com.google.common.collect.Lists;
|
||||
public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
|
||||
OnlineDsAssignmentStrategy(final TargetRepository targetRepository,
|
||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||
final BooleanSupplier confirmationFlowConfig) {
|
||||
final AfterTransactionCommitExecutor afterCommit, final EventPublisherHolder eventPublisherHolder,
|
||||
final ActionRepository actionRepository, final ActionStatusRepository actionStatusRepository,
|
||||
final QuotaManagement quotaManagement, final BooleanSupplier multiAssignmentsConfig,
|
||||
final BooleanSupplier confirmationFlowConfig) {
|
||||
super(targetRepository, afterCommit, eventPublisherHolder, actionRepository, actionStatusRepository,
|
||||
quotaManagement, multiAssignmentsConfig, confirmationFlowConfig);
|
||||
}
|
||||
@@ -122,9 +127,26 @@ public class OnlineDsAssignmentStrategy extends AbstractDsAssignmentStrategy {
|
||||
@Override
|
||||
public void setAssignedDistributionSetAndTargetStatus(final JpaDistributionSet set, final List<List<Long>> targetIds,
|
||||
final String currentUser) {
|
||||
targetIds.forEach(tIds -> targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
||||
set, System.currentTimeMillis(), currentUser, tIds));
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
targetIds.forEach(targetIdsChunk -> {
|
||||
if (targetRepository.count(AccessController.Operation.UPDATE, targetRepository.byIdsSpec(targetIdsChunk)) != targetIdsChunk.size()) {
|
||||
throw new InsufficientPermissionException("No update access to all targets!");
|
||||
}
|
||||
targetRepository.setAssignedDistributionSetAndUpdateStatus(TargetUpdateStatus.PENDING,
|
||||
set, now, currentUser, targetIdsChunk);
|
||||
// TODO AC - current problem with this approach is that the caller detach the targets and seems doesn't save them
|
||||
// targetRepository.saveAll(
|
||||
// targetRepository
|
||||
// .findAll(AccessController.Operation.UPDATE, targetRepository.byIdsSpec(targetIdsChunk))
|
||||
// .stream()
|
||||
// .peek(target -> {
|
||||
// target.setAssignedDistributionSet(set);
|
||||
// target.setLastModifiedAt(now);
|
||||
// target.setLastModifiedBy(currentUser);
|
||||
// target.setUpdateStatus(TargetUpdateStatus.PENDING);
|
||||
// })
|
||||
// .toList());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,9 +56,12 @@ import org.eclipse.persistence.descriptors.DescriptorEvent;
|
||||
@Table(name = "sp_action", indexes = { @Index(name = "sp_idx_action_01", columnList = "tenant,distribution_set"),
|
||||
@Index(name = "sp_idx_action_02", columnList = "tenant,target,active"),
|
||||
@Index(name = "sp_idx_action_prim", columnList = "tenant,id") })
|
||||
@NamedEntityGraphs({ @NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }),
|
||||
@NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"),
|
||||
@NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) })
|
||||
@NamedEntityGraphs({
|
||||
@NamedEntityGraph(name = "Action.ds", attributeNodes = { @NamedAttributeNode("distributionSet") }),
|
||||
@NamedEntityGraph(name = "Action.all", attributeNodes = {
|
||||
@NamedAttributeNode("distributionSet"),
|
||||
@NamedAttributeNode(value = "target", subgraph = "target.ds") },
|
||||
subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) })
|
||||
@Entity
|
||||
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
|
||||
// sub entities
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
|
||||
/**
|
||||
* JPA implementation of {@link LocalArtifact}.
|
||||
* JPA implementation of {@link Artifact}.
|
||||
*
|
||||
*/
|
||||
@Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
|
||||
|
||||
@@ -66,14 +66,6 @@ public class JpaDistributionSetTag extends JpaTag implements DistributionSetTag,
|
||||
// Default constructor for JPA.
|
||||
}
|
||||
|
||||
public List<DistributionSet> getAssignedToDistributionSet() {
|
||||
if (assignedToDistributionSet == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(assignedToDistributionSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
||||
@@ -84,7 +76,6 @@ public class JpaDistributionSetTag extends JpaTag implements DistributionSetTag,
|
||||
public void fireUpdateEvent(final DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
||||
new DistributionSetTagUpdatedEvent(this, EventPublisherHolder.getInstance().getApplicationId()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -140,6 +140,9 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
@Max(Action.WEIGHT_MAX)
|
||||
private Integer weight;
|
||||
|
||||
@Column(name = "access_control_context", nullable = true)
|
||||
private String accessControlContext;
|
||||
|
||||
@Transient
|
||||
private transient TotalTargetCountStatus totalTargetCountStatus;
|
||||
|
||||
@@ -222,6 +225,14 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public Optional<String> getAccessControlContext() {
|
||||
return Optional.ofNullable(accessControlContext);
|
||||
}
|
||||
|
||||
public void setAccessControlContext(final String accessControlContext) {
|
||||
this.accessControlContext = accessControlContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalTargets() {
|
||||
return totalTargets;
|
||||
|
||||
@@ -84,6 +84,9 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
||||
@Column(name = "confirmation_required")
|
||||
private boolean confirmationRequired;
|
||||
|
||||
@Column(name = "access_control_context", nullable = true)
|
||||
private String accessControlContext;
|
||||
|
||||
public JpaTargetFilterQuery() {
|
||||
// Default constructor for JPA.
|
||||
}
|
||||
@@ -176,6 +179,14 @@ public class JpaTargetFilterQuery extends AbstractJpaTenantAwareBaseEntity
|
||||
this.confirmationRequired = confirmationRequired;
|
||||
}
|
||||
|
||||
public Optional<String> getAccessControlContext() {
|
||||
return Optional.ofNullable(accessControlContext);
|
||||
}
|
||||
|
||||
public void setAccessControlContext(final String accessControlContext) {
|
||||
this.accessControlContext = accessControlContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fireCreateEvent(final DescriptorEvent descriptorEvent) {
|
||||
EventPublisherHolder.getInstance().getEventPublisher().publishEvent(
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Repository interface that offers some actions that takes in account a target operation.
|
||||
*
|
||||
* @param <T> entity type
|
||||
*/
|
||||
public interface ACMRepository<T> {
|
||||
|
||||
/**
|
||||
* Saves only if the caller have access for the operation over the entity. This method could be used to
|
||||
* check CREATE access in creating an entity (save without operation would check for UPDATE access).
|
||||
*
|
||||
* @param operation access operationIf operation is <code>null</code> no access is checked! Should be used
|
||||
* only for tenant context.
|
||||
* @param entity the entity to save
|
||||
* @return the saved entity
|
||||
*/
|
||||
@NonNull
|
||||
<S extends T> S save(@Nullable AccessController.Operation operation, @NonNull final S entity);
|
||||
|
||||
/**
|
||||
* Saves only if the caller have access for the operation over all entities. This method could be used to
|
||||
* check CREATE access in creating an entity (save without operation would check for UPDATE access).
|
||||
*
|
||||
* @param operation access operationIf operation is <code>null</code> no access is checked! Should be used
|
||||
* only for tenant context.
|
||||
* @param entities the entities to save
|
||||
* @return the saved entities
|
||||
*/
|
||||
<S extends T> List<S> saveAll(@Nullable AccessController.Operation operation, final Iterable<S> entities);
|
||||
|
||||
/**
|
||||
* Returns single entry that match specification and the operation is allowed for.
|
||||
*
|
||||
* @param operation access operation. If operation is <code>null</code> no access is checked! Should be used
|
||||
* only for tenant context.
|
||||
* @param spec specification
|
||||
* @return matching entity
|
||||
*/
|
||||
@NonNull
|
||||
Optional<T> findOne(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Returns all entries that match specification and the operation is allowed for.
|
||||
*
|
||||
* @param operation access operation. If operation is <code>null</code> no access is checked! Should be used
|
||||
* only for tenant context.
|
||||
* @param spec specification
|
||||
* @return matching entities
|
||||
*/
|
||||
@NonNull
|
||||
List<T> findAll(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Returns all entries that match specification and the operation is allowed for.
|
||||
*
|
||||
* @param operation access operation. If operation is <code>null</code> no access is checked! Should be used
|
||||
* only for tenant context.
|
||||
* @param spec specification
|
||||
* @return matching entities
|
||||
*/
|
||||
@NonNull
|
||||
boolean exists(@Nullable AccessController.Operation operation, Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Returns count of all entries that match specification and the operation is allowed for.
|
||||
*
|
||||
* @param operation access operation. If operation is <code>null</code> no access is checked! Should be used
|
||||
* only for tenant context.
|
||||
* @param spec specification
|
||||
* @return count of matching entities
|
||||
*/
|
||||
@NonNull
|
||||
long count(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Returns all entries, without count, that match specification and the operation is allowed for.
|
||||
*
|
||||
* @param operation access operation. If operation is <code>null</code> no access is checked! Should be used
|
||||
* only for tenant context.
|
||||
* @param spec specification
|
||||
* @param pageable pageable
|
||||
* @return count of matching entities
|
||||
*/
|
||||
@NonNull
|
||||
Slice<T> findAllWithoutCount(
|
||||
@Nullable final AccessController.Operation operation, @Nullable Specification<T> spec, Pageable pageable);
|
||||
|
||||
@NonNull
|
||||
Class<T> getDomainClass();
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -23,15 +23,11 @@ import org.eclipse.hawkbit.repository.model.Action.Status;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -42,7 +38,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>, JpaSpecificationExecutor<JpaAction> {
|
||||
public interface ActionRepository extends BaseEntityRepository<JpaAction> {
|
||||
|
||||
/**
|
||||
* Retrieves an Action with all lazy attributes.
|
||||
*
|
||||
@@ -51,144 +48,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
* @return the found {@link Action}
|
||||
*/
|
||||
@EntityGraph(value = "Action.all", type = EntityGraphType.LOAD)
|
||||
Optional<Action> getActionById(Long actionId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param dsId
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
Page<Action> findByDistributionSetId(Pageable pageable, Long dsId);
|
||||
|
||||
/**
|
||||
* Retrieves all active {@link Action}s which are referring the given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param set
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
List<Action> findByDistributionSetAndActiveIsTrue(DistributionSet set);
|
||||
|
||||
/**
|
||||
* Retrieves all active {@link Action}s which are referring the given
|
||||
* {@link DistributionSet} and are not in the given state
|
||||
*
|
||||
* @param set
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @param status
|
||||
* the state the actions should not have
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
List<Action> findByDistributionSetAndActiveIsTrueAndStatusIsNot(DistributionSet set, Status status);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given
|
||||
* {@link Target}.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param controllerId
|
||||
* the target to find assigned actions
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
Slice<Action> findByTargetControllerId(Pageable pageable, String controllerId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given targetId
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param targetId
|
||||
* the target to find assigned actions for
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
Page<Action> findByTargetId(Pageable pageable, Long targetId);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are active and referring to the given
|
||||
* {@link Target} order by ID ascending.
|
||||
*
|
||||
* @param target
|
||||
* the target to find assigned actions
|
||||
* @param active
|
||||
* the action active flag
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
List<Action> findByTargetAndActiveOrderByIdAsc(JpaTarget target, boolean active);
|
||||
|
||||
/**
|
||||
* Retrieves the active {@link Action}s with the highest weights that refer
|
||||
* to the given {@link Target}. If {@link Action}s have the same weight they
|
||||
* are ordered ascending by ID (oldest ones first).
|
||||
*
|
||||
* @param pageable
|
||||
* pageable
|
||||
* @param controllerId
|
||||
* the target to find assigned actions
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
Page<Action> findByTargetControllerIdAndActiveIsTrueAndWeightIsNotNullOrderByWeightDescIdAsc(Pageable pageable,
|
||||
String controllerId);
|
||||
|
||||
/**
|
||||
* Retrieves the active {@link Action}s with the lowest IDs (the oldest one)
|
||||
* whose weight is null and that that refers to the given {@link Target}.
|
||||
*
|
||||
* @param pageable
|
||||
* pageable
|
||||
* @param controllerId
|
||||
* the target to find assigned actions
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
Page<Action> findByTargetControllerIdAndActiveIsTrueAndWeightIsNullOrderByIdAsc(Pageable pageable,
|
||||
String controllerId);
|
||||
|
||||
/**
|
||||
* Checks if an active action exists for given
|
||||
* {@link Target#getControllerId()}.
|
||||
*
|
||||
* @param controllerId
|
||||
* of target to check
|
||||
* @return <code>true</code> if an active action for the target exists.
|
||||
*/
|
||||
@Query("SELECT CASE WHEN COUNT(a)>0 THEN 'true' ELSE 'false' END FROM JpaAction a JOIN a.target t WHERE t.controllerId=:controllerId AND a.active=1")
|
||||
boolean activeActionExistsForControllerId(@Param("controllerId") String controllerId);
|
||||
|
||||
/**
|
||||
* Check if any active actions with given action status and given controller
|
||||
* ID exist.
|
||||
*
|
||||
* @param controllerId
|
||||
* of the target to check for actions
|
||||
* @param currentStatus
|
||||
* of the active action to look for
|
||||
*
|
||||
* @return <code>true</code> if one or more active actions for the given
|
||||
* controllerId and action status are found
|
||||
*/
|
||||
boolean existsByTargetControllerIdAndStatusAndActiveIsTrue(String controllerId, Action.Status currentStatus);
|
||||
|
||||
/**
|
||||
* Retrieves latest {@link Action} for given target and
|
||||
* {@link SoftwareModule}.
|
||||
*
|
||||
* @param targetId
|
||||
* to search for
|
||||
* @param moduleId
|
||||
* to search for
|
||||
* @return action if there is one with assigned target and module is part of
|
||||
* assigned {@link DistributionSet}.
|
||||
*/
|
||||
@Query("Select a from JpaAction a join a.distributionSet ds join ds.modules modul where a.target.controllerId = :target and modul.id = :module order by a.id desc")
|
||||
List<Action> findActionByTargetAndSoftwareModule(@Param("target") String targetId, @Param("module") Long moduleId);
|
||||
Optional<Action> findWithDetailsById(Long actionId);
|
||||
|
||||
/**
|
||||
* Retrieves the latest finished {@link Action} for given target and {@link DistributionSet}.
|
||||
@@ -205,55 +65,11 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
Optional<Action> findFirstByTargetIdAndDistributionSetIdAndStatusOrderByIdDesc(@Param("target") long targetId,
|
||||
@Param("ds") Long dsId, @Param("status") Action.Status status);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s which are referring the given
|
||||
* {@link DistributionSet} and {@link Target}.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param target
|
||||
* is the assigned target
|
||||
* @param ds
|
||||
* the {@link DistributionSet} on which will be filtered
|
||||
* @return the found {@link Action}s
|
||||
*/
|
||||
@Query("Select a from JpaAction a where a.target = :target and a.distributionSet = :ds")
|
||||
Page<JpaAction> findByTargetAndDistributionSet(Pageable pageable, @Param("target") JpaTarget target,
|
||||
@Param("ds") JpaDistributionSet ds);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target, without pagination
|
||||
* ordered by action ID.
|
||||
*
|
||||
* @param target
|
||||
* to search for
|
||||
* @return a list of actions according to the searched target
|
||||
*/
|
||||
@Query("Select a from JpaAction a where a.target = :target order by a.id")
|
||||
List<JpaAction> findByTarget(@Param("target") Target target);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s of a specific target and given active flag
|
||||
* ordered by action ID. Loads also the lazy {@link Action#getDistributionSet()}
|
||||
* field.
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param controllerId
|
||||
* to search for
|
||||
* @param active
|
||||
* {@code true} for all actions which are currently active,
|
||||
* {@code false} for inactive
|
||||
* @return a list of actions
|
||||
*/
|
||||
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
|
||||
@Query("Select a from JpaAction a where a.target.controllerId = :controllerId and a.active = :active")
|
||||
Page<Action> findByActiveAndTarget(Pageable pageable, @Param("controllerId") String controllerId,
|
||||
@Param("active") boolean active);
|
||||
|
||||
/**
|
||||
* Switches the status of actions from one specific status into another, only if
|
||||
* the actions are in a specific status. This should be a atomar operation.
|
||||
* the actions are in a specific status. This should be a atomic operation.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param statusToSet
|
||||
* the new status the actions should get
|
||||
@@ -270,27 +86,15 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
void switchStatus(@Param("statusToSet") Action.Status statusToSet, @Param("targetsIds") List<Long> targetIds,
|
||||
@Param("active") boolean active, @Param("currentStatus") Action.Status currentStatus);
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves all active {@link Action}s by given controllerId filtered by a
|
||||
* status
|
||||
*
|
||||
* @param controllerId
|
||||
* the IDs of targets for the actions
|
||||
* @param status
|
||||
* the current status of the actions
|
||||
* @return the found list of {@link Action}
|
||||
*/
|
||||
@Query("SELECT a FROM JpaAction a WHERE a.target.controllerId = :controllerId AND a.active = true AND a.status = :status")
|
||||
List<JpaAction> findByTargetIdAndIsActiveAndActionStatus(@Param("controllerId") String controllerId,
|
||||
@Param("status") Action.Status status);
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves all IDs for {@link Action}s referring to the given target IDs,
|
||||
* active flag, current status and distribution set not requiring migration
|
||||
* step.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @deprecated will be removed
|
||||
* @param targetIds
|
||||
* the IDs of targets for the actions
|
||||
* @param active
|
||||
@@ -299,23 +103,12 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
* the current status of the actions
|
||||
* @return the found list of {@link Action} IDs
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@Query("SELECT a.id FROM JpaAction a WHERE a.target IN :targetsIds AND a.active = :active AND a.status = :currentStatus AND a.distributionSet.requiredMigrationStep = false")
|
||||
List<Long> findByTargetIdInAndIsActiveAndActionStatusAndDistributionSetNotRequiredMigrationStep(
|
||||
@Param("targetsIds") List<Long> targetIds, @Param("active") boolean active,
|
||||
@Param("currentStatus") Action.Status currentStatus);
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Action}s that matches the queried externalRefs.
|
||||
*
|
||||
* @param externalRefs
|
||||
* for which the actions need to be found
|
||||
* @param active
|
||||
* flag to indicate active/inactive actions
|
||||
* @return list of actions
|
||||
*/
|
||||
List<Action> findByExternalRefInAndActive(@Param("externalRefs") List<String> externalRefs,
|
||||
@Param("active") boolean active);
|
||||
|
||||
/**
|
||||
* Retrieves an {@link Action} that matches the queried externalRef.
|
||||
*
|
||||
@@ -328,7 +121,10 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Switches the status of actions from one specific status into another for
|
||||
* given actions IDs, active flag and current status
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @deprecated will be removed
|
||||
* @param statusToSet
|
||||
* the new status the actions should get
|
||||
* @param actionIds
|
||||
@@ -339,6 +135,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
* the current status of the actions
|
||||
* @return the amount of updated actions
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE JpaAction a SET a.status = :statusToSet WHERE a.id IN :actionIds AND a.active = :active AND a.status = :currentStatus")
|
||||
@@ -346,37 +143,10 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
@Param("actionIds") List<Long> actionIds, @Param("active") boolean active,
|
||||
@Param("currentStatus") Action.Status currentStatus);
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves all {@link Action}s which are active and referring to the given
|
||||
* target Ids and distribution set not requiring migration step.
|
||||
*
|
||||
* @param targetIds
|
||||
* the IDs of targets for the actions
|
||||
* @param notStatus
|
||||
* the status which the actions should not have
|
||||
* @return the found list of {@link Action}s
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target" }, type = EntityGraphType.LOAD)
|
||||
@Query("SELECT a FROM JpaAction a WHERE a.active = true AND a.distributionSet.requiredMigrationStep = false AND a.target IN ?1 AND a.status != ?2")
|
||||
List<JpaAction> findByActiveAndTargetIdInAndActionStatusNotEqualToAndDistributionSetNotRequiredMigrationStep(
|
||||
Collection<Long> targetIds, Action.Status notStatus);
|
||||
|
||||
/**
|
||||
*
|
||||
* Retrieves all {@link Action}s which are active and referring to the given
|
||||
* target Ids and distribution set not requiring migration step.
|
||||
*
|
||||
* @param targetIds
|
||||
* the IDs of targets for the actions
|
||||
* @return the found list of {@link Action}s
|
||||
*/
|
||||
@EntityGraph(attributePaths = { "target" }, type = EntityGraphType.LOAD)
|
||||
@Query("SELECT a FROM JpaAction a WHERE a.active = true AND a.distributionSet.requiredMigrationStep = false AND a.target IN ?1")
|
||||
List<JpaAction> findByActiveAndTargetIdInAndDistributionSetNotRequiredMigrationStep(Collection<Long> targetIds);
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given target.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param controllerId
|
||||
* the target to count the {@link Action}s
|
||||
@@ -386,6 +156,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given targetId.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param targetId
|
||||
* the target to count the {@link Action}s
|
||||
@@ -395,6 +167,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Counts all {@link Action}s referring to the given DistributionSet.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
@@ -404,6 +178,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
@@ -414,6 +190,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Counts all active {@link Action}s referring to the given DistributionSet
|
||||
* that are not in a given state.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param distributionSet
|
||||
* DistributionSet to count the {@link Action}s from
|
||||
@@ -428,6 +206,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
* are currently not in the given status. An in-clause statement does not
|
||||
* work with the spring-data, so this is specific usecase regarding to the
|
||||
* rollout-management to find out actions which are not in specific states.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout the actions are belong to
|
||||
@@ -443,6 +223,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout and rolloutgroup.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rollout
|
||||
* the rollout the actions belong to
|
||||
@@ -454,6 +236,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout, rolloutgroup and status.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of rollout the actions belong to
|
||||
@@ -468,6 +252,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Counts all actions referring to a given rollout and status.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout the actions belong to
|
||||
@@ -481,6 +267,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout the actions belong to
|
||||
@@ -493,6 +281,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Returns {@code true} if actions for the given rollout exists, otherwise
|
||||
* {@code false}
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId
|
||||
* the ID of the rollout the actions belong to
|
||||
@@ -507,8 +297,10 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Retrieving all actions referring to a given rollout with a specific action as
|
||||
* parent reference and a specific status.
|
||||
*
|
||||
* <p/>
|
||||
* Finding all actions of a specific rolloutgroup parent relation.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
@@ -527,6 +319,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Retrieving all actions referring to the first group of a rollout.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
@@ -544,6 +338,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
|
||||
/**
|
||||
* Retrieves all actions for a specific rollout and in a specific status.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
@@ -558,6 +354,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId
|
||||
* id of {@link Rollout}
|
||||
@@ -569,6 +367,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutId
|
||||
* id of {@link Rollout}
|
||||
@@ -580,6 +380,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout group.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutGroupId
|
||||
* id of {@link RolloutGroup}
|
||||
@@ -591,6 +393,8 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
/**
|
||||
* Get list of objects which has details of status and count of targets in
|
||||
* each status in specified rollout group.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param rolloutGroupId
|
||||
* list of id of {@link RolloutGroup}
|
||||
@@ -599,18 +403,6 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
@Query("SELECT NEW org.eclipse.hawkbit.repository.model.TotalTargetCountActionStatus(a.rolloutGroup.id, a.status , COUNT(a.id)) FROM JpaAction a WHERE a.rolloutGroup.id IN ?1 GROUP BY a.rolloutGroup.id, a.status")
|
||||
List<TotalTargetCountActionStatus> getStatusCountByRolloutGroupId(List<Long> rolloutGroupId);
|
||||
|
||||
/**
|
||||
* Deletes all actions with the given IDs.
|
||||
*
|
||||
* @param actionIDs
|
||||
* the IDs of the actions to be deleted.
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("DELETE FROM JpaAction a WHERE a.id IN ?1")
|
||||
void deleteByIdIn(Collection<Long> actionIDs);
|
||||
|
||||
/**
|
||||
* Updates the externalRef of an action by its actionId.
|
||||
*
|
||||
@@ -623,4 +415,16 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
|
||||
@Transactional
|
||||
@Query("UPDATE JpaAction a SET a.externalRef = :externalRef WHERE a.id = :actionId")
|
||||
void updateExternalRef(@Param("actionId") Long actionId, @Param("externalRef") String externalRef);
|
||||
|
||||
/**
|
||||
* Deletes all actions with the given IDs.
|
||||
*
|
||||
* @param actionIDs
|
||||
* the IDs of the actions to be deleted.
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("DELETE FROM JpaAction a WHERE a.id IN ?1")
|
||||
void deleteByIdIn(Collection<Long> actionIDs);
|
||||
}
|
||||
@@ -7,17 +7,13 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaActionStatus;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.ActionStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -27,25 +23,15 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface ActionStatusRepository
|
||||
extends BaseEntityRepository<JpaActionStatus, Long>, JpaSpecificationExecutor<JpaActionStatus> {
|
||||
public interface ActionStatusRepository extends BaseEntityRepository<JpaActionStatus> {
|
||||
|
||||
/**
|
||||
* Counts {@link ActionStatus} entries of given {@link Action} in
|
||||
* repository.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param action
|
||||
* to count status entries
|
||||
* @return number of actions in repository
|
||||
*/
|
||||
Long countByAction(JpaAction action);
|
||||
|
||||
/**
|
||||
* Counts {@link ActionStatus} entries of given {@link Action} in
|
||||
* repository.
|
||||
*
|
||||
* @param actionId
|
||||
* of the action to count status entries for
|
||||
* @param actionId of the action to count status entries for
|
||||
* @return number of actions in repository
|
||||
*/
|
||||
long countByActionId(Long actionId);
|
||||
@@ -53,32 +39,19 @@ public interface ActionStatusRepository
|
||||
/**
|
||||
* Retrieves all {@link ActionStatus} entries from repository of given
|
||||
* ActionId.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param pageReq
|
||||
* parameters
|
||||
* @param actionId
|
||||
* of the status entries
|
||||
* @param pageReq parameters
|
||||
* @param actionId of the status entries
|
||||
* @return pages list of {@link ActionStatus} entries
|
||||
*/
|
||||
Page<ActionStatus> findByActionId(Pageable pageReq, Long actionId);
|
||||
|
||||
/**
|
||||
* Finds all status updates for the defined action and target including
|
||||
* {@link ActionStatus#getMessages()}.
|
||||
*
|
||||
* @param pageReq
|
||||
* for page configuration
|
||||
* @param target
|
||||
* to look for
|
||||
* @param actionId
|
||||
* to look for
|
||||
* @return Page with found targets
|
||||
*/
|
||||
@EntityGraph(value = "ActionStatus.withMessages", type = EntityGraphType.LOAD)
|
||||
Page<ActionStatus> getByActionId(Pageable pageReq, Long actionId);
|
||||
|
||||
/**
|
||||
* Finds a filtered list of status messages for an action.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param pageable
|
||||
* for page configuration
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaBaseEntity_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* Command repository operations for all {@link TenantAwareBaseEntity}s.
|
||||
*
|
||||
* @param <T>
|
||||
* type if the entity type
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
@Transactional(readOnly = true)
|
||||
public interface BaseEntityRepository<T extends AbstractJpaTenantAwareBaseEntity>
|
||||
extends PagingAndSortingRepository<T, Long>, CrudRepository<T, Long>, JpaSpecificationExecutor<T>,
|
||||
NoCountSliceRepository<T>, ACMRepository<T> {
|
||||
|
||||
/**
|
||||
* Overrides
|
||||
* {@link org.springframework.data.repository.CrudRepository#findAll()}
|
||||
* to return a list of found entities instead of an instance of
|
||||
* {@link Iterable} to be able to work with it directly in further code
|
||||
* processing instead of converting the {@link Iterable}.
|
||||
*
|
||||
* @return the found entities
|
||||
*/
|
||||
@Override
|
||||
List<T> findAll();
|
||||
|
||||
/**
|
||||
* Overrides
|
||||
* {@link org.springframework.data.repository.CrudRepository#findAllById(Iterable)}
|
||||
* to return a list of found entities instead of an instance of
|
||||
* {@link Iterable} to be able to work with it directly in further code
|
||||
* processing instead of converting the {@link Iterable}.
|
||||
*
|
||||
* @param ids to search in the database for
|
||||
* @return the found entities
|
||||
*/
|
||||
@Override
|
||||
List<T> findAllById(final Iterable<Long> ids);
|
||||
|
||||
/**
|
||||
* Overrides
|
||||
* {@link org.springframework.data.repository.CrudRepository#saveAll(Iterable)}
|
||||
* to return a list of created entities instead of an instance of
|
||||
* {@link Iterable} to be able to work with it directly in further code
|
||||
* processing instead of converting the {@link Iterable}.
|
||||
*
|
||||
* @param entities to persist in the database
|
||||
* @return the created entities
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
<S extends T> List<S> saveAll(Iterable<S> entities);
|
||||
|
||||
|
||||
// TODO When we switch to Spring 3.0 probably we could remove extending methods using
|
||||
// queries and make here a default implementation using JPASpecificationExecutor delete method
|
||||
// TODO To be considered if this method is needed at all
|
||||
/**
|
||||
* Deletes all entities of a given tenant from this repository. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
* manually to query even if this will be done by {@link EntityManager}
|
||||
* anyhow. The DB should take care of optimizing this away.
|
||||
* <p/>
|
||||
*
|
||||
* @param tenant to delete data from
|
||||
*/
|
||||
void deleteByTenant(String tenant);
|
||||
|
||||
/**
|
||||
* Returns a wrapper (or the same instance if access controller is <code>null</code> of this repository that
|
||||
* supports ACM.
|
||||
* <p/>
|
||||
* Note: To use ACM support the returned object shall be used! <code>this</code> object will not achieve ACM
|
||||
* support!
|
||||
* <p/>
|
||||
* Notes on ACM support (if enabled, i.e. <code>accessController</code> is not <code>null</code>):
|
||||
* <ul>
|
||||
* <li>ACM is applied for all {@link BaseEntityRepository} methods</li>
|
||||
* <li>ACM is applied for all <code>findXXX</code> methods that returns {@link Iterable}
|
||||
* (expected of <code>? extends T</code>),
|
||||
* <code>? extends T</code> or {@link java.util.Optional}(expected of <code>? extends T</code>).
|
||||
* </li>
|
||||
* <li>For all other methods defined on repository interface level that are implemented, for instance,
|
||||
* via {@link org.springframework.data.jpa.repository.Query} or using naming conventions
|
||||
* (existsBySomething) the ACM won't be applied!
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param accessController access controller to be applied to the result
|
||||
* @param entityType the entity type of the repository
|
||||
* @return a repository that supports ACM.
|
||||
*/
|
||||
default BaseEntityRepository<T> withACM(@Nullable final AccessController<T> accessController) {
|
||||
if (accessController == null) {
|
||||
return this;
|
||||
} else {
|
||||
return BaseEntityRepositoryACM.of(this, accessController);
|
||||
}
|
||||
}
|
||||
|
||||
default <T extends AbstractJpaTenantAwareBaseEntity> Specification<T> byIdSpec(final Long id) {
|
||||
return (root, query, cb) -> cb.equal(root.get(AbstractJpaBaseEntity_.id), id);
|
||||
}
|
||||
|
||||
default <T extends AbstractJpaTenantAwareBaseEntity> Specification<T> byIdsSpec(final Iterable<Long> ids) {
|
||||
final Collection<Long> collection;
|
||||
if (ids instanceof Collection<Long>) {
|
||||
collection = (Collection<Long>) ids;
|
||||
} else {
|
||||
collection = new LinkedList<>();
|
||||
ids.forEach(collection::add);
|
||||
}
|
||||
return (root, query, cb) -> root.get(AbstractJpaBaseEntity_.id).in(collection);
|
||||
}
|
||||
|
||||
default Optional<AccessController<T>> getAccessController() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.exception.InsufficientPermissionException;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.AbstractJpaTenantAwareBaseEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class BaseEntityRepositoryACM<T extends AbstractJpaTenantAwareBaseEntity> implements BaseEntityRepository<T> {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BaseEntityRepositoryACM.class);
|
||||
|
||||
private final BaseEntityRepository<T> repository;
|
||||
private final AccessController<T> accessController;
|
||||
|
||||
BaseEntityRepositoryACM(final BaseEntityRepository<T> repository, final AccessController<T> accessController) {
|
||||
this.repository = repository;
|
||||
this.accessController = accessController;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends AbstractJpaTenantAwareBaseEntity, R extends BaseEntityRepository<T>> R of(
|
||||
final R repository, @NonNull final AccessController<T> accessController) {
|
||||
Objects.requireNonNull(repository);
|
||||
Objects.requireNonNull(accessController);
|
||||
final BaseEntityRepositoryACM<T> repositoryACM =
|
||||
new BaseEntityRepositoryACM<>(repository, accessController);
|
||||
final R acmProxy = (R) Proxy.newProxyInstance(
|
||||
Thread.currentThread().getContextClassLoader(),
|
||||
repository.getClass().getInterfaces(),
|
||||
(proxy, method, args) -> {
|
||||
try {
|
||||
try {
|
||||
// TODO - cache mapping so to speed things
|
||||
final Method delegateMethod =
|
||||
BaseEntityRepositoryACM.class.getDeclaredMethod(
|
||||
method.getName(), method.getParameterTypes());
|
||||
return delegateMethod.invoke(repositoryACM, args);
|
||||
} catch (final NoSuchMethodException e) {
|
||||
// call to repository itself
|
||||
}
|
||||
if (method.getName().startsWith("find") || method.getName().startsWith("get")) {
|
||||
final Object result = method.invoke(repository, args);
|
||||
if (Iterable.class.isAssignableFrom(method.getReturnType())) {
|
||||
for (final T e : ((Iterable<T>) result)) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.READ, e);
|
||||
}
|
||||
} else if (Optional.class.isAssignableFrom(method.getReturnType())) {
|
||||
return ((Optional<T>)result).filter(t -> isOperationAllowed(AccessController.Operation.READ, t, accessController));
|
||||
} else if (repository.getDomainClass().isAssignableFrom(method.getReturnType())) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.READ, (T)result);
|
||||
}
|
||||
return result;
|
||||
} else if ("toString".equals(method.getName()) && method.getParameterCount() == 0) {
|
||||
return BaseEntityRepositoryACM.class.getSimpleName() +
|
||||
"(repository: " + repository + ", accessController: " + accessController + ")";
|
||||
} else {
|
||||
return method.invoke(repository, args);
|
||||
}
|
||||
} catch (final InvocationTargetException e) {
|
||||
throw e.getCause() == null ? e : e.getCause();
|
||||
}
|
||||
});
|
||||
LOGGER.info("Proxy created -> {}", acmProxy);
|
||||
return acmProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Optional<T> findById(@NonNull final Long id) {
|
||||
return findOne(byIdSpec(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<T> findAll() {
|
||||
return findAll((Specification<T>) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<T> findAllById(@NonNull final Iterable<Long> ids) {
|
||||
return findAll(byIdsSpec(ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsById(@NonNull final Long id) {
|
||||
return exists(byIdSpec(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count() {
|
||||
return count(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(@NonNull final T entity) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, entity);
|
||||
repository.delete(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(@NonNull final Long id) {
|
||||
if (!exists(AccessController.Operation.READ, byIdSpec(id))) {
|
||||
throw new EntityNotFoundException(repository.getDomainClass(), id);
|
||||
}
|
||||
if (!exists(AccessController.Operation.DELETE, byIdSpec(id))) {
|
||||
throw new InsufficientPermissionException();
|
||||
}
|
||||
repository.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAllById(@NonNull final Iterable<? extends Long> ids) {
|
||||
final Set<Long> idList = toSetDistinct(ids);
|
||||
if (count(AccessController.Operation.DELETE, byIdsSpec(idList)) != idList.size()) {
|
||||
throw new InsufficientPermissionException("Has at least one id that is not allowed for deletion!");
|
||||
}
|
||||
repository.deleteAllById(idList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll(@NonNull final Iterable<? extends T> entities) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.DELETE, entities);
|
||||
repository.deleteAll(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
// TODO - shall we remove deleteByTenant and implement this method instead?
|
||||
// if (accessController.getAccessRules(AccessController.Operation.DELETE).isPresent()) {
|
||||
// throw new InsufficientPermissionException(
|
||||
// "DELETE operation has restriction for given context! deleteAll can't be executed!");
|
||||
// }
|
||||
// repository.deleteAll();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public <S extends T> S save(@NonNull final S entity) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.UPDATE, entity);
|
||||
return repository.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> List<S> saveAll(final Iterable<S> entities) {
|
||||
accessController.assertOperationAllowed(AccessController.Operation.UPDATE, entities);
|
||||
return repository.saveAll(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Optional<T> findOne(final Specification<T> spec) {
|
||||
return repository.findOne(accessController.appendAccessRules(AccessController.Operation.READ, spec));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Iterable<T> findAll(@NonNull final Sort sort) {
|
||||
return findAll(null, sort);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Page<T> findAll(@NonNull final Pageable pageable) {
|
||||
return findAll(null, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<T> findAll(final Specification<T> spec) {
|
||||
return repository.findAll(accessController.appendAccessRules(AccessController.Operation.READ, spec));
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Page<T> findAll(final Specification<T> spec, @NonNull final Pageable pageable) {
|
||||
return repository.findAll(accessController.appendAccessRules(AccessController.Operation.READ, spec), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<T> findAll(final Specification<T> spec, @NonNull final Sort sort) {
|
||||
return repository.findAll(accessController.appendAccessRules(AccessController.Operation.READ, spec), sort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(@NonNull final Specification<T> spec) {
|
||||
return repository.exists(
|
||||
Objects.requireNonNull(accessController.appendAccessRules(AccessController.Operation.READ, spec)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long count(final Specification<T> spec) {
|
||||
return repository.count(accessController.appendAccessRules(AccessController.Operation.READ, spec));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<T> findAllWithoutCount(final Pageable pageable) {
|
||||
return findAllWithoutCount(null, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<T> findAllWithoutCount(final Specification<T> spec, final Pageable pageable) {
|
||||
return repository.findAllWithoutCount(
|
||||
accessController.appendAccessRules(AccessController.Operation.READ, spec), pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@NonNull
|
||||
public <S extends T> S save(@Nullable AccessController.Operation operation, @NonNull final S entity) {
|
||||
if (operation != null) {
|
||||
accessController.assertOperationAllowed(operation, entity);
|
||||
}
|
||||
return repository.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public <S extends T> List<S> saveAll(@Nullable AccessController.Operation operation, final Iterable<S> entities) {
|
||||
if (operation != null) {
|
||||
accessController.assertOperationAllowed(operation, entities);
|
||||
}
|
||||
return repository.saveAll(entities);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Optional<T> findOne(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec) {
|
||||
if (operation == null) {
|
||||
return repository.findOne(spec);
|
||||
} else {
|
||||
return repository.findOne(accessController.appendAccessRules(operation, spec));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<T> findAll(@Nullable final AccessController.Operation operation, @Nullable final Specification<T> spec) {
|
||||
if (operation == null) {
|
||||
return repository.findAll(spec);
|
||||
} else {
|
||||
return repository.findAll(accessController.appendAccessRules(operation, spec));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public boolean exists(@Nullable AccessController.Operation operation, Specification<T> spec) {
|
||||
if (operation == null) {
|
||||
return repository.exists(spec);
|
||||
} else {
|
||||
return repository.exists(
|
||||
Objects.requireNonNull(accessController.appendAccessRules(operation, spec)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public long count(@Nullable final AccessController.Operation operation, @Nullable final Specification<T> spec) {
|
||||
if (operation == null) {
|
||||
return repository.count(spec);
|
||||
} else {
|
||||
return repository.count(accessController.appendAccessRules(operation, spec));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Slice<T> findAllWithoutCount(
|
||||
@Nullable final AccessController.Operation operation, @Nullable Specification<T> spec, Pageable pageable) {
|
||||
if (operation == null) {
|
||||
return repository.findAllWithoutCount(spec, pageable);
|
||||
} else {
|
||||
return repository.findAllWithoutCount(accessController.appendAccessRules(operation, spec), pageable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Class<T> getDomainClass() {
|
||||
return repository.getDomainClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<AccessController<T>> getAccessController() {
|
||||
return Optional.of(accessController);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByTenant(final String tenant) {
|
||||
if (accessController.getAccessRules(AccessController.Operation.DELETE).isPresent()) {
|
||||
throw new InsufficientPermissionException(
|
||||
"DELETE operation has restriction for given context! deleteAll can't be executed!");
|
||||
}
|
||||
repository.deleteByTenant(tenant);
|
||||
}
|
||||
|
||||
private static <T> boolean isOperationAllowed(
|
||||
final AccessController.Operation operation, T entity,
|
||||
final AccessController<T> accessController) {
|
||||
try {
|
||||
accessController.assertOperationAllowed(operation, entity);
|
||||
return true;
|
||||
} catch (final InsufficientPermissionException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private static <T extends Long> Set<Long> toSetDistinct(final Iterable<T> i) {
|
||||
final Set<Long> set = new HashSet<>();
|
||||
i.forEach(set::add);
|
||||
return set;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.DsMetadataCompositeKey;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetMetadata;
|
||||
@@ -29,12 +29,11 @@ public interface DistributionSetMetadataRepository
|
||||
|
||||
/**
|
||||
* Counts the meta data entries that match the given distribution set ID.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param id
|
||||
* of the distribution set.
|
||||
*
|
||||
* @param id of the distribution set.
|
||||
* @return The number of matching meta data entries.
|
||||
*/
|
||||
long countByDistributionSetId(@Param("id") Long id);
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -21,11 +21,7 @@ import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Tag;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -37,34 +33,23 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface DistributionSetRepository
|
||||
extends BaseEntityRepository<JpaDistributionSet, Long>, JpaSpecificationExecutor<JpaDistributionSet> {
|
||||
|
||||
/**
|
||||
* Finds {@link DistributionSet}s by assigned {@link Tag}.
|
||||
*
|
||||
* @param pageable
|
||||
* paging and sorting information
|
||||
*
|
||||
* @param tagId
|
||||
* to be found
|
||||
* @return list of found {@link DistributionSet}s
|
||||
*/
|
||||
@Query(value = "Select Distinct ds from JpaDistributionSet ds join ds.tags dst where dst.id = :tag and ds.deleted = 0")
|
||||
Page<JpaDistributionSet> findByTag(Pageable pageable, @Param("tag") Long tagId);
|
||||
extends BaseEntityRepository<JpaDistributionSet> {
|
||||
|
||||
/**
|
||||
* Count {@link Rollout}s by Status for Distribution set.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param dsId
|
||||
* to be found
|
||||
* @param dsId to be found
|
||||
* @return map for {@link Rollout}s status counts
|
||||
*/
|
||||
@Query(value = "SELECT r.status as name, COUNT(r.status) as data FROM JpaRollout r WHERE r.distributionSet.id = :dsId GROUP BY r.status")
|
||||
List<JpaStatistic> countRolloutsByStatusForDistributionSet(@Param("dsId") Long dsId);
|
||||
|
||||
|
||||
/**
|
||||
* Count {@link Action}s by Status for Distribution set.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param dsId
|
||||
* to be found
|
||||
@@ -75,6 +60,8 @@ public interface DistributionSetRepository
|
||||
|
||||
/**
|
||||
* Count total AutoAssignments for Distribution set.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param dsId
|
||||
* to be found
|
||||
@@ -85,6 +72,8 @@ public interface DistributionSetRepository
|
||||
|
||||
/**
|
||||
* deletes the {@link DistributionSet}s with the given IDs.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param ids
|
||||
* to be deleted
|
||||
@@ -94,22 +83,11 @@ public interface DistributionSetRepository
|
||||
@Query("update JpaDistributionSet d set d.deleted = 1 where d.id in :ids")
|
||||
void deleteDistributionSet(@Param("ids") Long... ids);
|
||||
|
||||
/**
|
||||
* deletes {@link DistributionSet}s by the given IDs.
|
||||
*
|
||||
* @param ids
|
||||
* List of IDs of {@link DistributionSet}s to be deleted
|
||||
* @return number of affected/deleted records
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("DELETE FROM JpaDistributionSet d WHERE d.id IN ?1")
|
||||
int deleteByIdIn(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* Finds {@link DistributionSet}s where given {@link SoftwareModule} is
|
||||
* assigned.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param moduleId
|
||||
* to search for
|
||||
@@ -120,6 +98,8 @@ public interface DistributionSetRepository
|
||||
/**
|
||||
* Finds {@link DistributionSet}s based on given ID that are assigned yet to
|
||||
* an {@link Action}, i.e. in use.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
@@ -131,6 +111,8 @@ public interface DistributionSetRepository
|
||||
/**
|
||||
* Finds {@link DistributionSet}s based on given ID that are assigned yet to
|
||||
* an {@link Rollout}, i.e. in use.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param ids
|
||||
* to search for
|
||||
@@ -139,16 +121,6 @@ public interface DistributionSetRepository
|
||||
@Query("select ra.distributionSet.id from JpaRollout ra where ra.distributionSet.id in :ids")
|
||||
List<Long> findAssignedToRolloutDistributionSetsById(@Param("ids") Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* Finds the distribution set for a specific action.
|
||||
*
|
||||
* @param action
|
||||
* the action associated with the distribution set to find
|
||||
* @return the distribution set associated with the given action
|
||||
*/
|
||||
@Query("select DISTINCT d from JpaDistributionSet d join fetch d.modules m join d.actions a where a.id = :action")
|
||||
JpaDistributionSet findByActionId(@Param("action") Long action);
|
||||
|
||||
@Query("select DISTINCT ds from JpaDistributionSet ds join fetch ds.modules join ds.assignedToTargets t where t.controllerId = :controllerId")
|
||||
Optional<DistributionSet> findAssignedToTarget(@Param("controllerId") String controllerId);
|
||||
|
||||
@@ -157,6 +129,8 @@ public interface DistributionSetRepository
|
||||
|
||||
/**
|
||||
* Counts {@link DistributionSet} instances of given type in the repository.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param typeId
|
||||
* to search for
|
||||
@@ -164,24 +138,6 @@ public interface DistributionSetRepository
|
||||
*/
|
||||
long countByTypeId(Long typeId);
|
||||
|
||||
/**
|
||||
* Counts {@link DistributionSet} with given
|
||||
* {@link DistributionSet#getName()} and
|
||||
* {@link DistributionSet#getVersion()}.
|
||||
*
|
||||
* @param name
|
||||
* to search for
|
||||
* @param version
|
||||
* to search for
|
||||
* @return number of found {@link DistributionSet}s
|
||||
*/
|
||||
long countByNameAndVersion(String name, String version);
|
||||
|
||||
@Override
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT d FROM JpaDistributionSet d WHERE d.id IN ?1")
|
||||
List<JpaDistributionSet> findAllById(Iterable<Long> ids);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
@@ -195,5 +151,4 @@ public interface DistributionSetRepository
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaDistributionSet t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -19,7 +19,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -31,17 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface DistributionSetTagRepository
|
||||
extends BaseEntityRepository<JpaDistributionSetTag, Long>, JpaSpecificationExecutor<JpaDistributionSetTag> {
|
||||
/**
|
||||
* deletes the {@link DistributionSet} with the given name.
|
||||
*
|
||||
* @param tagName
|
||||
* to be deleted
|
||||
* @return 1 if tag was deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
Long deleteByName(String tagName);
|
||||
extends BaseEntityRepository<JpaDistributionSetTag> {
|
||||
|
||||
/**
|
||||
* find {@link DistributionSetTag} by its name.
|
||||
@@ -52,16 +41,6 @@ public interface DistributionSetTagRepository
|
||||
*/
|
||||
Optional<DistributionSetTag> findByNameEquals(String tagName);
|
||||
|
||||
/**
|
||||
* Checks if tag with given name exists.
|
||||
*
|
||||
* @param tagName
|
||||
* to check for
|
||||
* @return <code>true</code> is tag with given name exists
|
||||
*/
|
||||
@Query("SELECT CASE WHEN COUNT(t)>0 THEN 'true' ELSE 'false' END FROM JpaDistributionSetTag t WHERE t.name=:tagName")
|
||||
boolean existsByName(@Param("tagName") String tagName);
|
||||
|
||||
/**
|
||||
* Returns all instances of the type.
|
||||
*
|
||||
@@ -83,9 +62,4 @@ public interface DistributionSetTagRepository
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaDistributionSetTag t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
@Override
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT d FROM JpaDistributionSetTag d WHERE d.id IN ?1")
|
||||
List<JpaDistributionSetTag> findAllById(Iterable<Long> ids);
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -18,9 +18,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
@@ -34,32 +31,13 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface DistributionSetTypeRepository
|
||||
extends BaseEntityRepository<JpaDistributionSetType, Long>, JpaSpecificationExecutor<JpaDistributionSetType> {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param pageable
|
||||
* page parameters
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only soft deleted entries of
|
||||
* <code>false</code> if undeleted ones
|
||||
*
|
||||
* @return list of found {@link DistributionSetType}s
|
||||
*/
|
||||
Page<JpaDistributionSetType> findByDeleted(Pageable pageable, boolean isDeleted);
|
||||
|
||||
/**
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only marked as deleted have to be
|
||||
* counted or all undeleted.
|
||||
*
|
||||
* @return number of {@link DistributionSetType}s in the repository.
|
||||
*/
|
||||
long countByDeleted(boolean isDeleted);
|
||||
extends BaseEntityRepository<JpaDistributionSetType> {
|
||||
|
||||
/**
|
||||
* Counts all distribution set type where a specific software module type is
|
||||
* assigned to.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param softwareModuleType
|
||||
* the software module type to count the distribution set type
|
||||
@@ -76,30 +54,18 @@ public interface DistributionSetTypeRepository
|
||||
* manually to query even if this will by done by {@link EntityManager}
|
||||
* anyhow. The DB should take care of optimizing this away.
|
||||
*
|
||||
* @param tenant
|
||||
* to delete data from
|
||||
* @param tenant to delete data from
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaDistributionSetType t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link DistributionSetType}s for the given IDs. Workaround
|
||||
* for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
*
|
||||
* @param ids
|
||||
* of the types to be located
|
||||
*
|
||||
* @return a list of distribution set types
|
||||
*/
|
||||
@Override
|
||||
@Query("SELECT d FROM JpaDistributionSetType d WHERE d.id IN ?1")
|
||||
List<JpaDistributionSetType> findAllById(Iterable<Long> ids);
|
||||
|
||||
/**
|
||||
* Counts the {@link SoftwareModuleType}s which are associated with the
|
||||
* addressed {@link DistributionSetType}.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param id
|
||||
* of the distribution set type
|
||||
@@ -108,5 +74,4 @@ public interface DistributionSetTypeRepository
|
||||
*/
|
||||
@Query("SELECT COUNT (e.smType) FROM DistributionSetTypeElement e WHERE e.dsType.id = :id")
|
||||
long countSmTypesById(@Param("id") Long id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.BaseRepositoryTypeProvider;
|
||||
import org.eclipse.hawkbit.repository.jpa.acm.AccessController;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
|
||||
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Repository implementation that allows findAll with disabled count query.
|
||||
*
|
||||
* @param <T> the domain type the repository manages
|
||||
* @param <ID> the type of the id of the entity the repository manages
|
||||
*/
|
||||
public class HawkBitBaseRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
|
||||
implements NoCountSliceRepository<T>, ACMRepository<T> {
|
||||
|
||||
public HawkBitBaseRepository(final Class<T> domainClass, final EntityManager em) {
|
||||
super(domainClass, em);
|
||||
}
|
||||
|
||||
public HawkBitBaseRepository(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {
|
||||
super(entityInformation, entityManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<T> findAllWithoutCount(@Nullable final Specification<T> spec, final Pageable pageable) {
|
||||
final TypedQuery<T> query = getQuery(spec, pageable);
|
||||
return pageable.isUnpaged() ? new PageImpl<>(query.getResultList()) : readPageWithoutCount(query, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Slice<T> findAllWithoutCount(final Pageable pageable) {
|
||||
return findAllWithoutCount(null, pageable);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@NonNull
|
||||
public <S extends T> S save(@Nullable AccessController.Operation operation, @NonNull final S entity) {
|
||||
return save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public <S extends T> List<S> saveAll(@Nullable AccessController.Operation operation, final Iterable<S> entities) {
|
||||
return saveAll(entities);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public Optional<T> findOne(@Nullable AccessController.Operation operation, @Nullable Specification<T> spec) {
|
||||
return findOne(spec);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public List<T> findAll(@Nullable final AccessController.Operation operation, @Nullable final Specification<T> spec) {
|
||||
return findAll(spec);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public boolean exists(@Nullable AccessController.Operation operation, Specification<T> spec) {
|
||||
return exists(spec);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public long count(@Nullable final AccessController.Operation operation, @Nullable final Specification<T> spec) {
|
||||
return count(spec);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Slice<T> findAllWithoutCount(@Nullable final AccessController.Operation operation, @Nullable Specification<T> spec, Pageable pageable) {
|
||||
return findAllWithoutCount(spec, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public Class<T> getDomainClass() {
|
||||
return super.getDomainClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + '<' + getDomainClass().getSimpleName() + '>';
|
||||
}
|
||||
|
||||
private <S extends T> Page<S> readPageWithoutCount(final TypedQuery<S> query, final Pageable pageable) {
|
||||
query.setFirstResult((int) pageable.getOffset());
|
||||
query.setMaxResults(pageable.getPageSize());
|
||||
|
||||
final List<S> content = query.getResultList();
|
||||
return new PageImpl<>(content, pageable, content.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link BaseRepositoryTypeProvider} leveraging our
|
||||
* {@link HawkBitBaseRepository} for all current use cases
|
||||
*/
|
||||
public static class RepositoryTypeProvider implements BaseRepositoryTypeProvider {
|
||||
|
||||
@Override
|
||||
public Class<?> getBaseRepositoryType(final Class<?> repositoryType) {
|
||||
return HawkBitBaseRepository.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,13 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.model.Artifact;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -26,55 +23,47 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface LocalArtifactRepository extends BaseEntityRepository<JpaArtifact, Long> {
|
||||
public interface LocalArtifactRepository
|
||||
extends BaseEntityRepository<JpaArtifact> {
|
||||
|
||||
/**
|
||||
* Counts artifacts size where the related software module is not
|
||||
* deleted/archived.
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @return sum of artifacts size in bytes
|
||||
*/
|
||||
@Query("SELECT SUM(la.size) FROM JpaArtifact la WHERE la.softwareModule.deleted = 0")
|
||||
Optional<Long> getSumOfUndeletedArtifactSize();
|
||||
@Query("SELECT SUM(la.size) FROM JpaArtifact la WHERE la.softwareModule.deleted = false")
|
||||
Optional<Long> sumOfNonDeletedArtifactSize();
|
||||
|
||||
/**
|
||||
* Counts artifacts where the related software module is deleted/archived.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param deleted
|
||||
* to true for counting the deleted artifacts
|
||||
*
|
||||
* @param deleted to true for counting the deleted artifacts
|
||||
* @return number of artifacts
|
||||
*/
|
||||
Long countBySoftwareModuleDeleted(boolean deleted);
|
||||
|
||||
/**
|
||||
* Searches for a {@link Artifact} based on given gridFsFileName.
|
||||
* Counts current elements based on the sha1 and tenant, as well as having the
|
||||
* {@link SoftwareModule} property 'deleted' with value 'false'
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param sha1Hash
|
||||
* to search
|
||||
* @return list of {@link Artifact}s.
|
||||
*/
|
||||
List<Artifact> findBySha1Hash(String sha1Hash);
|
||||
|
||||
/**
|
||||
* Counts current elements based on the sha1 and tenant, as well as having
|
||||
* the {@link SoftwareModule} property 'deleted' with value 'false
|
||||
*
|
||||
* @param sha1
|
||||
* the sha1 of the {@link Artifact}
|
||||
* @param tenant
|
||||
* the current tenant
|
||||
*
|
||||
* @param sha1 the sha1 of the {@link Artifact}
|
||||
* @param tenant the current tenant\
|
||||
* @return the count of the elements
|
||||
*/
|
||||
long countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(@Param("sha1") String sha1,
|
||||
@Param("tenant") String tenant);
|
||||
long countBySha1HashAndTenantAndSoftwareModuleDeletedIsFalse(
|
||||
@Param("sha1") String sha1, @Param("tenant") String tenant);
|
||||
|
||||
/**
|
||||
* Searches for a {@link Artifact} based on given gridFsFileName.
|
||||
*
|
||||
* @param sha1Hash
|
||||
* to search
|
||||
* @param sha1Hash to search
|
||||
* @return {@link Artifact} the first in the result list
|
||||
*/
|
||||
Optional<Artifact> findFirstBySha1Hash(String sha1Hash);
|
||||
@@ -82,38 +71,14 @@ public interface LocalArtifactRepository extends BaseEntityRepository<JpaArtifac
|
||||
/**
|
||||
* Searches for a {@link Artifact} based user provided filename at upload.
|
||||
*
|
||||
* @param filename
|
||||
* to search
|
||||
* @param filename to search
|
||||
* @return list of {@link Artifact}.
|
||||
*/
|
||||
Optional<Artifact> findFirstByFilename(String filename);
|
||||
|
||||
/**
|
||||
* Searches for local artifact for a base software module.
|
||||
*
|
||||
* @param pageReq
|
||||
* Pageable
|
||||
* @param softwareModuleId
|
||||
* software module id
|
||||
*
|
||||
* @return Page<Artifact>
|
||||
*/
|
||||
Page<Artifact> findBySoftwareModuleId(Pageable pageReq, Long softwareModuleId);
|
||||
|
||||
/**
|
||||
* Count the artifacts that are associated with the given software module.
|
||||
*
|
||||
* @param softwareModuleId
|
||||
* software module ID
|
||||
*
|
||||
* @return the current number of artifacts associated with the software
|
||||
* module.
|
||||
*/
|
||||
long countBySoftwareModuleId(Long softwareModuleId);
|
||||
|
||||
/**
|
||||
* Searches for a {@link Artifact} based user provided filename at upload
|
||||
* and selected software module id.
|
||||
* Searches for a {@link Artifact} based user provided filename at upload and
|
||||
* selected software module id.
|
||||
*
|
||||
* @param filename
|
||||
* to search
|
||||
@@ -123,5 +88,4 @@ public interface LocalArtifactRepository extends BaseEntityRepository<JpaArtifac
|
||||
* @return list of {@link Artifact}.
|
||||
*/
|
||||
Optional<Artifact> findFirstByFilenameAndSoftwareModuleId(String filename, Long softwareModuleId);
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.BaseEntity;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -19,7 +19,6 @@ import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup.RolloutGroupStatus;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -30,7 +29,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface RolloutGroupRepository
|
||||
extends BaseEntityRepository<JpaRolloutGroup, Long>, JpaSpecificationExecutor<JpaRolloutGroup> {
|
||||
extends BaseEntityRepository<JpaRolloutGroup> {
|
||||
|
||||
/**
|
||||
* Retrieves all {@link RolloutGroup} referring a specific rollout in the
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -20,7 +20,6 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout.RolloutStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -31,7 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface RolloutRepository
|
||||
extends BaseEntityRepository<JpaRollout, Long>, JpaSpecificationExecutor<JpaRollout> {
|
||||
extends BaseEntityRepository<JpaRollout> {
|
||||
|
||||
/**
|
||||
* Retrieves all {@link Rollout} for given status.
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.RolloutTargetGroup;
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -52,14 +52,12 @@ public interface SoftwareModuleMetadataRepository
|
||||
/**
|
||||
* Locates the meta data entries that match the given software module IDs
|
||||
* and target visibility flag.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param page
|
||||
* The pagination parameters.
|
||||
* @param moduleId
|
||||
* List of software module IDs.
|
||||
* @param targetVisible
|
||||
* The target visibility flag.
|
||||
*
|
||||
* @param page The pagination parameters.
|
||||
* @param moduleId List of software module IDs.
|
||||
* @param targetVisible The target visibility flag.
|
||||
* @return A {@link Page} with the matching meta data entries.
|
||||
*/
|
||||
@Query("SELECT smd.softwareModule.id, smd FROM JpaSoftwareModuleMetadata smd WHERE smd.softwareModule.id IN :moduleId AND smd.targetVisible = :targetVisible")
|
||||
@@ -69,13 +67,11 @@ public interface SoftwareModuleMetadataRepository
|
||||
/**
|
||||
* Counts the meta data entries that are associated with the addressed
|
||||
* software module.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param moduleId
|
||||
* The ID of the software module.
|
||||
*
|
||||
* @return The number of meta data entries associated with the software
|
||||
* module.
|
||||
* @param moduleId The ID of the software module.
|
||||
* @return The number of meta data entries associated with the software module.
|
||||
*/
|
||||
long countBySoftwareModuleId(@Param("moduleId") Long moduleId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link SoftwareModule} repository.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface SoftwareModuleRepository
|
||||
extends BaseEntityRepository<JpaSoftwareModule> {
|
||||
|
||||
/**
|
||||
* Counts all {@link SoftwareModule}s based on the given {@link JpaSoftwareModuleType}.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param type to count for
|
||||
* @return number of {@link SoftwareModule}s
|
||||
*/
|
||||
long countByType(JpaSoftwareModuleType type);
|
||||
|
||||
/**
|
||||
* Count the software modules which are assigned to the distribution set
|
||||
* with the given ID.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param distributionSetId the distribution set ID
|
||||
*
|
||||
* @return the number of software modules matching the given distribution set ID.
|
||||
*/
|
||||
long countByAssignedToId(Long distributionSetId);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
* manually to query even if this will by done by {@link EntityManager}
|
||||
* anyhow. The DB should take care of optimizing this away.
|
||||
*
|
||||
* @param tenant
|
||||
* to delete data from
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaSoftwareModule t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
}
|
||||
@@ -7,9 +7,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -17,9 +16,6 @@ import javax.persistence.EntityManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -31,24 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface SoftwareModuleTypeRepository
|
||||
extends BaseEntityRepository<JpaSoftwareModuleType, Long>, JpaSpecificationExecutor<JpaSoftwareModuleType> {
|
||||
|
||||
/**
|
||||
* @param pageable
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only marked as deleted have to be
|
||||
* count or all undeleted.
|
||||
* @return found {@link SoftwareModuleType}s.
|
||||
*/
|
||||
Page<SoftwareModuleType> findByDeleted(Pageable pageable, boolean isDeleted);
|
||||
|
||||
/**
|
||||
* @param isDeleted
|
||||
* to <code>true</code> if only marked as deleted have to be
|
||||
* count or all undeleted.
|
||||
* @return number of {@link SoftwareModuleType}s in the repository.
|
||||
*/
|
||||
Long countByDeleted(boolean isDeleted);
|
||||
extends BaseEntityRepository<JpaSoftwareModuleType> {
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -81,9 +60,4 @@ public interface SoftwareModuleTypeRepository
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaSoftwareModuleType t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
@Override
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT d FROM JpaSoftwareModuleType d WHERE d.id IN ?1")
|
||||
List<JpaSoftwareModuleType> findAllById(Iterable<Long> ids);
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -29,7 +28,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetFilterQueryRepository
|
||||
extends BaseEntityRepository<JpaTargetFilterQuery, Long>, JpaSpecificationExecutor<JpaTargetFilterQuery> {
|
||||
extends BaseEntityRepository<JpaTargetFilterQuery> {
|
||||
|
||||
/**
|
||||
* Find customer target filter by name
|
||||
@@ -39,27 +38,24 @@ public interface TargetFilterQueryRepository
|
||||
*/
|
||||
Optional<TargetFilterQuery> findByName(String name);
|
||||
|
||||
/**
|
||||
* Find list of all custom target filters.
|
||||
*/
|
||||
@Override
|
||||
Page<JpaTargetFilterQuery> findAll();
|
||||
|
||||
/**
|
||||
* Sets the auto assign distribution sets and action types to null which
|
||||
* match the ds ids.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param dsIds
|
||||
* distribution set ids to be set to null
|
||||
* @param dsIds distribution set ids to be set to null
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("update JpaTargetFilterQuery d set d.autoAssignDistributionSet = NULL, d.autoAssignActionType = NULL where d.autoAssignDistributionSet in :ids")
|
||||
void unsetAutoAssignDistributionSetAndActionType(@Param("ids") Long... dsIds);
|
||||
@Query("update JpaTargetFilterQuery d set d.autoAssignDistributionSet = NULL, d.autoAssignActionType = NULL, d.accessControlContext = NULL where d.autoAssignDistributionSet in :ids")
|
||||
void unsetAutoAssignDistributionSetAndActionTypeAndAccessContext(@Param("ids") Long... dsIds);
|
||||
|
||||
/**
|
||||
* Counts all target filters that have a given auto assign distribution set
|
||||
* assigned.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param autoAssignDistributionSetId
|
||||
* the id of the distribution set
|
||||
@@ -80,5 +76,4 @@ public interface TargetFilterQueryRepository
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetFilterQuery t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetMetadata;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.TargetMetadataCompositeKey;
|
||||
@@ -29,10 +29,10 @@ public interface TargetMetadataRepository
|
||||
|
||||
/**
|
||||
* Counts the meta data entries that match the given target ID.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param id
|
||||
* of the target.
|
||||
*
|
||||
* @param id of the target.
|
||||
* @return The number of matching meta data entries.
|
||||
*/
|
||||
long countByTargetId(@Param("id") Long id);
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link Target} repository.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetRepository extends BaseEntityRepository<JpaTarget> {
|
||||
|
||||
// TODO AC - remove it and use specification
|
||||
/**
|
||||
* @deprecated remove it and use specification
|
||||
*/
|
||||
// no access check
|
||||
@Deprecated(forRemoval = true)
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE JpaTarget t SET t.assignedDistributionSet = :set, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy, t.updateStatus = :status WHERE t.id IN :targets")
|
||||
void setAssignedDistributionSetAndUpdateStatus(@Param("status") TargetUpdateStatus status,
|
||||
@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
|
||||
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
|
||||
|
||||
|
||||
// TODO AC - remove it and use specification
|
||||
|
||||
/**
|
||||
* @deprecated will be removed
|
||||
*/
|
||||
// no access check
|
||||
@Deprecated(forRemoval = true)
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("UPDATE JpaTarget t SET t.assignedDistributionSet = :set, t.installedDistributionSet = :set, t.installationDate = :lastModifiedAt, t.lastModifiedAt = :lastModifiedAt, t.lastModifiedBy = :lastModifiedBy, t.updateStatus = :status WHERE t.id IN :targets")
|
||||
void setAssignedAndInstalledDistributionSetAndUpdateStatus(@Param("status") TargetUpdateStatus status,
|
||||
@Param("set") JpaDistributionSet set, @Param("lastModifiedAt") Long modifiedAt,
|
||||
@Param("lastModifiedBy") String modifiedBy, @Param("targets") Collection<Long> targets);
|
||||
|
||||
/**
|
||||
* Counts {@link Target} instances of given type in the repository.
|
||||
* <p/>
|
||||
* No access control applied
|
||||
*
|
||||
* @param targetTypeId to search for
|
||||
* @return number of found {@link Target}s
|
||||
*/
|
||||
long countByTargetTypeId(Long targetTypeId);
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
* manually to query even if this will by done by {@link EntityManager} anyhow.
|
||||
* The DB should take care of optimizing this away.
|
||||
*
|
||||
* @param tenant to delete data from
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTarget t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
}
|
||||
@@ -7,9 +7,8 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -17,7 +16,6 @@ import javax.persistence.EntityManager;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TargetTag;
|
||||
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@@ -28,19 +26,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetTagRepository
|
||||
extends BaseEntityRepository<JpaTargetTag, Long>, JpaSpecificationExecutor<JpaTargetTag> {
|
||||
|
||||
/**
|
||||
* deletes the {@link TargetTag}s with the given tag names.
|
||||
*
|
||||
* @param tagName
|
||||
* to be deleted
|
||||
* @return 1 if tag was deleted
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
Long deleteByName(String tagName);
|
||||
public interface TargetTagRepository extends BaseEntityRepository<JpaTargetTag> {
|
||||
|
||||
/**
|
||||
* find {@link TargetTag} by its name.
|
||||
@@ -51,24 +37,6 @@ public interface TargetTagRepository
|
||||
*/
|
||||
Optional<TargetTag> findByNameEquals(String tagName);
|
||||
|
||||
/**
|
||||
* Checks if tag with given name exists.
|
||||
*
|
||||
* @param tagName
|
||||
* to check for
|
||||
* @return <code>true</code> is tag with given name exists
|
||||
*/
|
||||
@Query("SELECT CASE WHEN COUNT(t)>0 THEN 'true' ELSE 'false' END FROM JpaTargetTag t WHERE t.name=:tagName")
|
||||
boolean existsByName(@Param("tagName") String tagName);
|
||||
|
||||
/**
|
||||
* Returns all instances of the type.
|
||||
*
|
||||
* @return all entities
|
||||
*/
|
||||
@Override
|
||||
List<JpaTargetTag> findAll();
|
||||
|
||||
/**
|
||||
* Deletes all {@link TenantAwareBaseEntity} of a given tenant. For safety
|
||||
* reasons (this is a "delete everything" query after all) we add the tenant
|
||||
@@ -82,9 +50,4 @@ public interface TargetTagRepository
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetTag t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
|
||||
@Override
|
||||
// Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477
|
||||
@Query("SELECT t FROM JpaTargetTag t WHERE t.id IN ?1")
|
||||
List<JpaTargetTag> findAllById(Iterable<Long> ids);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.specifications.TargetTypeSpecification;
|
||||
import org.eclipse.hawkbit.repository.model.TargetType;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* {@link PagingAndSortingRepository} and {@link org.springframework.data.repository.CrudRepository} for
|
||||
* {@link JpaTargetType}.
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TargetTypeRepository
|
||||
extends BaseEntityRepository<JpaTargetType> {
|
||||
|
||||
/**
|
||||
* Counts the distributions set types compatible with that type
|
||||
* <p/>
|
||||
* No access control applied.
|
||||
*
|
||||
* @param id target type id
|
||||
* @return the count
|
||||
*/
|
||||
@Query(value = "SELECT COUNT (t.id) FROM JpaDistributionSetType t JOIN t.compatibleToTargetTypes tt WHERE tt.id = :id")
|
||||
long countDsSetTypesById(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dsTypeId
|
||||
* to search for
|
||||
* @return all {@link TargetType}s in the repository with given
|
||||
* {@link TargetType#getName()}
|
||||
*/
|
||||
default List<JpaTargetType> findByDsType(@Param("id") final Long dsTypeId) {
|
||||
return this.findAll(Specification.where(TargetTypeSpecification.hasDsSetType(dsTypeId)));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name
|
||||
* to search for
|
||||
* @return all {@link TargetType}s in the repository with given
|
||||
* {@link TargetType#getName()}
|
||||
*/
|
||||
default Optional<JpaTargetType> findByName(final String name) {
|
||||
return this.findOne(Specification.where(TargetTypeSpecification.hasName(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tenant Tenant
|
||||
*/
|
||||
@Modifying
|
||||
@Transactional
|
||||
@Query("DELETE FROM JpaTargetType t WHERE t.tenant = :tenant")
|
||||
void deleteByTenant(@Param("tenant") String tenant);
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
*
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface TenantConfigurationRepository extends BaseEntityRepository<JpaTenantConfiguration, Long> {
|
||||
public interface TenantConfigurationRepository extends BaseEntityRepository<JpaTenantConfiguration> {
|
||||
|
||||
/**
|
||||
* Finds a specific {@link TenantConfiguration} by the configuration key.
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
package org.eclipse.hawkbit.repository.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
package org.eclipse.hawkbit.repository.jpa.rollout.condition;
|
||||
|
||||
import org.eclipse.hawkbit.repository.RolloutManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
|
||||
@@ -12,7 +12,7 @@ package org.eclipse.hawkbit.repository.jpa.rollout.condition;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DeploymentManagement;
|
||||
import org.eclipse.hawkbit.repository.jpa.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.RolloutGroupRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.rollout.condition;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRollout;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaRolloutGroup;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.rollout.condition;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.jpa.repository.ActionRepository;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.eclipse.hawkbit.repository.model.Rollout;
|
||||
import org.eclipse.hawkbit.repository.model.RolloutGroup;
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
|
||||
@@ -25,6 +27,8 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaTarget_;
|
||||
import org.eclipse.hawkbit.repository.model.Action;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class for {@link Action}s {@link Specification}s. The class provides
|
||||
* Spring Data JPQL Specifications.
|
||||
@@ -36,6 +40,81 @@ public final class ActionSpecifications {
|
||||
// utility class
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byTargetIdAndIsActive(final Long targetId) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.id), targetId),
|
||||
cb.equal(root.get(JpaAction_.active), true));
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byTargetControllerId(final String controllerId) {
|
||||
return (root, query, cb) -> cb.equal(root.get(JpaAction_.target).get(JpaTarget_.controllerId), controllerId);
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byTargetIdAndIsActiveAndStatus(final Long targetId, final Action.Status status) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.id), targetId),
|
||||
cb.equal(root.get(JpaAction_.active), true),
|
||||
cb.equal(root.get(JpaAction_.status), status));
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byTargetControllerIdAndActive(final String controllerId, final boolean active) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.controllerId), controllerId),
|
||||
cb.equal(root.get(JpaAction_.active), active));
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byTargetControllerIdAndIsActiveAndStatus(final String controllerId, final Action.Status status) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.controllerId), controllerId),
|
||||
cb.equal(root.get(JpaAction_.active), true),
|
||||
cb.equal(root.get(JpaAction_.status), status));
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byTargetIdsAndActiveAndStatusAndDSNotRequiredMigrationStep(
|
||||
final List<Long> targetIds, final boolean active, final Action.Status status) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
root.get(JpaAction_.target).in(targetIds),
|
||||
cb.equal(root.get(JpaAction_.active), active),
|
||||
cb.equal(root.get(JpaAction_.status), status),
|
||||
cb.equal(root.get(JpaAction_.distributionSet).get(JpaDistributionSet_.requiredMigrationStep), false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns active actions by target controller that has null or non-null depending on <code>isNull</code> value.
|
||||
* Fetches action's distribution set.
|
||||
*
|
||||
* @param controllerId controller id
|
||||
* @param isNull if <code>true</code> return with <code>null</code> weight, otherwise with non-<code>null</code>
|
||||
* @return the matching action s.
|
||||
*/
|
||||
public static Specification<JpaAction> byTargetControllerIdAndActiveAndWeightIsNullFetchDS(final String controllerId, final boolean isNull) {
|
||||
return (root, query, cb) -> {
|
||||
root.fetch(JpaAction_.distributionSet, JoinType.LEFT);
|
||||
return cb.and(
|
||||
cb.equal(root.get(JpaAction_.target).get(JpaTarget_.controllerId), controllerId),
|
||||
cb.equal(root.get(JpaAction_.active), true),
|
||||
isNull ? cb.isNull(root.get(JpaAction_.weight)) : cb.isNotNull(root.get(JpaAction_.weight)));
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byDistributionSetId(final Long distributionSetId) {
|
||||
return (root, query, cb) -> cb.equal(root.get(JpaAction_.distributionSet).get(JpaTarget_.id), distributionSetId);
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byDistributionSetIdAndActive(final Long distributionSetId) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
cb.equal(root.get(JpaAction_.distributionSet).get(JpaTarget_.id), distributionSetId),
|
||||
cb.equal(root.get(JpaAction_.active), true));
|
||||
}
|
||||
|
||||
public static Specification<JpaAction> byDistributionSetIdAndActiveAndStatusIsNot(
|
||||
final Long distributionSetId, final Action.Status status) {
|
||||
return (root, query, cb) -> cb.and(
|
||||
cb.equal(root.get(JpaAction_.distributionSet).get(JpaTarget_.id), distributionSetId),
|
||||
cb.equal(root.get(JpaAction_.active), true),
|
||||
cb.notEqual(root.get(JpaAction_.status), status));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specification which joins all necessary tables to retrieve the dependency
|
||||
* between a target and a local file assignment through the assigned action
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaArtifact_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule_;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
/**
|
||||
* Utility class for {@link JpaArtifact}s {@link Specification}s. The class provides
|
||||
* Spring Data JPQL Specifications.
|
||||
*/
|
||||
public final class ArtifactSpecifications {
|
||||
|
||||
private ArtifactSpecifications() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
public static Specification<JpaArtifact> bySoftwareModuleId(final Long softwareModuleId) {
|
||||
return (targetRoot, query, cb) -> cb.equal(
|
||||
targetRoot.get(JpaArtifact_.softwareModule).get(JpaSoftwareModule_.id), softwareModuleId);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@ import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaAction_;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSet;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag_;
|
||||
@@ -46,6 +48,16 @@ public final class DistributionSetSpecification {
|
||||
// utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s with
|
||||
* DELETED attribute <code>false</code> - i.e. is not deleted.
|
||||
*
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> isNotDeleted() {
|
||||
return isDeleted(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its
|
||||
* DELETED attribute.
|
||||
@@ -57,26 +69,25 @@ public final class DistributionSetSpecification {
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> isDeleted(final Boolean isDeleted) {
|
||||
return (dsRoot, query, cb) -> cb.equal(dsRoot.<Boolean> get(JpaDistributionSet_.deleted), isDeleted);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its
|
||||
* COMPLETED attribute.
|
||||
*
|
||||
* @param isCompleted
|
||||
* TRUE/FALSE are compared to the attribute COMPLETED. If NULL
|
||||
* the attribute is ignored
|
||||
* TRUE/FALSE are compared to the attribute COMPLETED. If NULL the
|
||||
* attribute is ignored
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> isCompleted(final Boolean isCompleted) {
|
||||
return (dsRoot, query, cb) -> cb.equal(dsRoot.<Boolean> get(JpaDistributionSet_.complete), isCompleted);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its
|
||||
* VALID attribute.
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by its VALID
|
||||
* attribute.
|
||||
*
|
||||
* @param isValid
|
||||
* TRUE/FALSE are compared to the attribute VALID. If NULL the
|
||||
@@ -85,7 +96,6 @@ public final class DistributionSetSpecification {
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> isValid(final Boolean isValid) {
|
||||
return (dsRoot, query, cb) -> cb.equal(dsRoot.<Boolean> get(JpaDistributionSet_.valid), isValid);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,6 +117,15 @@ public final class DistributionSetSpecification {
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<JpaDistributionSet> byActionId(final Long actionId) {
|
||||
return (dsRoot, query, cb) -> {
|
||||
final ListJoin<JpaDistributionSet, JpaAction> join = dsRoot.join(JpaDistributionSet_.actions,
|
||||
JoinType.LEFT);
|
||||
query.distinct(true);
|
||||
return cb.equal(join.get(JpaAction_.id), actionId);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet} with given
|
||||
* {@link DistributionSet#getId()}s.
|
||||
@@ -127,8 +146,8 @@ public final class DistributionSetSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by "like
|
||||
* name and like version".
|
||||
* {@link Specification} for retrieving {@link DistributionSet}s by "like name
|
||||
* and like version".
|
||||
*
|
||||
* @param name
|
||||
* to be filtered on
|
||||
@@ -188,8 +207,8 @@ public final class DistributionSetSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* returns query criteria {@link Specification} comparing case insensitive
|
||||
* "NAME == AND VERSION ==".
|
||||
* returns query criteria {@link Specification} comparing case insensitive "NAME
|
||||
* == AND VERSION ==".
|
||||
*
|
||||
* @param name
|
||||
* to be filtered on
|
||||
@@ -216,15 +235,27 @@ public final class DistributionSetSpecification {
|
||||
public static Specification<JpaDistributionSet> byType(final Long typeId) {
|
||||
return (dsRoot, query, cb) -> cb.equal(dsRoot.get(JpaDistributionSet_.type).get(JpaDistributionSetType_.id),
|
||||
typeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSet} for given id
|
||||
* collection of {@link DistributionSet#getType()}.
|
||||
*
|
||||
*
|
||||
* @param typeIds
|
||||
* id collection of distribution set type to search
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> hasType(final Collection<Long> typeIds) {
|
||||
return (dsRoot, query, cb) -> dsRoot.get(JpaDistributionSet_.type).get(JpaDistributionSetType_.id).in(typeIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param installedTargetId
|
||||
* the targetID which is installed to a distribution set to
|
||||
* search for.
|
||||
* @return the specification to search for a distribution set which is
|
||||
* installed to the given targetId
|
||||
* the targetID which is installed to a distribution set to search
|
||||
* for.
|
||||
* @return the specification to search for a distribution set which is installed
|
||||
* to the given targetId
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> installedTarget(final String installedTargetId) {
|
||||
return (dsRoot, query, cb) -> {
|
||||
@@ -238,8 +269,8 @@ public final class DistributionSetSpecification {
|
||||
* @param assignedTargetId
|
||||
* the targetID which is assigned to a distribution set to search
|
||||
* for.
|
||||
* @return the specification to search for a distribution set which is
|
||||
* assigned to the given targetId
|
||||
* @return the specification to search for a distribution set which is assigned
|
||||
* to the given targetId
|
||||
*/
|
||||
public static Specification<JpaDistributionSet> assignedTarget(final String assignedTargetId) {
|
||||
return (dsRoot, query, cb) -> {
|
||||
@@ -269,12 +300,11 @@ public final class DistributionSetSpecification {
|
||||
* Can be added to specification chain to order result by provided target
|
||||
*
|
||||
* Order: 1. Distribution set installed on target, 2. Distribution set(s)
|
||||
* assigned to target, 3. Based on requested sorting or id if
|
||||
* <code>null</code>.
|
||||
* assigned to target, 3. Based on requested sorting or id if <code>null</code>.
|
||||
*
|
||||
* NOTE: Other specs, pagables and sort objects may alter the queries
|
||||
* orderBy entry too, possibly invalidating the applied order, keep in mind
|
||||
* when using this
|
||||
* NOTE: Other specs, pagables and sort objects may alter the queries orderBy
|
||||
* entry too, possibly invalidating the applied order, keep in mind when using
|
||||
* this
|
||||
*
|
||||
* @param linkedControllerId
|
||||
* controller id to get installed/assigned DS for
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2023 Bosch.IO GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.specifications;
|
||||
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaDistributionSetTag_;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
/**
|
||||
* Utility class for {@link JpaDistributionSetTag}s {@link Specification}s. The class provides
|
||||
* Spring Data JPQL Specifications.
|
||||
*/
|
||||
public final class DistributionSetTagSpecifications {
|
||||
|
||||
private DistributionSetTagSpecifications() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
public static Specification<JpaDistributionSetTag> byName(@NotEmpty final String name) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaDistributionSetTag_.name), name);
|
||||
}
|
||||
}
|
||||
@@ -25,30 +25,13 @@ public final class DistributionSetTypeSpecification {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSetType}s by its
|
||||
* DELETED attribute.
|
||||
*
|
||||
* @param isDeleted
|
||||
* TRUE/FALSE are compared to the attribute DELETED. If NULL the
|
||||
* attribute is ignored
|
||||
* {@link Specification} for retrieving {@link DistributionSetType}s with
|
||||
* DELETED attribute <code>false</code> - i.e. is not deleted.
|
||||
*
|
||||
* @return the {@link DistributionSetType} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSetType> isDeleted(final Boolean isDeleted) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.<Boolean> get(JpaDistributionSetType_.deleted),
|
||||
isDeleted);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Specification} for retrieving {@link DistributionSetType} with
|
||||
* given {@link DistributionSetType#getId()} including fetching the elements
|
||||
* list.
|
||||
*
|
||||
* @param distid
|
||||
* to search
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSetType> byId(final Long distid) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.<Long> get(JpaDistributionSetType_.id), distid);
|
||||
public static Specification<JpaDistributionSetType> isNotDeleted() {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.<Boolean> get(JpaDistributionSetType_.deleted), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +44,7 @@ public final class DistributionSetTypeSpecification {
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSetType> byName(final String name) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.<String> get(JpaDistributionSetType_.name), name);
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaDistributionSetType_.name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +57,6 @@ public final class DistributionSetTypeSpecification {
|
||||
* @return the {@link DistributionSet} {@link Specification}
|
||||
*/
|
||||
public static Specification<JpaDistributionSetType> byKey(final String key) {
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.<String> get(JpaDistributionSetType_.key), key);
|
||||
return (targetRoot, query, cb) -> cb.equal(targetRoot.get(JpaDistributionSetType_.key), key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user