Removed the extra level of abstraction and modified the code

accordingly.
This commit is contained in:
GAH6KOR
2016-07-21 12:39:54 +02:00
parent 7afb2f996f
commit 5f1db53def
12 changed files with 1673 additions and 1687 deletions

View File

@@ -1,189 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.executor.AfterTransactionCommitExecutor;
import org.eclipse.hawkbit.repository.jpa.model.DescriptorEventDetails.ActionType;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.queries.UpdateObjectQuery;
import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.eventbus.EventBus;
/**
* Implementation of @link{AbstractDescriptorEventVisitor} .Publishes the
* appropriate event after any action on entity like create/update.
*
*/
public class AbstractDescriptorEventVisitorImpl implements
AbstractDescriptorEventVisitor {
private static final String COMPLETE = "complete";
private static final Logger LOG = LoggerFactory
.getLogger(AbstractDescriptorEventVisitorImpl.class);
@Override
public void publishEventPostAction(final DescriptorEventDetails event) {
Method method = null;
DescriptorEvent descriptorEvent = event.getDescriptorEvent();
ActionType actiontype = event.getActiontype();
try {
method = getMethod(descriptorEvent, actiontype);
if (method != null) {
method.invoke(this, descriptorEvent.getObject(),
descriptorEvent);
}
} catch (NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
LOG.info(
"Exception when invoking approriate method to publis event {}",
e);
}
}
private Method getMethod(DescriptorEvent descriptorEvent,
ActionType actiontype) throws NoSuchMethodException {
if (actiontype == ActionType.UPDATE) {
return this.getClass().getMethod("publishEventAfterUpdate",
descriptorEvent.getObject().getClass(),
DescriptorEvent.class);
} else if (actiontype == ActionType.CREATE) {
return this.getClass().getMethod("publishEventAfterCreate",
descriptorEvent.getObject().getClass(),
DescriptorEvent.class);
}
return null;
}
public void publishEventAfterCreate(JpaAction action, DescriptorEvent event) {
if (action.getRollout() != null) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(new ActionCreatedEvent(action)));
}
}
public void publishEventAfterCreate(JpaTarget target, DescriptorEvent event) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(new TargetCreatedEvent(target)));
}
public void publishEventAfterCreate(JpaDistributionSet ds,
DescriptorEvent event) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(new DistributionCreatedEvent(ds)));
}
public void publishEventAfterUpdate(JpaAction action, DescriptorEvent event) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(
new ActionPropertyChangeEvent(action, getChangeSet(
Action.class, event))));
}
public void publishEventAfterUpdate(JpaTarget target, DescriptorEvent event) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(new TargetUpdatedEvent(target)));
}
public void publishEventAfterUpdate(JpaTargetInfo targetInfo,
DescriptorEvent event) {
getAfterTransactionCommmitExecutor()
.afterCommit(
() -> getEventBus().post(
new TargetInfoUpdateEvent(targetInfo)));
}
public void publishEventAfterUpdate(JpaRollout entity, DescriptorEvent event) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(
new RolloutPropertyChangeEvent(entity, getChangeSet(
Rollout.class, event))));
}
public void publishEventAfterUpdate(JpaRolloutGroup entity,
DescriptorEvent event) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(
new RolloutGroupPropertyChangeEvent(entity,
getChangeSet(RolloutGroup.class, event))));
}
public void publishEventAfterUpdate(JpaDistributionSet entity,
DescriptorEvent event) {
Map<String, AbstractPropertyChangeEvent<JpaDistributionSet>.Values> changeSet = getChangeSet(
JpaDistributionSet.class, event);
if (changeSet.containsKey(COMPLETE)
&& changeSet.get(COMPLETE).getOldValue().equals(false)
&& changeSet.get(COMPLETE).getNewValue().equals(true)) {
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus().post(
new DistributionCreatedEvent(entity)));
}
getAfterTransactionCommmitExecutor().afterCommit(
() -> getEventBus()
.post(new DistributionSetUpdateEvent(entity)));
}
private <T extends TenantAwareBaseEntity> Map<String, AbstractPropertyChangeEvent<T>.Values> getChangeSet(
final Class<T> clazz, final DescriptorEvent event) {
final T rolloutGroup = clazz.cast(event.getObject());
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery())
.getObjectChangeSet();
return changeSet
.getChanges()
.stream()
.filter(record -> record instanceof DirectToFieldChangeRecord)
.map(record -> (DirectToFieldChangeRecord) record)
.collect(
Collectors.toMap(
record -> record.getAttribute(),
record -> new AbstractPropertyChangeEvent<T>(
rolloutGroup, null).new Values(record
.getOldValue(), record.getNewValue())));
}
private AfterTransactionCommitExecutor getAfterTransactionCommmitExecutor() {
return AfterTransactionCommitExecutorHolder.getInstance()
.getAfterCommit();
}
private EventBus getEventBus() {
return EventBusHolder.getInstance().getEventBus();
}
}

View File

@@ -32,7 +32,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
@MappedSuperclass
@Access(AccessType.FIELD)
@EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class, EntityPropertyChangeListener.class })
public abstract class AbstractJpaBaseEntity implements BaseEntity,AcceptVisitor {
public abstract class AbstractJpaBaseEntity implements BaseEntity {
private static final long serialVersionUID = 1L;
@Id
@@ -179,8 +179,4 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity,AcceptVisitor
}
@Override
public void postActionOnEntity(AbstractDescriptorEventVisitor visitor, DescriptorEventDetails eventDetails){
visitor.publishEventPostAction(eventDetails);
}
}

View File

@@ -1,18 +0,0 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
/**
* Interface to accept visitor @link{AbstractDescriptorEventVisitor}.
*
*/
public interface AcceptVisitor {
public void postActionOnEntity(AbstractDescriptorEventVisitor visitor,
DescriptorEventDetails eventDetails);
}

View File

@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import org.eclipse.hawkbit.repository.jpa.model.DescriptorEventDetails.ActionType;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
@@ -18,19 +17,23 @@ import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
*/
public class EntityPropertyChangeListener extends DescriptorEventAdapter {
@Override
public void postInsert(final DescriptorEvent event) {
AbstractDescriptorEventVisitor visitor = new AbstractDescriptorEventVisitorImpl();
((AbstractJpaBaseEntity) event.getObject()).postActionOnEntity(visitor,
new DescriptorEventDetails(ActionType.CREATE, event));
@Override
public void postInsert(final DescriptorEvent event) {
final Object object = event.getObject();
if (object instanceof EventAwareEntity) {
((EventAwareEntity) object).fireCreateEvent(object,event);
}
}
@Override
public void postUpdate(final DescriptorEvent event) {
final Object object = event.getObject();
if (object instanceof EventAwareEntity) {
((EventAwareEntity) object).fireUpdateEvent(object,event);
}
}
}
@Override
public void postUpdate(final DescriptorEvent event) {
AbstractDescriptorEventVisitor visitor = new AbstractDescriptorEventVisitorImpl();
((AbstractJpaBaseEntity) event.getObject()).postActionOnEntity(visitor,
new DescriptorEventDetails(ActionType.UPDATE, event));
}
}

View File

