package rocks.inspectit.server.ci.event;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.context.ApplicationEvent;
import rocks.inspectit.server.util.CollectionSubtractUtils;
import rocks.inspectit.shared.cs.ci.Environment;
import rocks.inspectit.shared.cs.ci.Profile;
import rocks.inspectit.shared.cs.ci.assignment.AbstractClassSensorAssignment;
import rocks.inspectit.shared.cs.ci.assignment.impl.SpecialMethodSensorAssignment;
import rocks.inspectit.shared.cs.ci.factory.SpecialMethodSensorAssignmentFactory;
import rocks.inspectit.shared.cs.ci.profile.data.AbstractProfileData;
import rocks.inspectit.shared.cs.ci.profile.data.SensorAssignmentProfileData;
/**
* Event that signals that an {@link Environment} has been updated via CI.
*
* @author Ivan Senic
*
*/
public class EnvironmentUpdateEvent extends ApplicationEvent {
/**
* Generated UID.
*/
private static final long serialVersionUID = 5572925794275714352L;
/**
* Environment before updating.
*/
private final Environment before;
/**
* Environment after updating.
*/
private final Environment after;
/**
* New profiles bounded to the updated environment.
*/
private final Collection<Profile> addedProfiles;
/**
* Removed profiles from the updated environment.
*/
private final Collection<Profile> removedProfiles;
/**
* Default constructor.
*
* @param source
* the component that published the event (never {@code null})
* @param before
* Environment before updating.
* @param after
* Environment after updated.
* @param addedProfiles
* New profiles bounded to the updated environment.
* @param removedProfiles
* Removed profiles from the updated environment.
*/
public EnvironmentUpdateEvent(Object source, Environment before, Environment after, Collection<Profile> addedProfiles, Collection<Profile> removedProfiles) {
super(source);
// check null
if ((null == before) || (null == after)) {
throw new IllegalArgumentException("Environment references must not be null.");
}
// check same id
if (!Objects.equals(before.getId(), after.getId())) {
throw new IllegalArgumentException("Before and after environment references must have same environment id.");
}
this.before = before;
this.after = after;
this.addedProfiles = addedProfiles;
this.removedProfiles = removedProfiles;
}
/**
* Returns id of the environment being updated.
*
* @return Returns id of the environment being updated.
*/
public String getEnvironmentId() {
return after.getId();
}
/**
* Returns all {@link AbstractClassSensorAssignment} that are contained in the removed profiles.
* Only active profiles are taken into account. Also includes the functional assignments that
* might be removed as the result of changes in the environment.
*
* @param functionalAssignmentFactory
* SpecialMethodSensorAssignmentFactory for resolving functional assignment updates.
*
* @return Returns all {@link AbstractClassSensorAssignment} that are "removed".
*/
public Collection<AbstractClassSensorAssignment<?>> getRemovedSensorAssignments(SpecialMethodSensorAssignmentFactory functionalAssignmentFactory) {
Collection<AbstractClassSensorAssignment<?>> removedAssignments = getSensorAssignments(removedProfiles);
removedAssignments.addAll(getFunctionalAssignmentsDifference(functionalAssignmentFactory, before, after));
return removedAssignments;
}
/**
* Returns all {@link AbstractClassSensorAssignment} that are contained in the added profiles.
* Only active profiles are taken into account. Also includes the functional assignments that
* might be added as the result of changes in the environment.
*
* @param functionalAssignmentFactory
* SpecialMethodSensorAssignmentFactory for resolving functional assignment updates.
*
* @return Returns all {@link AbstractClassSensorAssignment} that are "added".
*/
public Collection<AbstractClassSensorAssignment<?>> getAddedSensorAssignments(SpecialMethodSensorAssignmentFactory functionalAssignmentFactory) {
Collection<AbstractClassSensorAssignment<?>> addedAssignments = getSensorAssignments(addedProfiles);
addedAssignments.addAll(getFunctionalAssignmentsDifference(functionalAssignmentFactory, after, before));
return addedAssignments;
}
/**
* Collects all {@link AbstractClassSensorAssignment}s from the given profiles. If profile is
* not active assignments from that profile will not be included.
*
* @param profiles
* Collection of profiles.
* @return All {@link AbstractClassSensorAssignment}s from active profiles.
*/
private Collection<AbstractClassSensorAssignment<?>> getSensorAssignments(Collection<Profile> profiles) {
Collection<AbstractClassSensorAssignment<?>> assignments = new ArrayList<>();
if (CollectionUtils.isNotEmpty(profiles)) {
for (Profile profile : profiles) {
if (profile.isActive()) {
AbstractProfileData<?> profileData = profile.getProfileData();
if (profileData.isOfType(SensorAssignmentProfileData.class)) {
List<? extends AbstractClassSensorAssignment<?>> data = profileData.getData(SensorAssignmentProfileData.class);
if (CollectionUtils.isNotEmpty(data)) {
assignments.addAll(data);
}
}
}
}
}
return assignments;
}
/**
* Returns the difference from the Functional assignments for the two environments. The
* resulting collection will include the assignments that exist in first environment and do not
* exist in the second environment.
*
* @param factory
* {@link SpecialMethodSensorAssignmentFactory} for resolving assignments
* @param e1
* First environment
* @param e2
* Second environment
* @return Functional assignments that are contained in the first environment, but not in
* second.
*/
private Collection<? extends AbstractClassSensorAssignment<?>> getFunctionalAssignmentsDifference(SpecialMethodSensorAssignmentFactory factory, Environment e1, Environment e2) {
Collection<SpecialMethodSensorAssignment> functionalAssignments1 = factory.getSpecialAssignments(e1);
Collection<SpecialMethodSensorAssignment> functionalAssignments2 = factory.getSpecialAssignments(e2);
return CollectionSubtractUtils.subtractSafe(functionalAssignments1, functionalAssignments2);
}
/**
* Gets {@link #after}.
*
* @return {@link #after}
*/
public Environment getAfter() {
return after;
}
/**
* Gets {@link #addedProfiles}.
*
* @return {@link #addedProfiles}
*/
public Collection<Profile> getAddedProfiles() {
return addedProfiles;
}
/**
* Gets {@link #removedProfiles}.
*
* @return {@link #removedProfiles}
*/
public Collection<Profile> getRemovedProfiles() {
return removedProfiles;
}
}