Skip to content

Commit

Permalink
JPA Refactoring (#2107)
Browse files Browse the repository at this point in the history
Signed-off-by: Avgustin Marinov <[email protected]>
  • Loading branch information
avgustinmm authored Nov 29, 2024
1 parent ebcb6a0 commit 2a95adc
Show file tree
Hide file tree
Showing 29 changed files with 346 additions and 909 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ public static <J> long countBySpec(final JpaSpecificationExecutor<J> repository,

public static <J extends AbstractJpaBaseEntity> J touch(final EntityManager entityManager,
final CrudRepository<J, ?> repository, final J entity) {
// merge base entity so optLockRevision gets updated and audit
// log written because modifying e.g. metadata is modifying the base
// merge base entity so optLockRevision gets updated and auditing log written because modifying e.g. metadata is modifying the base
// entity itself for auditing purposes.
final J result = entityManager.merge(entity);
result.setLastModifiedAt(0L);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -592,13 +592,11 @@ public DistributionSet unassignSoftwareModule(final long id, final long moduleId
backoff = @Backoff(delay = Constants.TX_RT_DELAY))
public DistributionSetMetadata updateMetaData(final long id, final MetaData md) {
// check if exists otherwise throw entity not found exception
final JpaDistributionSetMetadata toUpdate = (JpaDistributionSetMetadata) getMetaDataByDistributionSetId(id,
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, it will, also check UPDATE access
// 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) getValid(id));
return distributionSetMetadataRepository.save(toUpdate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import jakarta.persistence.Version;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
Expand All @@ -38,11 +39,12 @@
import org.springframework.security.core.context.SecurityContextHolder;

/**
* Holder of the base attributes common to all entities.
* Base hawkBit entity class containing the common attributes.
*/
@NoArgsConstructor(access = AccessLevel.PROTECTED) // Default constructor needed for JPA entities.
@Setter
@Getter
@MappedSuperclass
@Access(AccessType.FIELD)
@EntityListeners({ AuditingEntityListener.class, EntityInterceptorListener.class })
public abstract class AbstractJpaBaseEntity implements BaseEntity {

Expand All @@ -51,62 +53,53 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
@Serial
private static final long serialVersionUID = 1L;

@Setter
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@Column(name = "created_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
private String createdBy;
@Column(name = "created_at", updatable = false, nullable = false)
private long createdAt;
@Column(name = "last_modified_by", nullable = false, length = USERNAME_FIELD_LENGTH)
private String lastModifiedBy;
@Column(name = "last_modified_at", nullable = false)
private long lastModifiedAt;

@Setter
@Version
@Column(name = "optlock_revision")
private int optLockRevision;

@Override
@Access(AccessType.PROPERTY)
@Column(name = "created_by", updatable = false, nullable = false, length = USERNAME_FIELD_LENGTH)
public String getCreatedBy() {
return createdBy;
}
@CreatedBy
public void setCreatedBy(final String createdBy) {
if (isController()) {
this.createdBy = "CONTROLLER_PLUG_AND_PLAY";

@Override
@Access(AccessType.PROPERTY)
@Column(name = "created_at", updatable = false, nullable = false)
public long getCreatedAt() {
return createdAt;
}
// In general modification audit entry is not changed by the controller.
// However, we want to stay consistent with EnableJpaAuditing#modifyOnCreate=true.
this.lastModifiedBy = this.createdBy;
return;
}

@Override
@Access(AccessType.PROPERTY)
@Column(name = "last_modified_by", nullable = false, length = USERNAME_FIELD_LENGTH)
public String getLastModifiedBy() {
return lastModifiedBy;
this.createdBy = createdBy;
}

@Override
// maybe needed to have correct createdBy value in the database
@Access(AccessType.PROPERTY)
@Column(name = "last_modified_at", nullable = false)
public long getLastModifiedAt() {
return lastModifiedAt;
public String getCreatedBy() {
return createdBy;
}

@Override
public int getOptLockRevision() {
return optLockRevision;
}
@CreatedDate
public void setCreatedAt(final long createdAt) {
this.createdAt = createdAt;

@LastModifiedDate
public void setLastModifiedAt(final long lastModifiedAt) {
// In general modification audit entry is not changed by the controller.
// However, we want to stay consistent with EnableJpaAuditing#modifyOnCreate=true.
if (isController()) {
return;
this.lastModifiedAt = createdAt;
}

this.lastModifiedAt = lastModifiedAt;
}

@LastModifiedBy
Expand All @@ -118,44 +111,36 @@ public void setLastModifiedBy(final String lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}

@CreatedDate
public void setCreatedAt(final long createdAt) {
this.createdAt = createdAt;
// maybe needed to have correct createdAt value in the database
@Access(AccessType.PROPERTY)
public long getCreatedAt() {
return createdAt;
}

// In general modification audit entry is not changed by the controller.
// However, we want to stay consistent with
// EnableJpaAuditing#modifyOnCreate=true.
if (isController()) {
this.lastModifiedAt = createdAt;
}
// seems needed to have correct lastModifiedBy value in the database
@Access(AccessType.PROPERTY)
public String getLastModifiedBy() {
return lastModifiedBy;
}

@CreatedBy
public void setCreatedBy(final String createdBy) {
@LastModifiedDate
public void setLastModifiedAt(final long lastModifiedAt) {
if (isController()) {
this.createdBy = "CONTROLLER_PLUG_AND_PLAY";

// In general modification audit entry is not changed by the
// controller. However, we want to stay consistent with
// EnableJpaAuditing#modifyOnCreate=true.
this.lastModifiedBy = this.createdBy;
return;
}

this.createdBy = createdBy;
this.lastModifiedAt = lastModifiedAt;
}

@Override
public Long getId() {
return id;
// property access to make entity manager to detect touch
@Access(AccessType.PROPERTY)
public long getLastModifiedAt() {
return lastModifiedAt;
}

/**
* Defined equals/hashcode strategy for the repository in general is that an
* entity is equal if it has the same {@link #getId()} and
* Defined equals/hashcode strategy for the repository in general is that an entity is equal if it has the same {@link #getId()} and
* {@link #getOptLockRevision()} and class.
*
* @see java.lang.Object#hashCode()
*/
@Override
// Exception squid:S864 - generated code
Expand All @@ -170,11 +155,8 @@ public int hashCode() {
}

/**
* Defined equals/hashcode strategy for the repository in general is that an
* entity is equal if it has the same {@link #getId()} and
* Defined equals/hashcode strategy for the repository in general is that an entity is equal if it has the same {@link #getId()} and
* {@link #getOptLockRevision()} and class.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@
* Holder of the base attributes common to all tenant aware entities.
*/
@NoArgsConstructor(access = AccessLevel.PROTECTED) // Default constructor needed for JPA entities.
@Setter
@Getter
@MappedSuperclass
// Eclipse link MultiTenant support
@TenantDiscriminatorColumn(name = "tenant", length = 40)
@Multitenant(MultitenantType.SINGLE_TABLE)
public abstract class AbstractJpaTenantAwareBaseEntity extends AbstractJpaBaseEntity implements TenantAwareBaseEntity {

@Serial
private static final long serialVersionUID = 1L;

@Setter
@Getter
@Column(name = "tenant", nullable = false, insertable = false, updatable = false, length = 40)
@Size(min = 1, max = 40)
@NotNull
Expand Down Expand Up @@ -74,13 +75,10 @@ public boolean equals(final Object obj) {
}
final AbstractJpaTenantAwareBaseEntity other = (AbstractJpaTenantAwareBaseEntity) obj;
if (tenant == null) {
if (other.tenant != null) {
return false;
}
} else if (!tenant.equals(other.tenant)) {
return false;
return other.tenant == null;
} else {
return tenant.equals(other.tenant);
}
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,25 @@
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.eclipse.hawkbit.artifact.repository.model.AbstractDbArtifact;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.SoftwareModule;

/**
* JPA implementation of {@link Artifact}.
*/
@Table(name = "sp_artifact", indexes = { @Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
@Index(name = "sp_idx_artifact_02", columnList = "tenant,sha1_hash"),
@Index(name = "sp_idx_artifact_prim", columnList = "tenant,id") })
@NoArgsConstructor(access = AccessLevel.PUBLIC) // Default constructor needed for JPA entities.
@Setter
@Getter
@Table(name = "sp_artifact",
indexes = {
@Index(name = "sp_idx_artifact_01", columnList = "tenant,software_module"),
@Index(name = "sp_idx_artifact_02", columnList = "tenant,sha1_hash"),
@Index(name = "sp_idx_artifact_prim", columnList = "tenant,id") })
@Entity
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for sub entities
@SuppressWarnings("squid:S2160")
Expand All @@ -43,94 +52,42 @@ public class JpaArtifact extends AbstractJpaTenantAwareBaseEntity implements Art
@Serial
private static final long serialVersionUID = 1L;

@Column(name = "sha1_hash", length = 40, nullable = false, updatable = false)
@Size(min = 1, max = 40)
@NotNull
private String sha1Hash;
@ManyToOne(optional = false, cascade = { CascadeType.PERSIST }, fetch = FetchType.LAZY)
@JoinColumn(
name = "software_module", nullable = false, updatable = false,
foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_assigned_sm"))
private JpaSoftwareModule softwareModule;

@Column(name = "provided_file_name", length = 256, updatable = false)
@Size(min = 1, max = 256)
@NotNull
private String filename;

@ManyToOne(optional = false, cascade = { CascadeType.PERSIST }, fetch = FetchType.LAZY)
@JoinColumn(name = "software_module", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_assigned_sm"))
private JpaSoftwareModule softwareModule;

@Column(name = "md5_hash", length = 32, updatable = false, nullable = true)
private String md5Hash;

@Column(name = "sha1_hash", length = 40, nullable = false, updatable = false)
@Size(min = 1, max = 40)
@NotNull
private String sha1Hash;

@Column(name = "sha256_hash", length = 64, updatable = false, nullable = true)
private String sha256Hash;

@Column(name = "file_size", updatable = false)
private long size;

/**
* Default constructor needed for JPA entities..
*/
public JpaArtifact() {
// Default constructor needed for JPA entities.
}

/**
* Constructs artifact.
*
* @param sha1Hash that is the link to the {@link AbstractDbArtifact} entity.
* @param filename that is used by {@link AbstractDbArtifact} store.
* @param softwareModule of this artifact
*/
public JpaArtifact(@NotEmpty final String sha1Hash, @NotNull final String filename,
final SoftwareModule softwareModule) {
public JpaArtifact(@NotEmpty final String sha1Hash, @NotNull final String filename, final SoftwareModule softwareModule) {
this.sha1Hash = sha1Hash;
this.filename = filename;
this.softwareModule = (JpaSoftwareModule) softwareModule;
this.softwareModule.addArtifact(this);
}

@Override
public String getFilename() {
return filename;
}

@Override
public SoftwareModule getSoftwareModule() {
return softwareModule;
}

@Override
public String getMd5Hash() {
return md5Hash;
}

@Override
public String getSha1Hash() {
return sha1Hash;
}

@Override
public String getSha256Hash() {
return sha256Hash;
}

public void setSha256Hash(final String sha256Hash) {
this.sha256Hash = sha256Hash;
}

@Override
public long getSize() {
return size;
}

public void setSize(final long size) {
this.size = size;
}

public void setSha1Hash(final String sha1Hash) {
this.sha1Hash = sha1Hash;
}

public void setMd5Hash(final String md5Hash) {
this.md5Hash = md5Hash;
}
}
}
Loading

0 comments on commit 2a95adc

Please sign in to comment.