@@ -8,12 +8,13 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
/**
*
* Interface defining the action to be performed after entity is
* created/updated.
*
*/
public interface AbstractDescriptorEventVisitor {
void publishEventPostAction(DescriptorEventDetails eventDetails);
import org.eclipse.persistence.descriptors.DescriptorEvent;
public interface EventAwareEntity<T> {
public void fireCreateEvent(T t,DescriptorEvent descriptorEvent);
public void fireUpdateEvent(T t,DescriptorEvent descriptorEvent);
public void fireDeleteEvent(T t,DescriptorEvent descriptorEvent);
}

View File

@@ -1,174 +1,199 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedSubgraph;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionStatus;
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.Target;
import org.eclipse.persistence.annotations.CascadeOnDelete;
/**
* JPA implementation of {@link Action}.
*/
@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"))) })
@Entity
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds"))
private JpaDistributionSet distributionSet;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target"))
private JpaTarget target;
@Column(name = "active")
private boolean active;
@Column(name = "action_type", nullable = false)
@Enumerated(EnumType.STRING)
private ActionType actionType;
@Column(name = "forced_time")
private long forcedTime;
@Column(name = "status")
private Status status;
@CascadeOnDelete
@OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = {
CascadeType.REMOVE })
private List<ActionStatus> actionStatus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup"))
private JpaRolloutGroup rolloutGroup;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
private JpaRollout rollout;
@Override
public DistributionSet getDistributionSet() {
return distributionSet;
}
@Override
public void setDistributionSet(final DistributionSet distributionSet) {
this.distributionSet = (JpaDistributionSet) distributionSet;
}
public void setActive(final boolean active) {
this.active = active;
}
@Override
public Status getStatus() {
return status;
}
@Override
public void setStatus(final Status status) {
this.status = status;
}
@Override
public boolean isActive() {
return active;
}
public void setActionType(final ActionType actionType) {
this.actionType = actionType;
}
@Override
public ActionType getActionType() {
return actionType;
}
@Override
public List<ActionStatus> getActionStatus() {
return actionStatus;
}
@Override
public void setTarget(final Target target) {
this.target = (JpaTarget) target;
}
@Override
public Target getTarget() {
return target;
}
@Override
public long getForcedTime() {
return forcedTime;
}
public void setForcedTime(final long forcedTime) {
this.forcedTime = forcedTime;
}
@Override
public RolloutGroup getRolloutGroup() {
return rolloutGroup;
}
public void setRolloutGroup(final RolloutGroup rolloutGroup) {
this.rolloutGroup = (JpaRolloutGroup) rolloutGroup;
}
@Override
public Rollout getRollout() {
return rollout;
}
public void setRollout(final Rollout rollout) {
this.rollout = (JpaRollout) rollout;
}
@Override
public String toString() {
return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]";
}
}
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.NamedSubgraph;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.hawkbit.repository.eventbus.event.ActionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.ActionPropertyChangeEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.ActionStatus;
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.Target;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.eclipse.persistence.descriptors.DescriptorEvent;
/**
* JPA implementation of {@link Action}.
*/
@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"))) })
@Entity
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Action,EventAwareEntity<JpaAction> {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_ds"))
private JpaDistributionSet distributionSet;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_target"))
private JpaTarget target;
@Column(name = "active")
private boolean active;
@Column(name = "action_type", nullable = false)
@Enumerated(EnumType.STRING)
private ActionType actionType;
@Column(name = "forced_time")
private long forcedTime;
@Column(name = "status")
private Status status;
@CascadeOnDelete
@OneToMany(mappedBy = "action", targetEntity = JpaActionStatus.class, fetch = FetchType.LAZY, cascade = {
CascadeType.REMOVE })
private List<ActionStatus> actionStatus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rolloutgroup", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rolloutgroup"))
private JpaRolloutGroup rolloutGroup;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_action_rollout"))
private JpaRollout rollout;
@Override
public DistributionSet getDistributionSet() {
return distributionSet;
}
@Override
public void setDistributionSet(final DistributionSet distributionSet) {
this.distributionSet = (JpaDistributionSet) distributionSet;
}
public void setActive(final boolean active) {
this.active = active;
}
@Override
public Status getStatus() {
return status;
}
@Override
public void setStatus(final Status status) {
this.status = status;
}
@Override
public boolean isActive() {
return active;
}
public void setActionType(final ActionType actionType) {
this.actionType = actionType;
}
@Override
public ActionType getActionType() {
return actionType;
}
@Override
public List<ActionStatus> getActionStatus() {
return actionStatus;
}
@Override
public void setTarget(final Target target) {
this.target = (JpaTarget) target;
}
@Override
public Target getTarget() {
return target;
}
@Override
public long getForcedTime() {
return forcedTime;
}
public void setForcedTime(final long forcedTime) {
this.forcedTime = forcedTime;
}
@Override
public RolloutGroup getRolloutGroup() {
return rolloutGroup;
}
public void setRolloutGroup(final RolloutGroup rolloutGroup) {
this.rolloutGroup = (JpaRolloutGroup) rolloutGroup;
}
@Override
public Rollout getRollout() {
return rollout;
}
public void setRollout(final Rollout rollout) {
this.rollout = (JpaRollout) rollout;
}
@Override
public String toString() {
return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]";
}
@Override
public void fireCreateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new ActionCreatedEvent(jpaAction)));
}
@Override
public void fireUpdateEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().
post(new ActionPropertyChangeEvent(jpaAction, EntityPropertyChangeHelper.getChangeSet(Action.class, descriptorEvent))));
}
@Override
public void fireDeleteEvent(final JpaAction jpaAction, final DescriptorEvent descriptorEvent) {
}
}

View File

