Feature/fix sonar warnings (#1226)
* Fixed sonar warnings - "Cognitive Complexity" - "Do not use replaceAll when not using a regex" - java:S5869 - Character classes in regular expressions should not contain the same character twice - Improved bad name - Typos - reduced code duplications - Replaced hand-made wait-utility with Awaitility - Log messages - Duplicate code - Typos - Removed Thread.sleep, instead relaxed check condition - Removed use of deprecated API - Removed use of deprecated API - Added supress-warnings as I do not see a better way to write the tests - Removed Thread.sleep / redundant functionality to Awaitility - Fixed other warnings (use isZero, isEmpty, hasToString) - Removed/Reduced duplicate code - Added generics - Fixed asserts - removed: field.setAccessible(true) actually should not be needed for public static fields! - Too long constructor passes arguments in wrong order - how surprisingly... - Clean-up use of varargs arguments - Fixed regex - Fixed typos and other minor stuff - Making public constructors protected in abstract classes - Swapped expected and asserted argument - volatile not enough for syncing threads - volatile not enough for syncing threads - out-commented code - Made regex not-greedy, added tests for verification - Avoid exposure of thread-local member var Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io> * Fixed Sonar warnings * License header fix Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io> * License header fix #2 Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io> * Fixing review findings Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io> * Fixing tests - Fixed '&' usage in javadoc and typos - Fixing some warnings Signed-off-by: Peter Vigier <Peter.Vigier@bosch.io>
This commit is contained in:
@@ -14,6 +14,7 @@ import javax.persistence.PersistenceException;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
|
||||
|
||||
@@ -53,13 +54,12 @@ public class HawkBitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
|
||||
private static final SQLStateSQLExceptionTranslator SQLSTATE_EXCEPTION_TRANSLATOR = new SQLStateSQLExceptionTranslator();
|
||||
|
||||
@Override
|
||||
public DataAccessException translateExceptionIfPossible(final RuntimeException ex) {
|
||||
public DataAccessException translateExceptionIfPossible(@NonNull final RuntimeException ex) {
|
||||
final DataAccessException dataAccessException = super.translateExceptionIfPossible(ex);
|
||||
|
||||
if (dataAccessException == null) {
|
||||
return searchAndTranslateSqlException(ex);
|
||||
}
|
||||
|
||||
return translateJpaSystemExceptionIfPossible(dataAccessException);
|
||||
}
|
||||
|
||||
@@ -69,22 +69,19 @@ public class HawkBitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
|
||||
return accessException;
|
||||
}
|
||||
|
||||
final DataAccessException sql = searchAndTranslateSqlException(accessException);
|
||||
if (sql == null) {
|
||||
final DataAccessException sqlException = searchAndTranslateSqlException(accessException);
|
||||
if (sqlException == null) {
|
||||
return accessException;
|
||||
}
|
||||
|
||||
return sql;
|
||||
return sqlException;
|
||||
}
|
||||
|
||||
private static DataAccessException searchAndTranslateSqlException(final RuntimeException ex) {
|
||||
final SQLException sqlException = findSqlException(ex);
|
||||
|
||||
if (sqlException == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return SQLSTATE_EXCEPTION_TRANSLATOR.translate(null, null, sqlException);
|
||||
return SQLSTATE_EXCEPTION_TRANSLATOR.translate("", null, sqlException);
|
||||
}
|
||||
|
||||
private static SQLException findSqlException(final RuntimeException jpaSystemException) {
|
||||
|
||||
@@ -767,7 +767,7 @@ public class JpaDeploymentManagement extends JpaActionManagement implements Depl
|
||||
final JpaAction action = actionRepository.findById(actionId)
|
||||
.orElseThrow(() -> new EntityNotFoundException(Action.class, actionId));
|
||||
|
||||
if (!action.isForce()) {
|
||||
if (!action.isForcedOrTimeForced()) {
|
||||
action.setActionType(ActionType.FORCED);
|
||||
return actionRepository.save(action);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -25,7 +24,6 @@ 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.JpaTargetType;
|
||||
import org.eclipse.hawkbit.repository.jpa.model.JpaTenantMetaData;
|
||||
import org.eclipse.hawkbit.repository.jpa.utils.DeploymentHelper;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
@@ -202,11 +200,11 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
// Create if it does not exist
|
||||
if (result == null) {
|
||||
try {
|
||||
currentTenantCacheKeyGenerator.getCreateInitialTenant().set(tenant);
|
||||
currentTenantCacheKeyGenerator.setTenantInCreation(tenant);
|
||||
return createInitialTenantMetaData(tenant);
|
||||
|
||||
} finally {
|
||||
currentTenantCacheKeyGenerator.getCreateInitialTenant().remove();
|
||||
currentTenantCacheKeyGenerator.removeTenantInCreation();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -276,20 +274,17 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
if (tenantAware.getCurrentTenant() == null) {
|
||||
throw new IllegalStateException("Tenant not set");
|
||||
}
|
||||
|
||||
return getTenantMetadata(tenantAware.getCurrentTenant());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "currentTenant", keyGenerator = "currentTenantKeyGenerator", cacheManager = "directCacheManager", unless = "#result == null")
|
||||
public String currentTenant() {
|
||||
final String initialTenantCreation = currentTenantCacheKeyGenerator.getCreateInitialTenant().get();
|
||||
if (initialTenantCreation == null) {
|
||||
return currentTenantCacheKeyGenerator.getTenantInCreation().orElseGet(() -> {
|
||||
final TenantMetaData findByTenant = tenantMetaDataRepository
|
||||
.findByTenantIgnoreCase(tenantAware.getCurrentTenant());
|
||||
return findByTenant != null ? findByTenant.getTenant() : null;
|
||||
}
|
||||
return initialTenantCreation;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -312,7 +307,7 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
|
||||
Integer.MAX_VALUE));
|
||||
final SoftwareModuleType os = softwareModuleTypeRepository.save(new JpaSoftwareModuleType(
|
||||
org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_OS_KEY,
|
||||
org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_OS_NAME, "Core firmware or operationg system", 1));
|
||||
org.eclipse.hawkbit.repository.Constants.SMT_DEFAULT_OS_NAME, "Core firmware or operation system", 1));
|
||||
|
||||
// make sure the module types get their IDs
|
||||
entityManager.flush();
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
package org.eclipse.hawkbit.repository.jpa;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -18,7 +22,6 @@ import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Implementation of {@link CurrentTenantCacheKeyGenerator}.
|
||||
*
|
||||
*/
|
||||
public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyGenerator {
|
||||
|
||||
@@ -28,25 +31,17 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG
|
||||
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* A implementation of the {@link KeyGenerator} to generate a key based on
|
||||
* An implementation of the {@link KeyGenerator} to generate a key based on
|
||||
* either the {@code createInitialTenant} thread local and the
|
||||
* {@link TenantAware}, but in case we are in a tenant creation with its
|
||||
* default types we need to use the tenant the current tenant which is
|
||||
* currently created and not the one currently in the {@link TenantAware}.
|
||||
*
|
||||
* {@link TenantAware}, but in case we are in a tenant creation with its default
|
||||
* types we need to use as the tenant the current tenant which is currently
|
||||
* created and not the one currently in the {@link TenantAware}.
|
||||
*/
|
||||
public class CurrentTenantKeyGenerator implements KeyGenerator {
|
||||
@Override
|
||||
// Exception squid:S923 - override
|
||||
@SuppressWarnings({ "squid:S923" })
|
||||
public Object generate(final Object target, final Method method, final Object... params) {
|
||||
final String initialTenantCreation = createInitialTenant.get();
|
||||
if (initialTenantCreation == null) {
|
||||
return SimpleKeyGenerator.generateKey(tenantAware.getCurrentTenant().toUpperCase(),
|
||||
tenantAware.getCurrentTenant().toUpperCase());
|
||||
}
|
||||
return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(),
|
||||
initialTenantCreation.toUpperCase());
|
||||
String tenant = getTenantInCreation().orElseGet(() -> tenantAware.getCurrentTenant()).toUpperCase();
|
||||
return SimpleKeyGenerator.generateKey(tenant, tenant);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,8 +51,33 @@ public class SystemManagementCacheKeyGenerator implements CurrentTenantCacheKeyG
|
||||
return new CurrentTenantKeyGenerator();
|
||||
}
|
||||
|
||||
ThreadLocal<String> getCreateInitialTenant() {
|
||||
return createInitialTenant;
|
||||
/**
|
||||
* Get the tenant which overwrites the actual tenant used by the
|
||||
* {@linkplain #currentTenantKeyGenerator()}.
|
||||
*
|
||||
* @return A present optional in case that there is a tenant in the progress of
|
||||
* creation.
|
||||
*/
|
||||
public Optional<String> getTenantInCreation() {
|
||||
return Optional.ofNullable(createInitialTenant.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the tenant used by the key generator in case that the tenant is in
|
||||
* the process of creation.
|
||||
*
|
||||
* @param tenant
|
||||
* the tenant which should be used instead of the actual one.
|
||||
*/
|
||||
public void setTenantInCreation(@NotNull String tenant) {
|
||||
createInitialTenant.set(Objects.requireNonNull(tenant));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the tenant overwriting the standard one used by the
|
||||
* {@linkplain #currentTenantKeyGenerator()}.
|
||||
*/
|
||||
public void removeTenantInCreation() {
|
||||
createInitialTenant.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.configuration;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.transaction.Transaction;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
@@ -37,8 +40,10 @@ public class MultiTenantJpaTransactionManager extends JpaTransactionManager {
|
||||
|
||||
final String currentTenant = tenantAware.getCurrentTenant();
|
||||
if (currentTenant != null) {
|
||||
final EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
|
||||
.getResource(getEntityManagerFactory());
|
||||
final EntityManagerFactory emFactory = Objects.requireNonNull(getEntityManagerFactory());
|
||||
final EntityManagerHolder emHolder = Objects.requireNonNull(
|
||||
(EntityManagerHolder) TransactionSynchronizationManager.getResource(emFactory),
|
||||
"No EntityManagerHolder provided by TransactionSynchronizationManager");
|
||||
final EntityManager em = emHolder.getEntityManager();
|
||||
em.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, currentTenant.toUpperCase());
|
||||
}
|
||||
|
||||
@@ -55,34 +55,34 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
|
||||
/**
|
||||
* Default constructor needed for JPA entities.
|
||||
*/
|
||||
public AbstractJpaBaseEntity() {
|
||||
protected AbstractJpaBaseEntity() {
|
||||
// Default constructor needed for JPA entities.
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "created_at", insertable = true, updatable = false, nullable = false)
|
||||
@Column(name = "created_at", updatable = false, nullable = false)
|
||||
public long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "created_by", insertable = true, updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
|
||||
@Column(name = "created_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "last_modified_at", insertable = true, updatable = true, nullable = false)
|
||||
@Column(name = "last_modified_at", nullable = false)
|
||||
public long getLastModifiedAt() {
|
||||
return lastModifiedAt;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Column(name = "last_modified_by", insertable = true, updatable = true, nullable = false, length = USERNAME_FIELD_LENGTH)
|
||||
@Column(name = "last_modified_by", nullable = false, length = USERNAME_FIELD_LENGTH)
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.repository.jpa.model;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Id;
|
||||
@@ -36,12 +38,12 @@ public abstract class AbstractJpaMetaData implements MetaData {
|
||||
@Basic
|
||||
private String value;
|
||||
|
||||
public AbstractJpaMetaData(final String key, final String value) {
|
||||
protected AbstractJpaMetaData(final String key, final String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public AbstractJpaMetaData() {
|
||||
protected AbstractJpaMetaData() {
|
||||
// Default constructor needed for JPA entities
|
||||
}
|
||||
|
||||
@@ -64,41 +66,17 @@ public abstract class AbstractJpaMetaData implements MetaData {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((key == null) ? 0 : key.hashCode());
|
||||
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||
return result;
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
final AbstractJpaMetaData that = (AbstractJpaMetaData) o;
|
||||
return Objects.equals(key, that.key) && Objects.equals(value, that.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(this.getClass().isInstance(obj))) {
|
||||
return false;
|
||||
}
|
||||
final AbstractJpaMetaData other = (AbstractJpaMetaData) obj;
|
||||
if (key == null) {
|
||||
if (other.key != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!key.equals(other.key)) {
|
||||
return false;
|
||||
}
|
||||
if (value == null) {
|
||||
if (other.value != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!value.equals(other.value)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
public int hashCode() {
|
||||
return Objects.hash(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,14 +32,14 @@ public abstract class AbstractJpaNamedEntity extends AbstractJpaTenantAwareBaseE
|
||||
@NotNull
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", nullable = true, length = NamedEntity.DESCRIPTION_MAX_SIZE)
|
||||
@Column(name = "description", length = NamedEntity.DESCRIPTION_MAX_SIZE)
|
||||
@Size(max = NamedEntity.DESCRIPTION_MAX_SIZE)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public AbstractJpaNamedEntity() {
|
||||
protected AbstractJpaNamedEntity() {
|
||||
// Default constructor needed for JPA entities
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEn
|
||||
/**
|
||||
* Default constructor needed for JPA entities.
|
||||
*/
|
||||
public AbstractJpaTenantAwareBaseEntity() {
|
||||
protected AbstractJpaTenantAwareBaseEntity() {
|
||||
// Default constructor needed for JPA entities.
|
||||
}
|
||||
|
||||
|
||||
@@ -299,22 +299,10 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeModule(final SoftwareModule softwareModule) {
|
||||
if (modules == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Optional<SoftwareModule> found = modules.stream()
|
||||
.filter(module -> module.getId().equals(softwareModule.getId())).findAny();
|
||||
|
||||
if (found.isPresent()) {
|
||||
modules.remove(found.get());
|
||||
public void removeModule(final SoftwareModule softwareModule) {
|
||||
if (modules != null && modules.removeIf(m -> m.getId().equals(softwareModule.getId()))) {
|
||||
complete = type.checkComplete(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -371,11 +359,11 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
|
||||
private static boolean isSoftDeleted(final DescriptorEvent event) {
|
||||
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
|
||||
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
|
||||
.filter(record -> record instanceof DirectToFieldChangeRecord)
|
||||
.map(record -> (DirectToFieldChangeRecord) record).collect(Collectors.toList());
|
||||
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return changes.stream().filter(record -> DELETED_PROPERTY.equals(record.getAttribute())
|
||||
&& Boolean.parseBoolean(record.getNewValue().toString())).count() > 0;
|
||||
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
|
||||
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -278,11 +278,11 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
|
||||
private static boolean isSoftDeleted(final DescriptorEvent event) {
|
||||
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
|
||||
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
|
||||
.filter(record -> record instanceof DirectToFieldChangeRecord)
|
||||
.map(record -> (DirectToFieldChangeRecord) record).collect(Collectors.toList());
|
||||
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return changes.stream().filter(record -> DELETED_PROPERTY.equals(record.getAttribute())
|
||||
&& Boolean.parseBoolean(record.getNewValue().toString())).count() > 0;
|
||||
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
|
||||
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -258,11 +258,11 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
|
||||
private static boolean isSoftDeleted(final DescriptorEvent event) {
|
||||
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery()).getObjectChangeSet();
|
||||
final List<DirectToFieldChangeRecord> changes = changeSet.getChanges().stream()
|
||||
.filter(record -> record instanceof DirectToFieldChangeRecord)
|
||||
.map(record -> (DirectToFieldChangeRecord) record).collect(Collectors.toList());
|
||||
.filter(DirectToFieldChangeRecord.class::isInstance).map(DirectToFieldChangeRecord.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return changes.stream().filter(record -> DELETED_PROPERTY.equals(record.getAttribute())
|
||||
&& Boolean.parseBoolean(record.getNewValue().toString())).count() > 0;
|
||||
return changes.stream().anyMatch(changeRecord -> DELETED_PROPERTY.equals(changeRecord.getAttribute())
|
||||
&& Boolean.parseBoolean(changeRecord.getNewValue().toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -96,7 +96,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
@Column(name = "controller_id", length = Target.CONTROLLER_ID_MAX_SIZE, updatable = false, nullable = false)
|
||||
@Size(min = 1, max = Target.CONTROLLER_ID_MAX_SIZE)
|
||||
@NotNull
|
||||
@Pattern(regexp = "[.\\S]*", message = "has whitespaces which are not allowed")
|
||||
@Pattern(regexp = "[\\S]*", message = "has whitespaces which are not allowed")
|
||||
private String controllerId;
|
||||
|
||||
@CascadeOnDelete
|
||||
@@ -243,34 +243,28 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
if (rolloutTargetGroup == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(rolloutTargetGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tag
|
||||
* tag
|
||||
* @return boolean true or false
|
||||
* to be added
|
||||
*/
|
||||
public boolean addTag(final TargetTag tag) {
|
||||
public void addTag(final TargetTag tag) {
|
||||
if (tags == null) {
|
||||
tags = new HashSet<>();
|
||||
}
|
||||
|
||||
return tags.add(tag);
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tag
|
||||
* tag
|
||||
* @return boolean true or false
|
||||
* the tag to be removed from the target
|
||||
*/
|
||||
public boolean removeTag(final TargetTag tag) {
|
||||
if (tags == null) {
|
||||
return false;
|
||||
public void removeTag(final TargetTag tag) {
|
||||
if (tags != null) {
|
||||
tags.remove(tag);
|
||||
}
|
||||
|
||||
return tags.remove(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,14 +297,12 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Target, EventAw
|
||||
/**
|
||||
* @param action
|
||||
* Action
|
||||
* @return boolean true or false
|
||||
*/
|
||||
public boolean addAction(final Action action) {
|
||||
public void addAction(final Action action) {
|
||||
if (actions == null) {
|
||||
actions = new ArrayList<>();
|
||||
}
|
||||
|
||||
return actions.add((JpaAction) action);
|
||||
actions.add((JpaAction) action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.eclipse.hawkbit.repository.FieldNameProvider;
|
||||
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
|
||||
import org.slf4j.Logger;
|
||||
@@ -25,7 +27,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
|
||||
|
||||
private final Class<A> fieldNameProvider;
|
||||
|
||||
public AbstractFieldNameRSQLVisitor(final Class<A> fieldNameProvider) {
|
||||
protected AbstractFieldNameRSQLVisitor(final Class<A> fieldNameProvider) {
|
||||
this.fieldNameProvider = fieldNameProvider;
|
||||
}
|
||||
|
||||
@@ -51,7 +53,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
|
||||
|
||||
// sub entity need minimum 1 dot
|
||||
if (!propertyEnum.getSubEntityAttributes().isEmpty() && graph.length < 2) {
|
||||
throw createRSQLParameterUnsupportedException(node);
|
||||
throw createRSQLParameterUnsupportedException(node, null);
|
||||
}
|
||||
|
||||
final StringBuilder fieldNameBuilder = new StringBuilder(propertyEnum.getFieldName());
|
||||
@@ -67,7 +69,7 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
|
||||
}
|
||||
|
||||
if (!propertyEnum.containsSubEntityAttribute(propertyField)) {
|
||||
throw createRSQLParameterUnsupportedException(node);
|
||||
throw createRSQLParameterUnsupportedException(node, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,30 +95,21 @@ public abstract class AbstractFieldNameRSQLVisitor<A extends Enum<A> & FieldName
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param node
|
||||
* current processing node
|
||||
* @param rootException
|
||||
* in case there is a cause otherwise {@code null}
|
||||
* @return Exception with prepared message extracted from the comparison node.
|
||||
*/
|
||||
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(
|
||||
final ComparisonNode node) {
|
||||
return createRSQLParameterUnsupportedException(node, new Exception());
|
||||
}
|
||||
|
||||
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(final ComparisonNode node,
|
||||
@NotNull final ComparisonNode node,
|
||||
final Exception rootException) {
|
||||
return createRSQLParameterUnsupportedException(String.format(
|
||||
return new RSQLParameterUnsupportedFieldException(String.format(
|
||||
"The given search parameter field {%s} does not exist, must be one of the following fields %s",
|
||||
node.getSelector(), getExpectedFieldList()), rootException);
|
||||
}
|
||||
|
||||
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(final String message) {
|
||||
return createRSQLParameterUnsupportedException(message, null);
|
||||
}
|
||||
|
||||
protected RSQLParameterUnsupportedFieldException createRSQLParameterUnsupportedException(final String message,
|
||||
final Exception rootException) {
|
||||
return new RSQLParameterUnsupportedFieldException(message, rootException);
|
||||
}
|
||||
|
||||
// Exception squid:S2095 - see
|
||||
// https://jira.sonarsource.com/browse/SONARJAVA-1478
|
||||
@SuppressWarnings({ "squid:S2095" })
|
||||
private List<String> getExpectedFieldList() {
|
||||
final List<String> expectedFieldList = Arrays.stream(fieldNameProvider.getEnumConstants())
|
||||
.filter(enumField -> enumField.getSubEntityAttributes().isEmpty()).map(enumField -> {
|
||||
|
||||
@@ -181,7 +181,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
||||
private Path<Object> getFieldPath(final A enumField, final String finalProperty) {
|
||||
return (Path<Object>) getFieldPath(root, enumField.getSubAttributes(finalProperty), enumField.isMap(),
|
||||
this::getJoinFieldPath).orElseThrow(
|
||||
() -> createRSQLParameterUnsupportedException("RSQL field path cannot be empty", null));
|
||||
() -> new RSQLParameterUnsupportedFieldException("RSQL field path cannot be empty", null));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -279,7 +279,7 @@ public class JpaQueryRsqlVisitor<A extends Enum<A> & FieldNameProvider, T> exten
|
||||
private Object convertFieldConverterValue(final ComparisonNode node, final A fieldName, final String value) {
|
||||
final Object convertedValue = ((FieldValueConverter) fieldName).convertValue(fieldName, value);
|
||||
if (convertedValue == null) {
|
||||
throw createRSQLParameterUnsupportedException(
|
||||
throw new RSQLParameterUnsupportedFieldException(
|
||||
"field {" + node.getSelector() + "} must be one of the following values {"
|
||||
+ Arrays.toString(((FieldValueConverter) fieldName).possibleValues(fieldName)) + "}",
|
||||
null);
|
||||
|
||||
@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.repository.jpa.rsql;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import cz.jirutka.rsql.parser.ParseException;
|
||||
|
||||
@@ -24,13 +24,7 @@ import cz.jirutka.rsql.parser.ParseException;
|
||||
*/
|
||||
public class ParseExceptionWrapper {
|
||||
|
||||
private static final String FIELD_EXPECTED_TOKEN_SEQ = "expectedTokenSequences";
|
||||
private static final String FIELD_CURRENT_TOKEN = "currentToken";
|
||||
|
||||
private final ParseException parseException;
|
||||
private final Class<? extends ParseException> parseExceptionClass;
|
||||
private Field expectedTokenSequenceField;
|
||||
private Field currentTokenField;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -41,33 +35,24 @@ public class ParseExceptionWrapper {
|
||||
*/
|
||||
public ParseExceptionWrapper(final ParseException parseException) {
|
||||
this.parseException = parseException;
|
||||
parseExceptionClass = parseException.getClass();
|
||||
|
||||
try {
|
||||
expectedTokenSequenceField = getAccessibleField(parseExceptionClass, FIELD_EXPECTED_TOKEN_SEQ);
|
||||
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
|
||||
expectedTokenSequenceField = null;
|
||||
}
|
||||
|
||||
try {
|
||||
currentTokenField = getAccessibleField(parseExceptionClass, FIELD_CURRENT_TOKEN);
|
||||
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
|
||||
currentTokenField = null;
|
||||
}
|
||||
}
|
||||
|
||||
public int[][] getExpectedTokenSequence() {
|
||||
if (expectedTokenSequenceField == null) {
|
||||
return new int[0][0];
|
||||
}
|
||||
return (int[][]) getValue(expectedTokenSequenceField, parseException);
|
||||
return (parseException.expectedTokenSequences != null) // unclear if this can happen
|
||||
? parseException.expectedTokenSequences
|
||||
: new int[0][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current token
|
||||
*
|
||||
* @return the current token or {@code null} if there is non.
|
||||
*/
|
||||
public TokenWrapper getCurrentToken() {
|
||||
if (currentTokenField == null) {
|
||||
return null;
|
||||
}
|
||||
return new TokenWrapper(getValue(currentTokenField, parseException));
|
||||
return (parseException.currentToken != null) // unclear if this can happen
|
||||
? new TokenWrapper(parseException.currentToken)
|
||||
: null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,19 +61,6 @@ public class ParseExceptionWrapper {
|
||||
+ ", getCurrentToken()=" + getCurrentToken() + "]";
|
||||
}
|
||||
|
||||
private static Field getAccessibleField(final Class<?> clazz, final String field) throws NoSuchFieldException {
|
||||
final Field declaredField = clazz.getDeclaredField(field);
|
||||
declaredField.setAccessible(true);
|
||||
return declaredField;
|
||||
}
|
||||
|
||||
private static Object getValue(final Field field, final Object instance) {
|
||||
try {
|
||||
return field.get(instance);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link TokenWrapper} which wraps the
|
||||
@@ -115,37 +87,37 @@ public class ParseExceptionWrapper {
|
||||
this.tokenInstance = tokenField;
|
||||
|
||||
try {
|
||||
nextTokenField = getAccessibleField(tokenField.getClass(), FIELD_NEXT);
|
||||
nextTokenField = getAccessibleField(FIELD_NEXT);
|
||||
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
|
||||
nextTokenField = null;
|
||||
}
|
||||
try {
|
||||
kindTokenField = getAccessibleField(tokenField.getClass(), FIELD_KIND);
|
||||
kindTokenField = getAccessibleField(FIELD_KIND);
|
||||
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
|
||||
kindTokenField = null;
|
||||
}
|
||||
|
||||
try {
|
||||
imageTokenField = getAccessibleField(tokenField.getClass(), FIELD_IMAGE);
|
||||
imageTokenField = getAccessibleField(FIELD_IMAGE);
|
||||
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
|
||||
imageTokenField = null;
|
||||
}
|
||||
|
||||
try {
|
||||
beginColumnTokenField = getAccessibleField(tokenField.getClass(), FIELD_BEGIN_COL);
|
||||
beginColumnTokenField = getAccessibleField(FIELD_BEGIN_COL);
|
||||
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
|
||||
beginColumnTokenField = null;
|
||||
}
|
||||
|
||||
try {
|
||||
endColumnTokenField = getAccessibleField(tokenField.getClass(), FIELD_END_COL);
|
||||
endColumnTokenField = getAccessibleField(FIELD_END_COL);
|
||||
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
|
||||
endColumnTokenField = null;
|
||||
}
|
||||
}
|
||||
|
||||
public TokenWrapper getNext() {
|
||||
final Object nextToken = getValue(nextTokenField, tokenInstance);
|
||||
final Object nextToken = getValue(nextTokenField);
|
||||
return nextToken != null ? new TokenWrapper(nextToken) : null;
|
||||
|
||||
}
|
||||
@@ -154,28 +126,42 @@ public class ParseExceptionWrapper {
|
||||
if (kindTokenField == null) {
|
||||
return 0;
|
||||
}
|
||||
return (int) getValue(kindTokenField, tokenInstance);
|
||||
return (int) getValue(kindTokenField);
|
||||
}
|
||||
|
||||
public String getImage() {
|
||||
if (imageTokenField == null) {
|
||||
return null;
|
||||
}
|
||||
return (String) getValue(imageTokenField, tokenInstance);
|
||||
return (String) getValue(imageTokenField);
|
||||
}
|
||||
|
||||
public int getBeginColumn() {
|
||||
if (beginColumnTokenField == null) {
|
||||
return 0;
|
||||
}
|
||||
return (int) getValue(beginColumnTokenField, tokenInstance);
|
||||
return (int) getValue(beginColumnTokenField);
|
||||
}
|
||||
|
||||
public int getEndColumn() {
|
||||
if (endColumnTokenField == null) {
|
||||
return 0;
|
||||
}
|
||||
return (int) getValue(endColumnTokenField, tokenInstance);
|
||||
return (int) getValue(endColumnTokenField);
|
||||
}
|
||||
|
||||
private Field getAccessibleField(final String field) throws NoSuchFieldException {
|
||||
final Field declaredField = tokenInstance.getClass().getDeclaredField(field);
|
||||
ReflectionUtils.makeAccessible(declaredField);
|
||||
return declaredField;
|
||||
}
|
||||
|
||||
private Object getValue(final Field field) {
|
||||
try {
|
||||
return field.get(tokenInstance);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new IllegalFieldAccessExeption(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,4 +171,11 @@ public class ParseExceptionWrapper {
|
||||
+ ", getEndColumn()=" + getEndColumn() + "]";
|
||||
}
|
||||
}
|
||||
|
||||
static class IllegalFieldAccessExeption extends RuntimeException {
|
||||
public IllegalFieldAccessExeption(Throwable e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ public class RsqlParserValidationOracle implements RsqlValidationOracle {
|
||||
private static List<SuggestToken> getNextTokens(final ParseException parseException) {
|
||||
final List<SuggestToken> listTokens = new ArrayList<>();
|
||||
final ParseExceptionWrapper parseExceptionWrapper = new ParseExceptionWrapper(parseException);
|
||||
final int[][] expectedTokenSequence = parseExceptionWrapper.getExpectedTokenSequence();
|
||||
final int[][] expectedTokenSequence = parseException.expectedTokenSequences;
|
||||
final TokenWrapper currentToken = parseExceptionWrapper.getCurrentToken();
|
||||
if (currentToken == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -243,8 +243,8 @@ public class RsqlParserValidationOracle implements RsqlValidationOracle {
|
||||
}
|
||||
builder = builder.replace('\r', ' ');
|
||||
builder = builder.replace('\n', ' ');
|
||||
builder = builder.replaceAll(">", " ");
|
||||
builder = builder.replaceAll("<", " ");
|
||||
builder = builder.replace(">", " ");
|
||||
builder = builder.replace("<", " ");
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user