@@ -1,282 +1,320 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException;
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.persistence.annotations.CascadeOnDelete;
/**
* Jpa implementation of {@link DistributionSet}.
*
*/
@Entity
@Table(name = "sp_distribution_set", uniqueConstraints = {
@UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = {
@Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,name,complete"),
@Index(name = "sp_idx_distribution_set_02", columnList = "tenant,required_migration_step"),
@Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") })
@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"),
@NamedAttributeNode("tags"), @NamedAttributeNode("type") })
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet {
private static final long serialVersionUID = 1L;
@Column(name = "required_migration_step")
private boolean requiredMigrationStep;
@ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY)
@JoinTable(name = "sp_ds_module", joinColumns = {
@JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = {
@JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) })
private final Set<SoftwareModule> modules = new HashSet<>();
@ManyToMany(targetEntity = JpaDistributionSetTag.class)
@JoinTable(name = "sp_ds_dstag", joinColumns = {
@JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds")) }, inverseJoinColumns = {
@JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag")) })
private Set<DistributionSetTag> tags = new HashSet<>();
@Column(name = "deleted")
private boolean deleted;
@OneToMany(mappedBy = "assignedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY)
private List<Target> assignedToTargets;
@OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY)
private List<TargetInfo> installedAtTargets;
@OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY)
private List<Action> actions;
@CascadeOnDelete
@OneToMany(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetMetadata.class, cascade = {
CascadeType.REMOVE })
@JoinColumn(name = "ds_id", insertable = false, updatable = false)
private final List<DistributionSetMetadata> metadata = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class)
@JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds"))
private DistributionSetType type;
@Column(name = "complete")
private boolean complete;
/**
* Default constructor.
*/
public JpaDistributionSet() {
super();
}
/**
* Parameterized constructor.
*
* @param name
* of the {@link DistributionSet}
* @param version
* of the {@link DistributionSet}
* @param description
* of the {@link DistributionSet}
* @param type
* of the {@link DistributionSet}
* @param moduleList
* {@link SoftwareModule}s of the {@link DistributionSet}
*/
public JpaDistributionSet(final String name, final String version, final String description,
final DistributionSetType type, final Collection<SoftwareModule> moduleList) {
super(name, version, description);
this.type = type;
if (moduleList != null) {
moduleList.forEach(this::addModule);
}
if (this.type != null) {
complete = this.type.checkComplete(this);
}
}
@Override
public Set<DistributionSetTag> getTags() {
return tags;
}
@Override
public boolean isDeleted() {
return deleted;
}
@Override
public List<DistributionSetMetadata> getMetadata() {
return Collections.unmodifiableList(metadata);
}
public List<Action> getActions() {
return actions;
}
@Override
public boolean isRequiredMigrationStep() {
return requiredMigrationStep;
}
@Override
public DistributionSet setDeleted(final boolean deleted) {
this.deleted = deleted;
return this;
}
@Override
public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) {
requiredMigrationStep = isRequiredMigrationStep;
return this;
}
public DistributionSet setTags(final Set<DistributionSetTag> tags) {
this.tags = tags;
return this;
}
@Override
public List<Target> getAssignedTargets() {
return assignedToTargets;
}
@Override
public List<TargetInfo> getInstalledTargets() {
return installedAtTargets;
}
@Override
public String toString() {
return "DistributionSet [getName()=" + getName() + ", getOptLockRevision()=" + getOptLockRevision()
+ ", getId()=" + getId() + "]";
}
@Override
public Set<SoftwareModule> getModules() {
return Collections.unmodifiableSet(modules);
}
@Override
public boolean addModule(final SoftwareModule softwareModule) {
// we cannot allow that modules are added without a type defined
if (type == null) {
throw new DistributionSetTypeUndefinedException();
}
// check if it is allowed to such a module to this DS type
if (!type.containsModuleType(softwareModule.getType())) {
throw new UnsupportedSoftwareModuleForThisDistributionSetException();
}
final Optional<SoftwareModule> found = modules.stream()
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
if (found.isPresent()) {
return false;
}
final long allready = modules.stream()
.filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count();
if (allready >= softwareModule.getType().getMaxAssignments()) {
final Optional<SoftwareModule> sameKey = modules.stream()
.filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).findFirst();
modules.remove(sameKey.get());
}
if (modules.add(softwareModule)) {
complete = type.checkComplete(this);
return true;
}
return false;
}
@Override
public boolean removeModule(final SoftwareModule softwareModule) {
final Optional<SoftwareModule> found = modules.stream()
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
if (found.isPresent()) {
modules.remove(found.get());
complete = type.checkComplete(this);
return true;
}
return false;
}
@Override
public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) {
final Optional<SoftwareModule> result = modules.stream().filter(module -> module.getType().equals(type))
.findFirst();
if (result.isPresent()) {
return result.get();
}
return null;
}
@Override
public DistributionSetType getType() {
return type;
}
@Override
public void setType(final DistributionSetType type) {
this.type = type;
}
@Override
public boolean isComplete() {
return complete;
}
}
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.DistributionSetUpdateEvent;
import org.eclipse.hawkbit.repository.exception.DistributionSetTypeUndefinedException;
import org.eclipse.hawkbit.repository.exception.UnsupportedSoftwareModuleForThisDistributionSetException;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
import org.eclipse.hawkbit.repository.model.DistributionSetTag;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.eclipse.persistence.descriptors.DescriptorEvent;
/**
* Jpa implementation of {@link DistributionSet}.
*
*/
@Entity
@Table(name = "sp_distribution_set", uniqueConstraints = {
@UniqueConstraint(columnNames = { "name", "version", "tenant" }, name = "uk_distrib_set") }, indexes = {
@Index(name = "sp_idx_distribution_set_01", columnList = "tenant,deleted,name,complete"),
@Index(name = "sp_idx_distribution_set_02", columnList = "tenant,required_migration_step"),
@Index(name = "sp_idx_distribution_set_prim", columnList = "tenant,id") })
@NamedEntityGraph(name = "DistributionSet.detail", attributeNodes = { @NamedAttributeNode("modules"),
@NamedAttributeNode("tags"), @NamedAttributeNode("type") })
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implements DistributionSet,EventAwareEntity<JpaDistributionSet> {
private static final long serialVersionUID = 1L;
private static final String COMPLETE = "complete";
@Column(name = "required_migration_step")
private boolean requiredMigrationStep;
@ManyToMany(targetEntity = JpaSoftwareModule.class, fetch = FetchType.LAZY)
@JoinTable(name = "sp_ds_module", joinColumns = {
@JoinColumn(name = "ds_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_ds")) }, inverseJoinColumns = {
@JoinColumn(name = "module_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_module_module")) })
private final Set<SoftwareModule> modules = new HashSet<>();
@ManyToMany(targetEntity = JpaDistributionSetTag.class)
@JoinTable(name = "sp_ds_dstag", joinColumns = {
@JoinColumn(name = "ds", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_ds")) }, inverseJoinColumns = {
@JoinColumn(name = "TAG", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstag_tag")) })
private Set<DistributionSetTag> tags = new HashSet<>();
@Column(name = "deleted")
private boolean deleted;
@OneToMany(mappedBy = "assignedDistributionSet", targetEntity = JpaTarget.class, fetch = FetchType.LAZY)
private List<Target> assignedToTargets;
@OneToMany(mappedBy = "installedDistributionSet", targetEntity = JpaTargetInfo.class, fetch = FetchType.LAZY)
private List<TargetInfo> installedAtTargets;
@OneToMany(mappedBy = "distributionSet", targetEntity = JpaAction.class, fetch = FetchType.LAZY)
private List<Action> actions;
@CascadeOnDelete
@OneToMany(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetMetadata.class, cascade = {
CascadeType.REMOVE })
@JoinColumn(name = "ds_id", insertable = false, updatable = false)
private final List<DistributionSetMetadata> metadata = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class)
@JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds"))
private DistributionSetType type;
@Column(name = "complete")
private boolean complete;
/**
* Default constructor.
*/
public JpaDistributionSet() {
super();
}
/**
* Parameterized constructor.
*
* @param name
* of the {@link DistributionSet}
* @param version
* of the {@link DistributionSet}
* @param description
* of the {@link DistributionSet}
* @param type
* of the {@link DistributionSet}
* @param moduleList
* {@link SoftwareModule}s of the {@link DistributionSet}
*/
public JpaDistributionSet(final String name, final String version, final String description,
final DistributionSetType type, final Collection<SoftwareModule> moduleList) {
super(name, version, description);
this.type = type;
if (moduleList != null) {
moduleList.forEach(this::addModule);
}
if (this.type != null) {
complete = this.type.checkComplete(this);
}
}
@Override
public Set<DistributionSetTag> getTags() {
return tags;
}
@Override
public boolean isDeleted() {
return deleted;
}
@Override
public List<DistributionSetMetadata> getMetadata() {
return Collections.unmodifiableList(metadata);
}
public List<Action> getActions() {
return actions;
}
@Override
public boolean isRequiredMigrationStep() {
return requiredMigrationStep;
}
@Override
public DistributionSet setDeleted(final boolean deleted) {
this.deleted = deleted;
return this;
}
@Override
public DistributionSet setRequiredMigrationStep(final boolean isRequiredMigrationStep) {
requiredMigrationStep = isRequiredMigrationStep;
return this;
}
public DistributionSet setTags(final Set<DistributionSetTag> tags) {
this.tags = tags;
return this;
}
@Override
public List<Target> getAssignedTargets() {
return assignedToTargets;
}
@Override
public List<TargetInfo> getInstalledTargets() {
return installedAtTargets;
}
@Override
public String toString() {
return "DistributionSet [getName()=" + getName() + ", getOptLockRevision()=" + getOptLockRevision()
+ ", getId()=" + getId() + "]";
}
@Override
public Set<SoftwareModule> getModules() {
return Collections.unmodifiableSet(modules);
}
@Override
public boolean addModule(final SoftwareModule softwareModule) {
// we cannot allow that modules are added without a type defined
if (type == null) {
throw new DistributionSetTypeUndefinedException();
}
// check if it is allowed to such a module to this DS type
if (!type.containsModuleType(softwareModule.getType())) {
throw new UnsupportedSoftwareModuleForThisDistributionSetException();
}
final Optional<SoftwareModule> found = modules.stream()
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
if (found.isPresent()) {
return false;
}
final long allready = modules.stream()
.filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).count();
if (allready >= softwareModule.getType().getMaxAssignments()) {
final Optional<SoftwareModule> sameKey = modules.stream()
.filter(module -> module.getType().getKey().equals(softwareModule.getType().getKey())).findFirst();
modules.remove(sameKey.get());
}
if (modules.add(softwareModule)) {
complete = type.checkComplete(this);
return true;
}
return false;
}
@Override
public boolean removeModule(final SoftwareModule softwareModule) {
final Optional<SoftwareModule> found = modules.stream()
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
if (found.isPresent()) {
modules.remove(found.get());
complete = type.checkComplete(this);
return true;
}
return false;
}
@Override
public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) {
final Optional<SoftwareModule> result = modules.stream().filter(module -> module.getType().equals(type))
.findFirst();
if (result.isPresent()) {
return result.get();
}
return null;
}
@Override
public DistributionSetType getType() {
return type;
}
@Override
public void setType(final DistributionSetType type) {
this.type = type;
}
@Override
public boolean isComplete() {
return complete;
}
@Override
public void fireCreateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new DistributionCreatedEvent(jpaDistributionSet)));
}
@Override
public void fireUpdateEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) {
final Map<String, AbstractPropertyChangeEvent<JpaDistributionSet>.Values> changeSet = EntityPropertyChangeHelper.getChangeSet(
JpaDistributionSet.class, descriptorEvent);
if (changeSet.containsKey(COMPLETE)
&& changeSet.get(COMPLETE).getOldValue().equals(false)
&& changeSet.get(COMPLETE).getNewValue().equals(true)) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(
() -> EventBusHolder.getInstance().getEventBus().post(
new DistributionCreatedEvent(jpaDistributionSet)));
}
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(
() -> EventBusHolder.getInstance().getEventBus().post(new DistributionSetUpdateEvent(jpaDistributionSet)));
}
@Override
public void fireDeleteEvent(final JpaDistributionSet jpaDistributionSet, final DescriptorEvent descriptorEvent) {
}
}

View File

@@ -1,200 +1,223 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
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.TotalTargetCountStatus;
/**
* JPA implementation of a {@link Rollout}.
*
*/
@Entity
@Table(name = "sp_rollout", indexes = {
@Index(name = "sp_idx_rollout_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = {
"name", "tenant" }, name = "uk_rollout"))
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaRollout extends AbstractJpaNamedEntity implements Rollout {
private static final long serialVersionUID = 1L;
@OneToMany(targetEntity = JpaRolloutGroup.class)
@JoinColumn(name = "rollout", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollout_rolloutgroup"))
private List<RolloutGroup> rolloutGroups;
@Column(name = "target_filter", length = 1024, nullable = false)
private String targetFilterQuery;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolltout_ds"))
private JpaDistributionSet distributionSet;
@Column(name = "status")
private RolloutStatus status = RolloutStatus.CREATING;
@Column(name = "last_check")
private long lastCheck;
@Column(name = "action_type", nullable = false)
@Enumerated(EnumType.STRING)
private ActionType actionType = ActionType.FORCED;
@Column(name = "forced_time")
private long forcedTime;
@Column(name = "total_targets")
private long totalTargets;
@Transient
@CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL)
private int rolloutGroupsTotal;
@Transient
@CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED)
private int rolloutGroupsCreated;
@Transient
private transient TotalTargetCountStatus totalTargetCountStatus;
@Override
public DistributionSet getDistributionSet() {
return distributionSet;
}
@Override
public void setDistributionSet(final DistributionSet distributionSet) {
this.distributionSet = (JpaDistributionSet) distributionSet;
}
@Override
public List<RolloutGroup> getRolloutGroups() {
return rolloutGroups;
}
public void setRolloutGroups(final List<RolloutGroup> rolloutGroups) {
this.rolloutGroups = rolloutGroups;
}
@Override
public String getTargetFilterQuery() {
return targetFilterQuery;
}
@Override
public void setTargetFilterQuery(final String targetFilterQuery) {
this.targetFilterQuery = targetFilterQuery;
}
@Override
public RolloutStatus getStatus() {
return status;
}
public void setStatus(final RolloutStatus status) {
this.status = status;
}
public long getLastCheck() {
return lastCheck;
}
public void setLastCheck(final long lastCheck) {
this.lastCheck = lastCheck;
}
@Override
public ActionType getActionType() {
return actionType;
}
@Override
public void setActionType(final ActionType actionType) {
this.actionType = actionType;
}
@Override
public long getForcedTime() {
return forcedTime;
}
@Override
public void setForcedTime(final long forcedTime) {
this.forcedTime = forcedTime;
}
@Override
public long getTotalTargets() {
return totalTargets;
}
public void setTotalTargets(final long totalTargets) {
this.totalTargets = totalTargets;
}
public int getRolloutGroupsTotal() {
return rolloutGroupsTotal;
}
public void setRolloutGroupsTotal(final int rolloutGroupsTotal) {
this.rolloutGroupsTotal = rolloutGroupsTotal;
}
@Override
public int getRolloutGroupsCreated() {
return rolloutGroupsCreated;
}
public void setRolloutGroupsCreated(final int rolloutGroupsCreated) {
this.rolloutGroupsCreated = rolloutGroupsCreated;
}
@Override
public TotalTargetCountStatus getTotalTargetCountStatus() {
if (totalTargetCountStatus == null) {
totalTargetCountStatus = new TotalTargetCountStatus(totalTargets);
}
return totalTargetCountStatus;
}
public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) {
this.totalTargetCountStatus = totalTargetCountStatus;
}
@Override
public String toString() {
return "Rollout [rolloutGroups=" + rolloutGroups + ", targetFilterQuery=" + targetFilterQuery
+ ", distributionSet=" + distributionSet + ", status=" + status + ", lastCheck=" + lastCheck
+ ", getName()=" + getName() + ", getId()=" + getId() + "]";
}
}
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutPropertyChangeEvent;
import org.eclipse.hawkbit.repository.jpa.cache.CacheField;
import org.eclipse.hawkbit.repository.jpa.cache.CacheKeys;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
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.TotalTargetCountStatus;
import org.eclipse.persistence.descriptors.DescriptorEvent;
/**
* JPA implementation of a {@link Rollout}.
*
*/
@Entity
@Table(name = "sp_rollout", indexes = {
@Index(name = "sp_idx_rollout_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = {
"name", "tenant" }, name = "uk_rollout"))
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaRollout extends AbstractJpaNamedEntity implements Rollout,EventAwareEntity<JpaRollout> {
private static final long serialVersionUID = 1L;
@OneToMany(targetEntity = JpaRolloutGroup.class)
@JoinColumn(name = "rollout", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rollout_rolloutgroup"))
private List<RolloutGroup> rolloutGroups;
@Column(name = "target_filter", length = 1024, nullable = false)
private String targetFilterQuery;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "distribution_set", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolltout_ds"))
private JpaDistributionSet distributionSet;
@Column(name = "status")
private RolloutStatus status = RolloutStatus.CREATING;
@Column(name = "last_check")
private long lastCheck;
@Column(name = "action_type", nullable = false)
@Enumerated(EnumType.STRING)
private ActionType actionType = ActionType.FORCED;
@Column(name = "forced_time")
private long forcedTime;
@Column(name = "total_targets")
private long totalTargets;
@Transient
@CacheField(key = CacheKeys.ROLLOUT_GROUP_TOTAL)
private int rolloutGroupsTotal;
@Transient
@CacheField(key = CacheKeys.ROLLOUT_GROUP_CREATED)
private int rolloutGroupsCreated;
@Transient
private transient TotalTargetCountStatus totalTargetCountStatus;
@Override
public DistributionSet getDistributionSet() {
return distributionSet;
}
@Override
public void setDistributionSet(final DistributionSet distributionSet) {
this.distributionSet = (JpaDistributionSet) distributionSet;
}
@Override
public List<RolloutGroup> getRolloutGroups() {
return rolloutGroups;
}
public void setRolloutGroups(final List<RolloutGroup> rolloutGroups) {
this.rolloutGroups = rolloutGroups;
}
@Override
public String getTargetFilterQuery() {
return targetFilterQuery;
}
@Override
public void setTargetFilterQuery(final String targetFilterQuery) {
this.targetFilterQuery = targetFilterQuery;
}
@Override
public RolloutStatus getStatus() {
return status;
}
public void setStatus(final RolloutStatus status) {
this.status = status;
}
public long getLastCheck() {
return lastCheck;
}
public void setLastCheck(final long lastCheck) {
this.lastCheck = lastCheck;
}
@Override
public ActionType getActionType() {
return actionType;
}
@Override
public void setActionType(final ActionType actionType) {
this.actionType = actionType;
}
@Override
public long getForcedTime() {
return forcedTime;
}
@Override
public void setForcedTime(final long forcedTime) {
this.forcedTime = forcedTime;
}
@Override
public long getTotalTargets() {
return totalTargets;
}
public void setTotalTargets(final long totalTargets) {
this.totalTargets = totalTargets;
}
public int getRolloutGroupsTotal() {
return rolloutGroupsTotal;
}
public void setRolloutGroupsTotal(final int rolloutGroupsTotal) {
this.rolloutGroupsTotal = rolloutGroupsTotal;
}
@Override
public int getRolloutGroupsCreated() {
return rolloutGroupsCreated;
}
public void setRolloutGroupsCreated(final int rolloutGroupsCreated) {
this.rolloutGroupsCreated = rolloutGroupsCreated;
}
@Override
public TotalTargetCountStatus getTotalTargetCountStatus() {
if (totalTargetCountStatus == null) {
totalTargetCountStatus = new TotalTargetCountStatus(totalTargets);
}
return totalTargetCountStatus;
}
public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) {
this.totalTargetCountStatus = totalTargetCountStatus;
}
@Override
public String toString() {
return "Rollout [rolloutGroups=" + rolloutGroups + ", targetFilterQuery=" + targetFilterQuery
+ ", distributionSet=" + distributionSet + ", status=" + status + ", lastCheck=" + lastCheck
+ ", getName()=" + getName() + ", getId()=" + getId() + "]";
}
@Override
public void fireCreateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) {
}
@Override
public void fireUpdateEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus().
post(new RolloutPropertyChangeEvent(jpaRollout, EntityPropertyChangeHelper.getChangeSet(
Rollout.class, descriptorEvent))));
}
@Override
public void fireDeleteEvent(final JpaRollout jpaRollout, final DescriptorEvent descriptorEvent) {
}
}

View File

@@ -1,239 +1,261 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
/**
* JPA entity definition of persisting a group of an rollout.
*
*/
@Entity
@Table(name = "sp_rolloutgroup", indexes = {
@Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = {
"name", "rollout", "tenant" }, name = "uk_rolloutgroup"))
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout"))
private JpaRollout rollout;
@Column(name = "status")
private RolloutGroupStatus status = RolloutGroupStatus.READY;
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }, targetEntity = RolloutTargetGroup.class)
@JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false)
private final List<RolloutTargetGroup> rolloutTargetGroup = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
private JpaRolloutGroup parent;
@Column(name = "success_condition", nullable = false)
private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD;
@Column(name = "success_condition_exp", length = 512, nullable = false)
private String successConditionExp;
@Column(name = "success_action", nullable = false)
private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP;
@Column(name = "success_action_exp", length = 512, nullable = false)
private String successActionExp;
@Column(name = "error_condition")
private RolloutGroupErrorCondition errorCondition;
@Column(name = "error_condition_exp", length = 512)
private String errorConditionExp;
@Column(name = "error_action")
private RolloutGroupErrorAction errorAction;
@Column(name = "error_action_exp", length = 512)
private String errorActionExp;
@Column(name = "total_targets")
private long totalTargets;
@Transient
private transient TotalTargetCountStatus totalTargetCountStatus;
@Override
public Rollout getRollout() {
return rollout;
}
@Override
public void setRollout(final Rollout rollout) {
this.rollout = (JpaRollout) rollout;
}
@Override
public RolloutGroupStatus getStatus() {
return status;
}
@Override
public void setStatus(final RolloutGroupStatus status) {
this.status = status;
}
public List<RolloutTargetGroup> getRolloutTargetGroup() {
return rolloutTargetGroup;
}
@Override
public RolloutGroup getParent() {
return parent;
}
public void setParent(final RolloutGroup parent) {
this.parent = (JpaRolloutGroup) parent;
}
@Override
public RolloutGroupSuccessCondition getSuccessCondition() {
return successCondition;
}
@Override
public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) {
successCondition = finishCondition;
}
@Override
public String getSuccessConditionExp() {
return successConditionExp;
}
@Override
public void setSuccessConditionExp(final String finishExp) {
successConditionExp = finishExp;
}
@Override
public RolloutGroupErrorCondition getErrorCondition() {
return errorCondition;
}
@Override
public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) {
this.errorCondition = errorCondition;
}
@Override
public String getErrorConditionExp() {
return errorConditionExp;
}
@Override
public void setErrorConditionExp(final String errorExp) {
errorConditionExp = errorExp;
}
@Override
public RolloutGroupErrorAction getErrorAction() {
return errorAction;
}
@Override
public void setErrorAction(final RolloutGroupErrorAction errorAction) {
this.errorAction = errorAction;
}
@Override
public String getErrorActionExp() {
return errorActionExp;
}
@Override
public void setErrorActionExp(final String errorActionExp) {
this.errorActionExp = errorActionExp;
}
@Override
public RolloutGroupSuccessAction getSuccessAction() {
return successAction;
}
@Override
public String getSuccessActionExp() {
return successActionExp;
}
@Override
public long getTotalTargets() {
return totalTargets;
}
public void setTotalTargets(final long totalTargets) {
this.totalTargets = totalTargets;
}
public void setSuccessAction(final RolloutGroupSuccessAction successAction) {
this.successAction = successAction;
}
public void setSuccessActionExp(final String successActionExp) {
this.successActionExp = successActionExp;
}
/**
* @return the totalTargetCountStatus
*/
@Override
public TotalTargetCountStatus getTotalTargetCountStatus() {
if (totalTargetCountStatus == null) {
totalTargetCountStatus = new TotalTargetCountStatus(totalTargets);
}
return totalTargetCountStatus;
}
/**
* @param totalTargetCountStatus
* the totalTargetCountStatus to set
*/
@Override
public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) {
this.totalTargetCountStatus = totalTargetCountStatus;
}
@Override
public String toString() {
return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup
+ ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp
+ ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName()
+ ", getId()=" + getId() + "]";
}
}
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import org.eclipse.hawkbit.repository.eventbus.event.RolloutGroupPropertyChangeEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityPropertyChangeHelper;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.model.Rollout;
import org.eclipse.hawkbit.repository.model.RolloutGroup;
import org.eclipse.hawkbit.repository.model.TotalTargetCountStatus;
import org.eclipse.persistence.descriptors.DescriptorEvent;
/**
* JPA entity definition of persisting a group of an rollout.
*
*/
@Entity
@Table(name = "sp_rolloutgroup", indexes = {
@Index(name = "sp_idx_rolloutgroup_01", columnList = "tenant,name") }, uniqueConstraints = @UniqueConstraint(columnNames = {
"name", "rollout", "tenant" }, name = "uk_rolloutgroup"))
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGroup,EventAwareEntity<JpaRolloutGroup> {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "rollout", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_rolloutgroup_rollout"))
private JpaRollout rollout;
@Column(name = "status")
private RolloutGroupStatus status = RolloutGroupStatus.READY;
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST }, targetEntity = RolloutTargetGroup.class)
@JoinColumn(name = "rolloutGroup_Id", insertable = false, updatable = false)
private final List<RolloutTargetGroup> rolloutTargetGroup = new ArrayList<>();
@ManyToOne(fetch = FetchType.LAZY)
private JpaRolloutGroup parent;
@Column(name = "success_condition", nullable = false)
private RolloutGroupSuccessCondition successCondition = RolloutGroupSuccessCondition.THRESHOLD;
@Column(name = "success_condition_exp", length = 512, nullable = false)
private String successConditionExp;
@Column(name = "success_action", nullable = false)
private RolloutGroupSuccessAction successAction = RolloutGroupSuccessAction.NEXTGROUP;
@Column(name = "success_action_exp", length = 512, nullable = false)
private String successActionExp;
@Column(name = "error_condition")
private RolloutGroupErrorCondition errorCondition;
@Column(name = "error_condition_exp", length = 512)
private String errorConditionExp;
@Column(name = "error_action")
private RolloutGroupErrorAction errorAction;
@Column(name = "error_action_exp", length = 512)
private String errorActionExp;
@Column(name = "total_targets")
private long totalTargets;
@Transient
private transient TotalTargetCountStatus totalTargetCountStatus;
@Override
public Rollout getRollout() {
return rollout;
}
@Override
public void setRollout(final Rollout rollout) {
this.rollout = (JpaRollout) rollout;
}
@Override
public RolloutGroupStatus getStatus() {
return status;
}
@Override
public void setStatus(final RolloutGroupStatus status) {
this.status = status;
}
public List<RolloutTargetGroup> getRolloutTargetGroup() {
return rolloutTargetGroup;
}
@Override
public RolloutGroup getParent() {
return parent;
}
public void setParent(final RolloutGroup parent) {
this.parent = (JpaRolloutGroup) parent;
}
@Override
public RolloutGroupSuccessCondition getSuccessCondition() {
return successCondition;
}
@Override
public void setSuccessCondition(final RolloutGroupSuccessCondition finishCondition) {
successCondition = finishCondition;
}
@Override
public String getSuccessConditionExp() {
return successConditionExp;
}
@Override
public void setSuccessConditionExp(final String finishExp) {
successConditionExp = finishExp;
}
@Override
public RolloutGroupErrorCondition getErrorCondition() {
return errorCondition;
}
@Override
public void setErrorCondition(final RolloutGroupErrorCondition errorCondition) {
this.errorCondition = errorCondition;
}
@Override
public String getErrorConditionExp() {
return errorConditionExp;
}
@Override
public void setErrorConditionExp(final String errorExp) {
errorConditionExp = errorExp;
}
@Override
public RolloutGroupErrorAction getErrorAction() {
return errorAction;
}
@Override
public void setErrorAction(final RolloutGroupErrorAction errorAction) {
this.errorAction = errorAction;
}
@Override
public String getErrorActionExp() {
return errorActionExp;
}
@Override
public void setErrorActionExp(final String errorActionExp) {
this.errorActionExp = errorActionExp;
}
@Override
public RolloutGroupSuccessAction getSuccessAction() {
return successAction;
}
@Override
public String getSuccessActionExp() {
return successActionExp;
}
@Override
public long getTotalTargets() {
return totalTargets;
}
public void setTotalTargets(final long totalTargets) {
this.totalTargets = totalTargets;
}
public void setSuccessAction(final RolloutGroupSuccessAction successAction) {
this.successAction = successAction;
}
public void setSuccessActionExp(final String successActionExp) {
this.successActionExp = successActionExp;
}
/**
* @return the totalTargetCountStatus
*/
@Override
public TotalTargetCountStatus getTotalTargetCountStatus() {
if (totalTargetCountStatus == null) {
totalTargetCountStatus = new TotalTargetCountStatus(totalTargets);
}
return totalTargetCountStatus;
}
/**
* @param totalTargetCountStatus
* the totalTargetCountStatus to set
*/
@Override
public void setTotalTargetCountStatus(final TotalTargetCountStatus totalTargetCountStatus) {
this.totalTargetCountStatus = totalTargetCountStatus;
}
@Override
public String toString() {
return "RolloutGroup [rollout=" + rollout + ", status=" + status + ", rolloutTargetGroup=" + rolloutTargetGroup
+ ", parent=" + parent + ", finishCondition=" + successCondition + ", finishExp=" + successConditionExp
+ ", errorCondition=" + errorCondition + ", errorExp=" + errorConditionExp + ", getName()=" + getName()
+ ", getId()=" + getId() + "]";
}
@Override
public void fireCreateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) {
}
@Override
public void fireUpdateEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit(() -> EventBusHolder.getInstance().getEventBus().
post(new RolloutGroupPropertyChangeEvent(jpaRolloutGroup,
EntityPropertyChangeHelper.getChangeSet(RolloutGroup.class, descriptorEvent))));
}
@Override
public void fireDeleteEvent(final JpaRolloutGroup jpaRolloutGroup, final DescriptorEvent descriptorEvent) {
}
}

View File

@@ -1,234 +1,257 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityChecker;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.springframework.data.domain.Persistable;
/**
* JPA implementation of {@link Target}.
*
*/
@Entity
@Table(name = "sp_target", indexes = {
@Index(name = "sp_idx_target_01", columnList = "tenant,name,assigned_distribution_set"),
@Index(name = "sp_idx_target_02", columnList = "tenant,name"),
@Index(name = "sp_idx_target_03", columnList = "tenant,controller_id,assigned_distribution_set"),
@Index(name = "sp_idx_target_04", columnList = "tenant,created_at"),
@Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = {
"controller_id", "tenant" }, name = "uk_tenant_controller_id"))
@NamedEntityGraph(name = "Target.detail", attributeNodes = { @NamedAttributeNode("tags"),
@NamedAttributeNode(value = "assignedDistributionSet"), @NamedAttributeNode(value = "targetInfo") })
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Long>, Target {
private static final long serialVersionUID = 1L;
@Column(name = "controller_id", length = 64)
@Size(min = 1)
@NotNull
private String controllerId;
@Transient
private boolean entityNew;
@ManyToMany(targetEntity = JpaTargetTag.class)
@JoinTable(name = "sp_target_target_tag", joinColumns = {
@JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_target")) }, inverseJoinColumns = {
@JoinColumn(name = "tag", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_tag")) })
private Set<TargetTag> tags = new HashSet<>();
@CascadeOnDelete
@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = {
CascadeType.REMOVE }, targetEntity = JpaAction.class)
@JoinColumn(name = "target", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_act_hist_targ"))
private final List<Action> actions = new ArrayList<>();
@ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = JpaDistributionSet.class)
@JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds"))
private JpaDistributionSet assignedDistributionSet;
@CascadeOnDelete
@OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = JpaTargetInfo.class)
@PrimaryKeyJoinColumn
private JpaTargetInfo targetInfo;
/**
* the security token of the target which allows if enabled to authenticate
* with this security token.
*/
@Column(name = "sec_token", insertable = true, updatable = true, nullable = false, length = 128)
private String securityToken;
@CascadeOnDelete
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE, CascadeType.PERSIST })
@JoinColumn(name = "target_Id", insertable = false, updatable = false)
private final List<RolloutTargetGroup> rolloutTargetGroup = new ArrayList<>();
/**
* Constructor.
*
* @param controllerId
* controller ID of the {@link Target}
*/
public JpaTarget(final String controllerId) {
this(controllerId, SecurityTokenGeneratorHolder.getInstance().generateToken());
}
/**
* Constructor.
*
* @param controllerId
* controller ID of the {@link Target}
* @param securityToken
* for target authentication if enabled
*/
public JpaTarget(final String controllerId, final String securityToken) {
this.controllerId = controllerId;
setName(controllerId);
this.securityToken = securityToken;
targetInfo = new JpaTargetInfo(this);
}
/**
* empty constructor for JPA.
*/
JpaTarget() {
controllerId = null;
securityToken = null;
}
@Override
public DistributionSet getAssignedDistributionSet() {
return assignedDistributionSet;
}
@Override
public String getControllerId() {
return controllerId;
}
@Override
public Set<TargetTag> getTags() {
return tags;
}
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet;
}
public void setControllerId(final String controllerId) {
this.controllerId = controllerId;
}
public void setTags(final Set<TargetTag> tags) {
this.tags = tags;
}
@Override
public List<Action> getActions() {
return actions;
}
@Override
@Transient
public boolean isNew() {
return entityNew;
}
/**
* @param isNew
* the isNew to set
*/
public void setNew(final boolean entityNew) {
this.entityNew = entityNew;
}
/**
* @return the targetInfo
*/
@Override
public TargetInfo getTargetInfo() {
return targetInfo;
}
/**
* @param targetInfo
* the targetInfo to set
*/
public void setTargetInfo(final TargetInfo targetInfo) {
this.targetInfo = (JpaTargetInfo) targetInfo;
}
/**
* @return the securityToken if the current security context contains the
* necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN}
* or the current context is executed as system code, otherwise
* {@code null}.
*/
@Override
public String getSecurityToken() {
if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode()
|| SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) {
return securityToken;
}
return null;
}
/**
* @param securityToken
* the securityToken to set
*/
public void setSecurityToken(final String securityToken) {
this.securityToken = securityToken;
}
@Override
public String toString() {
return "Target [controllerId=" + controllerId + ", getId()=" + getId() + "]";
}
}
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.repository.eventbus.event.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.eventbus.event.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityChecker;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.springframework.data.domain.Persistable;
/**
* JPA implementation of {@link Target}.
*
*/
@Entity
@Table(name = "sp_target", indexes = {
@Index(name = "sp_idx_target_01", columnList = "tenant,name,assigned_distribution_set"),
@Index(name = "sp_idx_target_02", columnList = "tenant,name"),
@Index(name = "sp_idx_target_03", columnList = "tenant,controller_id,assigned_distribution_set"),
@Index(name = "sp_idx_target_04", columnList = "tenant,created_at"),
@Index(name = "sp_idx_target_prim", columnList = "tenant,id") }, uniqueConstraints = @UniqueConstraint(columnNames = {
"controller_id", "tenant" }, name = "uk_tenant_controller_id"))
@NamedEntityGraph(name = "Target.detail", attributeNodes = { @NamedAttributeNode("tags"),
@NamedAttributeNode(value = "assignedDistributionSet"), @NamedAttributeNode(value = "targetInfo") })
// exception squid:S2160 - BaseEntity equals/hashcode is handling correctly for
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Long>, Target, EventAwareEntity<JpaTarget> {
private static final long serialVersionUID = 1L;
@Column(name = "controller_id", length = 64)
@Size(min = 1)
@NotNull
private String controllerId;
@Transient
private boolean entityNew;
@ManyToMany(targetEntity = JpaTargetTag.class)
@JoinTable(name = "sp_target_target_tag", joinColumns = {
@JoinColumn(name = "target", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_target")) }, inverseJoinColumns = {
@JoinColumn(name = "tag", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_targtag_tag")) })
private Set<TargetTag> tags = new HashSet<>();
@CascadeOnDelete
@OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = {
CascadeType.REMOVE }, targetEntity = JpaAction.class)
@JoinColumn(name = "target", insertable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_act_hist_targ"))
private final List<Action> actions = new ArrayList<>();
@ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = JpaDistributionSet.class)
@JoinColumn(name = "assigned_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_assign_ds"))
private JpaDistributionSet assignedDistributionSet;
@CascadeOnDelete
@OneToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, targetEntity = JpaTargetInfo.class)
@PrimaryKeyJoinColumn
private JpaTargetInfo targetInfo;
/**
* the security token of the target which allows if enabled to authenticate
* with this security token.
*/
@Column(name = "sec_token", insertable = true, updatable = true, nullable = false, length = 128)
private String securityToken;
@CascadeOnDelete
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE, CascadeType.PERSIST })
@JoinColumn(name = "target_Id", insertable = false, updatable = false)
private final List<RolloutTargetGroup> rolloutTargetGroup = new ArrayList<>();
/**
* Constructor.
*
* @param controllerId
* controller ID of the {@link Target}
*/
public JpaTarget(final String controllerId) {
this(controllerId, SecurityTokenGeneratorHolder.getInstance().generateToken());
}
/**
* Constructor.
*
* @param controllerId
* controller ID of the {@link Target}
* @param securityToken
* for target authentication if enabled
*/
public JpaTarget(final String controllerId, final String securityToken) {
this.controllerId = controllerId;
setName(controllerId);
this.securityToken = securityToken;
targetInfo = new JpaTargetInfo(this);
}
/**
* empty constructor for JPA.
*/
JpaTarget() {
controllerId = null;
securityToken = null;
}
@Override
public DistributionSet getAssignedDistributionSet() {
return assignedDistributionSet;
}
@Override
public String getControllerId() {
return controllerId;
}
@Override
public Set<TargetTag> getTags() {
return tags;
}
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
this.assignedDistributionSet = (JpaDistributionSet) assignedDistributionSet;
}
public void setControllerId(final String controllerId) {
this.controllerId = controllerId;
}
public void setTags(final Set<TargetTag> tags) {
this.tags = tags;
}
@Override
public List<Action> getActions() {
return actions;
}
@Override
@Transient
public boolean isNew() {
return entityNew;
}
/**
* @param isNew
* the isNew to set
*/
public void setNew(final boolean entityNew) {
this.entityNew = entityNew;
}
/**
* @return the targetInfo
*/
@Override
public TargetInfo getTargetInfo() {
return targetInfo;
}
/**
* @param targetInfo
* the targetInfo to set
*/
public void setTargetInfo(final TargetInfo targetInfo) {
this.targetInfo = (JpaTargetInfo) targetInfo;
}
/**
* @return the securityToken if the current security context contains the
* necessary permission {@link SpPermission#READ_TARGET_SEC_TOKEN}
* or the current context is executed as system code, otherwise
* {@code null}.
*/
@Override
public String getSecurityToken() {
if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode()
|| SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) {
return securityToken;
}
return null;
}
/**
* @param securityToken
* the securityToken to set
*/
@Override
public void setSecurityToken(final String securityToken) {
this.securityToken = securityToken;
}
@Override
public String toString() {
return "Target [controllerId=" + controllerId + ", getId()=" + getId() + "]";
}
@Override
public void fireCreateEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () ->EventBusHolder.getInstance().getEventBus().post(new TargetCreatedEvent(jpaTarget)));
}
@Override
public void fireUpdateEvent(final JpaTarget jpaTarget,final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetUpdatedEvent(jpaTarget)));
}
@Override
public void fireDeleteEvent(final JpaTarget jpaTarget, final DescriptorEvent descriptorEvent) {
}
}

View File

@@ -1,324 +1,344 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.MapsId;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Persistable;
/**
* A table which contains all the information inserted, updated by the
* controller itself. So this entity does not provide audit information because
* changes on this entity are mostly only done by controller requests. That's
* the reason that we store these information in a separated table so we don't
* modifying the {@link Target} itself when a controller reports it's
* {@link #lastTargetQuery} for example.
*
*/
@Table(name = "sp_target_info", indexes = {
@Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") })
@Entity
public class JpaTargetInfo implements Persistable<Long>, TargetInfo {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class);
@Id
private Long targetId;
@Transient
private boolean entityNew;
@CascadeOnDelete
@OneToOne(cascade = { CascadeType.MERGE,
CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = JpaTarget.class)
@JoinColumn(name = "target_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_stat_targ"))
@MapsId
private JpaTarget target;
@Column(name = "address", length = 512)
private String address;
@Column(name = "last_target_query")
private Long lastTargetQuery;
@Column(name = "install_date")
private Long installationDate;
@Column(name = "update_status", nullable = false, length = 255)
@Enumerated(EnumType.STRING)
private TargetUpdateStatus updateStatus = TargetUpdateStatus.UNKNOWN;
@ManyToOne(optional = true, fetch = FetchType.LAZY)
@JoinColumn(name = "installed_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds"))
private JpaDistributionSet installedDistributionSet;
/**
* Read only on management API. Are commited by controller.
*/
@ElementCollection
@Column(name = "attribute_value", length = 128)
@MapKeyColumn(name = "attribute_key", nullable = false, length = 32)
@CollectionTable(name = "sp_target_attributes", joinColumns = {
@JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
private final Map<String, String> controllerAttributes = Collections.synchronizedMap(new HashMap<String, String>());
// set default request controller attributes to true, because we want to
// request them the first
// time
@Column(name = "request_controller_attributes", nullable = false)
private boolean requestControllerAttributes = true;
/**
* Constructor for {@link TargetStatus}.
*
* @param target
* related to this status.
*/
public JpaTargetInfo(final JpaTarget target) {
this.target = target;
targetId = target.getId();
}
JpaTargetInfo() {
target = null;
targetId = null;
}
@Override
public Long getId() {
return targetId;
}
@Override
@Transient
public boolean isNew() {
return entityNew;
}
/**
* @param isNew
* the isNew to set
*/
public void setNew(final boolean entityNew) {
this.entityNew = entityNew;
}
/**
* @return the ipAddress
*/
@Override
public URI getAddress() {
if (address == null) {
return null;
}
try {
return URI.create(address);
} catch (final IllegalArgumentException e) {
LOG.warn("Invalid address provided. Cloud not be configured to URI", e);
return null;
}
}
/**
* @param address
* the target address to set
*
* @throws IllegalArgumentException
* If the given string violates RFC&nbsp;2396
*/
@Override
public void setAddress(final String address) {
// check if this is a real URI
if (address != null) {
try {
URI.create(address);
} catch (final IllegalArgumentException e) {
throw new InvalidTargetAddressException(
"The given address " + address + " violates the RFC-2396 specification", e);
}
}
this.address = address;
}
public Long getTargetId() {
return targetId;
}
public void setTargetId(final Long targetId) {
this.targetId = targetId;
}
@Override
public Target getTarget() {
return target;
}
public void setTarget(final JpaTarget target) {
this.target = target;
}
@Override
public Long getLastTargetQuery() {
return lastTargetQuery;
}
public void setLastTargetQuery(final Long lastTargetQuery) {
this.lastTargetQuery = lastTargetQuery;
}
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
this.requestControllerAttributes = requestControllerAttributes;
}
@Override
public Map<String, String> getControllerAttributes() {
return controllerAttributes;
}
@Override
public boolean isRequestControllerAttributes() {
return requestControllerAttributes;
}
@Override
public Long getInstallationDate() {
return installationDate;
}
public void setInstallationDate(final Long installationDate) {
this.installationDate = installationDate;
}
@Override
public TargetUpdateStatus getUpdateStatus() {
return updateStatus;
}
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
this.updateStatus = updateStatus;
}
@Override
public DistributionSet getInstalledDistributionSet() {
return installedDistributionSet;
}
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
this.installedDistributionSet = installedDistributionSet;
}
/**
* @return the poll time which holds the last poll time of the target, the
* next poll time and the overdue time. In case the
* {@link #lastTargetQuery} is not set e.g. the target never polled
* before this method returns {@code null}
*/
@Override
public PollStatus getPollStatus() {
if (lastTargetQuery == null) {
return null;
}
return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> {
final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder
.getInstance().getTenantConfigurationManagement()
.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue());
final Duration overdueTime = DurationHelper.formattedStringToDuration(
TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement()
.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)
.getValue());
final LocalDateTime currentDate = LocalDateTime.now();
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
ZoneId.systemDefault());
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
});
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((target == null) ? 0 : target.hashCode());
result = prime * result + ((targetId == null) ? 0 : targetId.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof TargetInfo)) {
return false;
}
final JpaTargetInfo other = (JpaTargetInfo) obj;
if (target == null) {
if (other.target != null) {
return false;
}
} else if (!target.equals(other.target)) {
return false;
}
if (targetId == null) {
if (other.targetId != null) {
return false;
}
} else if (!targetId.equals(other.targetId)) {
return false;
}
return true;
}
}
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapKeyColumn;
import javax.persistence.MapsId;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.eclipse.hawkbit.repository.eventbus.event.TargetInfoUpdateEvent;
import org.eclipse.hawkbit.repository.exception.InvalidTargetAddressException;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EventBusHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.PollStatus;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetInfo;
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Persistable;
/**
* A table which contains all the information inserted, updated by the
* controller itself. So this entity does not provide audit information because
* changes on this entity are mostly only done by controller requests. That's
* the reason that we store these information in a separated table so we don't
* modifying the {@link Target} itself when a controller reports it's
* {@link #lastTargetQuery} for example.
*
*/
@Table(name = "sp_target_info", indexes = {
@Index(name = "sp_idx_target_info_02", columnList = "target_id,update_status") })
@Entity
@EntityListeners(EntityPropertyChangeListener.class)
public class JpaTargetInfo implements Persistable<Long>, TargetInfo, EventAwareEntity<JpaTargetInfo> {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(TargetInfo.class);
@Id
private Long targetId;
@Transient
private boolean entityNew;
@CascadeOnDelete
@OneToOne(cascade = { CascadeType.MERGE,
CascadeType.REMOVE }, fetch = FetchType.LAZY, targetEntity = JpaTarget.class)
@JoinColumn(name = "target_id", nullable = false, updatable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_stat_targ"))
@MapsId
private JpaTarget target;
@Column(name = "address", length = 512)
private String address;
@Column(name = "last_target_query")
private Long lastTargetQuery;
@Column(name = "install_date")
private Long installationDate;
@Column(name = "update_status", nullable = false, length = 255)
@Enumerated(EnumType.STRING)
private TargetUpdateStatus updateStatus = TargetUpdateStatus.UNKNOWN;
@ManyToOne(optional = true, fetch = FetchType.LAZY)
@JoinColumn(name = "installed_distribution_set", nullable = true, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_target_inst_ds"))
private JpaDistributionSet installedDistributionSet;
/**
* Read only on management API. Are commited by controller.
*/
@ElementCollection
@Column(name = "attribute_value", length = 128)
@MapKeyColumn(name = "attribute_key", nullable = false, length = 32)
@CollectionTable(name = "sp_target_attributes", joinColumns = {
@JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
private final Map<String, String> controllerAttributes = Collections.synchronizedMap(new HashMap<String, String>());
// set default request controller attributes to true, because we want to
// request them the first
// time
@Column(name = "request_controller_attributes", nullable = false)
private boolean requestControllerAttributes = true;
/**
* Constructor for {@link TargetStatus}.
*
* @param target
* related to this status.
*/
public JpaTargetInfo(final JpaTarget target) {
this.target = target;
targetId = target.getId();
}
JpaTargetInfo() {
target = null;
targetId = null;
}
@Override
public Long getId() {
return targetId;
}
@Override
@Transient
public boolean isNew() {
return entityNew;
}
/**
* @param isNew
* the isNew to set
*/
public void setNew(final boolean entityNew) {
this.entityNew = entityNew;
}
/**
* @return the ipAddress
*/
@Override
public URI getAddress() {
if (address == null) {
return null;
}
try {
return URI.create(address);
} catch (final IllegalArgumentException e) {
LOG.warn("Invalid address provided. Cloud not be configured to URI", e);
return null;
}
}
/**
* @param address
* the target address to set
*
* @throws IllegalArgumentException
* If the given string violates RFC&nbsp;2396
*/
@Override
public void setAddress(final String address) {
// check if this is a real URI
if (address != null) {
try {
URI.create(address);
} catch (final IllegalArgumentException e) {
throw new InvalidTargetAddressException(
"The given address " + address + " violates the RFC-2396 specification", e);
}
}
this.address = address;
}
public Long getTargetId() {
return targetId;
}
public void setTargetId(final Long targetId) {
this.targetId = targetId;
}
@Override
public Target getTarget() {
return target;
}
public void setTarget(final JpaTarget target) {
this.target = target;
}
@Override
public Long getLastTargetQuery() {
return lastTargetQuery;
}
public void setLastTargetQuery(final Long lastTargetQuery) {
this.lastTargetQuery = lastTargetQuery;
}
public void setRequestControllerAttributes(final boolean requestControllerAttributes) {
this.requestControllerAttributes = requestControllerAttributes;
}
@Override
public Map<String, String> getControllerAttributes() {
return controllerAttributes;
}
@Override
public boolean isRequestControllerAttributes() {
return requestControllerAttributes;
}
@Override
public Long getInstallationDate() {
return installationDate;
}
public void setInstallationDate(final Long installationDate) {
this.installationDate = installationDate;
}
@Override
public TargetUpdateStatus getUpdateStatus() {
return updateStatus;
}
public void setUpdateStatus(final TargetUpdateStatus updateStatus) {
this.updateStatus = updateStatus;
}
@Override
public DistributionSet getInstalledDistributionSet() {
return installedDistributionSet;
}
public void setInstalledDistributionSet(final JpaDistributionSet installedDistributionSet) {
this.installedDistributionSet = installedDistributionSet;
}
/**
* @return the poll time which holds the last poll time of the target, the
* next poll time and the overdue time. In case the
* {@link #lastTargetQuery} is not set e.g. the target never polled
* before this method returns {@code null}
*/
@Override
public PollStatus getPollStatus() {
if (lastTargetQuery == null) {
return null;
}
return SystemSecurityContextHolder.getInstance().getSystemSecurityContext().runAsSystem(() -> {
final Duration pollTime = DurationHelper.formattedStringToDuration(TenantConfigurationManagementHolder
.getInstance().getTenantConfigurationManagement()
.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue());
final Duration overdueTime = DurationHelper.formattedStringToDuration(
TenantConfigurationManagementHolder.getInstance().getTenantConfigurationManagement()
.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)
.getValue());
final LocalDateTime currentDate = LocalDateTime.now();
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
ZoneId.systemDefault());
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
});
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((target == null) ? 0 : target.hashCode());
result = prime * result + ((targetId == null) ? 0 : targetId.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof TargetInfo)) {
return false;
}
final JpaTargetInfo other = (JpaTargetInfo) obj;
if (target == null) {
if (other.target != null) {
return false;
}
} else if (!target.equals(other.target)) {
return false;
}
if (targetId == null) {
if (other.targetId != null) {
return false;
}
} else if (!targetId.equals(other.targetId)) {
return false;
}
return true;
}
@Override
public void fireCreateEvent(final JpaTargetInfo jpaTargetInfo,final DescriptorEvent descriptorEvent) {
// there is no target info created event
}
@Override
public void fireUpdateEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) {
AfterTransactionCommitExecutorHolder.getInstance().getAfterCommit().afterCommit( () -> EventBusHolder.getInstance().getEventBus().post(new TargetInfoUpdateEvent(jpaTargetInfo)));
}
@Override
public void fireDeleteEvent(final JpaTargetInfo jpaTargetInfo, final DescriptorEvent descriptorEvent) {
}
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model.helper;
import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.eventbus.event.AbstractPropertyChangeEvent;
import org.eclipse.hawkbit.repository.model.TenantAwareBaseEntity;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
import org.eclipse.persistence.queries.UpdateObjectQuery;
import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord;
public class EntityPropertyChangeHelper<T extends TenantAwareBaseEntity> {
public static <T extends TenantAwareBaseEntity> Map<String, AbstractPropertyChangeEvent<T>.Values> getChangeSet(
final Class<T> clazz, final DescriptorEvent event) {
final T rolloutGroup = clazz.cast(event.getObject());
final ObjectChangeSet changeSet = ((UpdateObjectQuery) event.getQuery())
.getObjectChangeSet();
return changeSet
.getChanges()
.stream()
.filter(record -> record instanceof DirectToFieldChangeRecord)
.map(record -> (DirectToFieldChangeRecord) record)
.collect(
Collectors.toMap(
record -> record.getAttribute(),
record -> new AbstractPropertyChangeEvent<T>(
rolloutGroup, null).new Values(record
.getOldValue(), record.getNewValue())));
}
}