Merge branch 'master' into feature_auto_assignment_squashed

This commit is contained in:
Dominik Herbst
2016-10-07 14:57:11 +02:00
211 changed files with 5164 additions and 2794 deletions

View File

@@ -208,15 +208,16 @@ public interface ArtifactManagement {
void deleteLocalArtifact(@NotNull Long id);
/**
* Searches for {@link Artifact} with given {@link Identifiable}.
* Searches for {@link LocalArtifact} with given {@link Identifiable}.
*
* @param id
* to search for
* @return found {@link Artifact} or <code>null</code> is it could not be
* found.
* @return found {@link LocalArtifact} or <code>null</code> is it could not
* be found.
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
Artifact findArtifact(@NotNull Long id);
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.IS_CONTROLLER)
LocalArtifact findLocalArtifact(@NotNull Long id);
/**
* Find by artifact by software module id and filename.

View File

@@ -183,22 +183,6 @@ public interface ControllerManagement {
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
String getPollingTime();
/**
* An direct access to the security token of an
* {@link Target#getSecurityToken()} without authorization. This is
* necessary to be able to access the security-token without any
* security-context information because the security-token is used for
* authentication.
*
* @param controllerId
* the ID of the controller to retrieve the security token for
* @return the security context of the target, in case no target exists for
* the given controllerId {@code null} is returned
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET_SEC_TOKEN)
String getSecurityTokenByControllerId(@NotEmpty String controllerId);
/**
* Checks if a given target has currently or has even been assigned to the
* given artifact through the action history list. This can e.g. indicate if
@@ -218,6 +202,25 @@ public interface ControllerManagement {
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
boolean hasTargetArtifactAssigned(@NotNull String controllerId, @NotNull LocalArtifact localArtifact);
/**
* Checks if a given target has currently or has even been assigned to the
* given artifact through the action history list. This can e.g. indicate if
* a target is allowed to download a given artifact because it has currently
* assigned or had ever been assigned to the target and so it's visible to a
* specific target e.g. for downloading.
*
* @param targetId
* the ID of the target to check
* @param localArtifact
* the artifact to verify if the given target had even been
* assigned to
* @return {@code true} if the given target has currently or had ever a
* relation to the given artifact through the action history,
* otherwise {@code false}
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
boolean hasTargetArtifactAssigned(@NotNull Long targetId, @NotNull LocalArtifact localArtifact);
/**
* Registers retrieved status for given {@link Target} and {@link Action} if
* it does not exist yet.
@@ -300,4 +303,32 @@ public interface ControllerManagement {
TargetInfo updateTargetStatus(@NotNull TargetInfo targetInfo, TargetUpdateStatus status, Long lastTargetQuery,
URI address);
/**
* Finds {@link Target} based on given controller ID returns found Target
* without details, i.e. NO {@link Target#getTags()} and
* {@link Target#getActions()} possible.
*
* @param controllerId
* to look for.
* @return {@link Target} or {@code null} if it does not exist
* @see Target#getControllerId()
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.IS_SYSTEM_CODE)
Target findByControllerId(@NotEmpty final String controllerId);
/**
* Finds {@link Target} based on given ID returns found Target without
* details, i.e. NO {@link Target#getTags()} and {@link Target#getActions()}
* possible.
*
* @param targetId
* to look for.
* @return {@link Target} or {@code null} if it does not exist
* @see Target#getId()
*/
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.IS_SYSTEM_CODE)
Target findByTargetId(final long targetId);
}

View File

@@ -57,7 +57,11 @@ public class DistributionSetAssignmentResult extends AssignmentResult<Target> {
* @return the actionIds
*/
public List<Long> getActions() {
return actions;
if (actions == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(actions);
}
@Override

View File

@@ -205,8 +205,10 @@ public interface DistributionSetManagement {
/**
* deletes a distribution set meta data entry.
*
* @param id
* the ID of the distribution set meta data to delete
* @param distributionSet
* where meta data has to be deleted
* @param key
* of the meta data element
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
void deleteDistributionSetMetadata(@NotNull final DistributionSet distributionSet, @NotNull final String key);
@@ -429,7 +431,7 @@ public interface DistributionSetManagement {
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
DistributionSetType findDistributionSetTypeByKey(@NotNull String key);
DistributionSetType findDistributionSetTypeByKey(@NotEmpty String key);
/**
* @param name
@@ -469,15 +471,16 @@ public interface DistributionSetManagement {
/**
* finds a single distribution set meta data by its id.
*
* @param id
* the id of the distribution set meta data containing the meta
* data key and the ID of the distribution set
* @param distributionSet
* where meta data has to rind
* @param key
* of the meta data element
* @return the found DistributionSetMetadata or {@code null} if not exits
* @throws EntityNotFoundException
* in case the meta data does not exists for the given key
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotNull String key);
DistributionSetMetadata findOne(@NotNull DistributionSet distributionSet, @NotEmpty String key);
/**
* Checks if a {@link DistributionSet} is currently in use by a target in

View File

@@ -11,6 +11,8 @@ package org.eclipse.hawkbit.repository;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import javax.validation.constraints.NotNull;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.Status;
import org.eclipse.hawkbit.repository.model.ActionStatus;
@@ -64,7 +66,7 @@ public interface EntityFactory {
*
* @return {@link ActionStatus} object
*/
ActionStatus generateActionStatus(Action action, Status status, Long occurredAt);
ActionStatus generateActionStatus(@NotNull Action action, @NotNull Status status, Long occurredAt);
/**
* Generates an {@link ActionStatus} object without persisting it.
@@ -81,7 +83,7 @@ public interface EntityFactory {
*
* @return {@link ActionStatus} object
*/
ActionStatus generateActionStatus(Action action, final Status status, Long occurredAt,
ActionStatus generateActionStatus(@NotNull Action action, @NotNull Status status, Long occurredAt,
final Collection<String> messages);
/**
@@ -99,7 +101,8 @@ public interface EntityFactory {
*
* @return {@link ActionStatus} object
*/
ActionStatus generateActionStatus(Action action, Status status, Long occurredAt, final String message);
ActionStatus generateActionStatus(@NotNull Action action, @NotNull Status status, Long occurredAt,
final String message);
/**
* Generates an empty {@link DistributionSet} without persisting it.
@@ -124,8 +127,8 @@ public interface EntityFactory {
*
* @return {@link DistributionSet} object
*/
DistributionSet generateDistributionSet(String name, String version, String description, DistributionSetType type,
Collection<SoftwareModule> moduleList);
DistributionSet generateDistributionSet(@NotNull String name, @NotNull String version, String description,
@NotNull DistributionSetType type, Collection<SoftwareModule> moduleList);
/**
* Generates an empty {@link DistributionSetMetadata} element without
@@ -148,7 +151,8 @@ public interface EntityFactory {
*
* @return {@link DistributionSetMetadata} object
*/
DistributionSetMetadata generateDistributionSetMetadata(DistributionSet distributionSet, String key, String value);
DistributionSetMetadata generateDistributionSetMetadata(@NotNull DistributionSet distributionSet,
@NotNull String key, String value);
/**
* Generates an empty {@link DistributionSetTag} without persisting it.
@@ -164,7 +168,7 @@ public interface EntityFactory {
* of the tag
* @return {@link DistributionSetTag} object
*/
DistributionSetTag generateDistributionSetTag(String name);
DistributionSetTag generateDistributionSetTag(@NotNull String name);
/**
* Generates a {@link DistributionSetTag} without persisting it.
@@ -177,7 +181,7 @@ public interface EntityFactory {
* of the tag
* @return {@link DistributionSetTag} object
*/
DistributionSetTag generateDistributionSetTag(String name, String description, String colour);
DistributionSetTag generateDistributionSetTag(@NotNull String name, String description, String colour);
/**
* Generates an empty {@link DistributionSetType} without persisting it.
@@ -198,7 +202,7 @@ public interface EntityFactory {
*
* @return {@link DistributionSetType} object
*/
DistributionSetType generateDistributionSetType(String key, String name, String description);
DistributionSetType generateDistributionSetType(@NotNull String key, @NotNull String name, String description);
/**
* Generates an empty {@link Rollout} without persisting it.
@@ -237,8 +241,8 @@ public interface EntityFactory {
*
* @return {@link SoftwareModule} object
*/
SoftwareModule generateSoftwareModule(SoftwareModuleType type, String name, String version, String description,
String vendor);
SoftwareModule generateSoftwareModule(@NotNull SoftwareModuleType type, @NotNull String name,
@NotNull String version, String description, String vendor);
/**
* Generates an empty {@link SoftwareModuleMetadata} pair without persisting
@@ -260,7 +264,8 @@ public interface EntityFactory {
*
* @return {@link SoftwareModuleMetadata} object
*/
SoftwareModuleMetadata generateSoftwareModuleMetadata(SoftwareModule softwareModule, String key, String value);
SoftwareModuleMetadata generateSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key,
String value);
/**
* Generates an empty {@link SoftwareModuleType} without persisting it.
@@ -283,7 +288,8 @@ public interface EntityFactory {
*
* @return {@link SoftwareModuleType} object
*/
SoftwareModuleType generateSoftwareModuleType(String key, String name, String description, int maxAssignments);
SoftwareModuleType generateSoftwareModuleType(@NotNull String key, @NotNull String name, String description,
int maxAssignments);
/**
* Generates an empty {@link Target} without persisting it.
@@ -307,7 +313,7 @@ public interface EntityFactory {
*
* @return {@link Target} object
*/
Target generateTarget(@NotEmpty String controllerID, @NotEmpty String securityToken);
Target generateTarget(@NotEmpty String controllerID, String securityToken);
/**
* Generates an empty {@link TargetFilterQuery} without persisting it.
@@ -354,7 +360,7 @@ public interface EntityFactory {
* of the tag
* @return {@link TargetTag} object
*/
TargetTag generateTargetTag(String name);
TargetTag generateTargetTag(@NotNull String name);
/**
* Generates a {@link TargetTag} without persisting it.
@@ -367,7 +373,7 @@ public interface EntityFactory {
* of the tag
* @return {@link TargetTag} object
*/
TargetTag generateTargetTag(String name, String description, String colour);
TargetTag generateTargetTag(@NotNull String name, String description, String colour);
/**
* Generates an empty {@link LocalArtifact} without persisting it.

View File

@@ -155,11 +155,13 @@ public interface SoftwareManagement {
/**
* deletes a software module meta data entry.
*
* @param id
* the ID of the software module meta data to delete
* @param softwareModule
* where meta data has to be deleted
* @param key
* of the metda data element
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_REPOSITORY)
void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotNull String key);
void deleteSoftwareModuleMetadata(@NotNull SoftwareModule softwareModule, @NotEmpty String key);
/**
* Deletes {@link SoftwareModule}s which is any if the given ids.
@@ -251,9 +253,10 @@ public interface SoftwareManagement {
/**
* finds a single software module meta data by its id.
*
* @param id
* the id of the software module meta data containing the meta
* data key and the ID of the software module
* @param softwareModule
* where meta data has to be found
* @param key
* of the meta data element
* @return the found SoftwareModuleMetadata or {@code null} if not exits
* @throws EntityNotFoundException
* in case the meta data does not exists for the given key
@@ -280,8 +283,8 @@ public interface SoftwareManagement {
*
* @param softwareModuleId
* the software module id to retrieve the meta data from
* @param spec
* the specification to filter the result
* @param rsqlParam
* filter definition in RSQL syntax
* @param pageable
* the page request to page the result
* @return a paged result of all meta data entries for a given software
@@ -346,8 +349,8 @@ public interface SoftwareManagement {
/**
* Retrieves all {@link SoftwareModule}s with a given specification.
*
* @param spec
* the specification to filter the software modules
* @param rsqlParam
* filter definition in RSQL syntax
* @param pageable
* pagination parameter
* @return the found {@link SoftwareModule}s
@@ -392,7 +395,7 @@ public interface SoftwareManagement {
* {@link SoftwareModuleType#getKey()}
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
SoftwareModuleType findSoftwareModuleTypeByKey(@NotNull String key);
SoftwareModuleType findSoftwareModuleTypeByKey(@NotEmpty String key);
/**
*
@@ -415,8 +418,8 @@ public interface SoftwareManagement {
/**
* Retrieves all {@link SoftwareModuleType}s with a given specification.
*
* @param spec
* the specification to filter the software modules types
* @param rsqlParam
* filter definition in RSQL syntax
* @param pageable
* pagination parameter
* @return the found {@link SoftwareModuleType}s

View File

@@ -63,7 +63,8 @@ public interface SystemManagement {
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
+ SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR
+ SpringEvalExpressions.IS_CONTROLLER)
TenantMetaData getTenantMetadata();
/**
@@ -93,4 +94,14 @@ public interface SystemManagement {
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
TenantMetaData updateTenantMetadata(@NotNull TenantMetaData metaData);
/**
* Returns {@link TenantMetaData} of given tenant ID.
*
* @param tenantId
* to retrieve data for
* @return {@link TenantMetaData} of given tenant
*/
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
TenantMetaData getTenantMetadata(@NotNull Long tenantId);
}

View File

@@ -34,6 +34,8 @@ public class RolloutGroupCreatedEvent extends AbstractDistributedEvent {
* the revision of the event
* @param rolloutId
* the ID of the rollout the group has been created
* @param rolloutGroupId
* identifier of this group
* @param totalRolloutGroup
* the total number of rollout groups for this rollout
* @param createdRolloutGroup

View File

@@ -8,11 +8,11 @@
*/
package org.eclipse.hawkbit.repository.eventbus.event;
import java.net.URI;
import java.util.Collection;
import org.eclipse.hawkbit.eventbus.event.DefaultEvent;
import org.eclipse.hawkbit.repository.model.SoftwareModule;
import org.eclipse.hawkbit.repository.model.Target;
/**
* Event that gets sent when a distribution set gets assigned to a target.
@@ -21,10 +21,8 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule;
public class TargetAssignDistributionSetEvent extends DefaultEvent {
private final Collection<SoftwareModule> softwareModules;
private final String controllerId;
private final Target target;
private final Long actionId;
private final URI targetAdress;
private final String targetToken;
/**
* Creates a new {@link TargetAssignDistributionSetEvent}.
@@ -33,26 +31,19 @@ public class TargetAssignDistributionSetEvent extends DefaultEvent {
* the revision of the event
* @param tenant
* the tenant of the event
* @param controllerId
* the ID of the controller
* @param target
* the assigned {@link Target}
* @param actionId
* the action id of the assignment
* @param softwareModules
* the software modules which have been assigned to the target
* @param targetAdress
* the targetAdress of the target
* @param targetToken
* the authentication token of the target
*/
public TargetAssignDistributionSetEvent(final long revision, final String tenant, final String controllerId,
final Long actionId, final Collection<SoftwareModule> softwareModules, final URI targetAdress,
final String targetToken) {
public TargetAssignDistributionSetEvent(final long revision, final String tenant, final Target target,
final Long actionId, final Collection<SoftwareModule> softwareModules) {
super(revision, tenant);
this.controllerId = controllerId;
this.target = target;
this.actionId = actionId;
this.softwareModules = softwareModules;
this.targetAdress = targetAdress;
this.targetToken = targetToken;
}
/**
@@ -63,11 +54,11 @@ public class TargetAssignDistributionSetEvent extends DefaultEvent {
}
/**
* @return the controllerId of the Target which has been assigned to the
* distribution set
* @return the {@link Target} which has been assigned to the distribution
* set
*/
public String getControllerId() {
return controllerId;
public Target getTarget() {
return target;
}
/**
@@ -76,12 +67,4 @@ public class TargetAssignDistributionSetEvent extends DefaultEvent {
public Collection<SoftwareModule> getSoftwareModules() {
return softwareModules;
}
public URI getTargetAdress() {
return targetAdress;
}
public String getTargetToken() {
return targetToken;
}
}

View File

@@ -47,10 +47,10 @@ public interface ActionStatus extends TenantAwareBaseEntity {
* @return current {@link Status#DOWNLOAD} progress if known by the update
* server.
*/
int getDownloadProgressPercent();
short getDownloadProgressPercent();
/**
* @return list of message entries that can be added to the
* @return immutable list of message entries that in the
* {@link ActionStatus}.
*/
List<String> getMessages();

View File

@@ -37,6 +37,6 @@ public interface Artifact extends TenantAwareBaseEntity {
/**
* @return size of the artifact in bytes.
*/
Long getSize();
long getSize();
}

View File

@@ -60,7 +60,7 @@ public class AssignedSoftwareModule implements Serializable {
final int prime = 31;
int result = 1;
result = prime * result + (assigned ? 1231 : 1237);
result = prime * result + (softwareModule == null ? 0 : softwareModule.hashCode());
result = prime * result + ((softwareModule == null) ? 0 : softwareModule.hashCode());
return result;
}
@@ -72,7 +72,7 @@ public class AssignedSoftwareModule implements Serializable {
if (obj == null) {
return false;
}
if (!(obj instanceof AssignedSoftwareModule)) {
if (getClass() != obj.getClass()) {
return false;
}
final AssignedSoftwareModule other = (AssignedSoftwareModule) obj;

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.model;
import java.util.Collections;
import java.util.List;
/**
@@ -82,14 +83,22 @@ public class AssignmentResult<T extends BaseEntity> {
* @return {@link List} of assigned entity.
*/
public List<T> getAssignedEntity() {
return assignedEntity;
if (assignedEntity == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(assignedEntity);
}
/**
* @return {@link List} of unassigned entity.
*/
public List<T> getUnassignedEntity() {
return unassignedEntity;
if (unassignedEntity == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(unassignedEntity);
}
}

View File

@@ -44,6 +44,6 @@ public interface BaseEntity extends Serializable, Identifiable<Long> {
/**
* @return version of the {@link BaseEntity}.
*/
long getOptLockRevision();
int getOptLockRevision();
}

View File

@@ -26,10 +26,25 @@ import org.eclipse.hawkbit.repository.DistributionSetManagement;
public interface DistributionSet extends NamedVersionedEntity {
/**
* @return {@link Set} of assigned {@link DistributionSetTag}s.
* @return immutable {@link Set} of assigned {@link DistributionSetTag}s.
*/
Set<DistributionSetTag> getTags();
/**
* @param tag
* to add
* @return <code>true</code> if tag could be added sucessfully (i.e. was not
* already in the list).
*/
boolean addTag(final DistributionSetTag tag);
/**
* @param tag
* to remove
* @return <code>true</code> if tag was in the list and removed
*/
boolean removeTag(final DistributionSetTag tag);
/**
* @return <code>true</code> if the set is deleted and only kept for history
* purposes.

View File

@@ -17,8 +17,8 @@ import java.util.List;
public interface DistributionSetTag extends Tag {
/**
* @return {@link List} of {@link DistributionSet}s this {@link Tag} is
* assigned to.
* @return immutable {@link List} of {@link DistributionSet}s this
* {@link Tag} is assigned to.
*/
List<DistributionSet> getAssignedToDistributionSet();

View File

@@ -27,15 +27,15 @@ public interface DistributionSetType extends NamedEntity {
boolean isDeleted();
/**
* @return set of {@link SoftwareModuleType}s that need to be in a
* @return immutable set of {@link SoftwareModuleType}s that need to be in a
* {@link DistributionSet} of this type to be
* {@link DistributionSet#isComplete()}.
*/
Set<SoftwareModuleType> getMandatoryModuleTypes();
/**
* @return set of optional {@link SoftwareModuleType}s that can be in a
* {@link DistributionSet} of this type.
* @return immutable set of optional {@link SoftwareModuleType}s that can be
* in a {@link DistributionSet} of this type.
*/
Set<SoftwareModuleType> getOptionalModuleTypes();

View File

@@ -11,6 +11,9 @@ package org.eclipse.hawkbit.repository.model;
/**
* Interface for the entity interceptor lifecycle.
*/
// Exception squid:EmptyStatementUsageCheck - don't want to force users to
// impelemnt all methods
@SuppressWarnings("squid:EmptyStatementUsageCheck")
public interface EntityInterceptor {
/**

View File

@@ -38,7 +38,7 @@ public interface Rollout extends NamedEntity {
void setDistributionSet(DistributionSet distributionSet);
/**
* @return list of deployment groups of the rollout.
* @return immutable list of deployment groups of the rollout.
*/
List<RolloutGroup> getRolloutGroups();

View File

@@ -155,7 +155,7 @@ public interface RolloutGroup extends NamedEntity {
/**
* @return the total amount of targets containing in this group
*/
long getTotalTargets();
int getTotalTargets();
/**
* @return the totalTargetCountStatus

View File

@@ -11,6 +11,10 @@ package org.eclipse.hawkbit.repository.model;
import java.util.List;
import java.util.Optional;
/**
* Software package as sub element of a {@link DistributionSet}.
*
*/
public interface SoftwareModule extends NamedVersionedEntity {
/**
@@ -40,12 +44,12 @@ public interface SoftwareModule extends NamedVersionedEntity {
Optional<LocalArtifact> getLocalArtifactByFilename(String fileName);
/**
* @return the artifacts
* @return immutable list of all artifacts
*/
List<Artifact> getArtifacts();
/**
* @return local artifacts only
* @return immutable list of local artifacts only
*/
List<LocalArtifact> getLocalArtifacts();
@@ -104,7 +108,8 @@ public interface SoftwareModule extends NamedVersionedEntity {
List<SoftwareModuleMetadata> getMetadata();
/**
* @return the assignedTo
* @return immutable list of {@link DistributionSet}s the module is assigned
* to
*/
List<DistributionSet> getAssignedTo();

View File

@@ -32,12 +32,12 @@ public interface Target extends NamedEntity {
String getControllerId();
/**
* @return assigned {@link TargetTag}s.
* @return immutable set of assigned {@link TargetTag}s.
*/
Set<TargetTag> getTags();
/**
* @return {@link Action} history of the {@link Target}.
* @return immutable {@link Action} history of the {@link Target}.
*/
List<Action> getActions();
@@ -64,4 +64,19 @@ public interface Target extends NamedEntity {
*/
void setSecurityToken(String token);
/**
* @param tag
* to add
* @return <code>true</code> if tag could be added sucessfully (i.e. was not
* already in the list).
*/
public boolean addTag(TargetTag tag);
/**
* @param tag
* to remove
* @return <code>true</code> if tag was in the list and removed
*/
public boolean removeTag(TargetTag tag);
}

View File

@@ -36,7 +36,8 @@ public interface TargetInfo extends Serializable {
/**
* @return time in {@link TimeUnit#MILLISECONDS} GMT when the {@link Target}
* polled the server the last time.
* polled the server the last time or <code>null</code> if target
* has never queried yet.
*/
Long getLastTargetQuery();

View File

@@ -17,7 +17,7 @@ import java.util.List;
public interface TargetTag extends Tag {
/**
* @return {@link List} of targets assigned to this {@link Tag}.
* @return immutable {@link List} of targets assigned to this {@link Tag}.
*/
List<Target> getAssignedToTargets();

View File

@@ -0,0 +1,34 @@
/**
* 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.rsql;
/**
* An interface declaration which validates an RSQL based query syntax and
* allows providing suggestions e.g. in case of syntax errors or current cursor
* position.
*/
@FunctionalInterface
public interface RsqlValidationOracle {
/**
* Parses and validates an given RSQL based query syntax and provides
* suggestion based on syntax error and cursor positioning.
*
* @param rsqlQuery
* an RSQL based query string to parse.
* @param cursorPosition
* the position of the cursor to retrieve suggestions at the
* position. {@code -1} indicates for no cursor suggestion
* @return a validation oracle context providing information about syntax
* errors and possible suggestions for fixing the syntax error or at
* the cursor position to replace tokens
*/
ValidationOracleContext suggest(final String rsqlQuery, final int cursorPosition);
}

View File

@@ -0,0 +1,63 @@
/**
* 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.rsql;
/**
* A suggestion which contains the start and the end character position of the
* suggested token of the suggestion of the token and the actual suggestion.
*/
public class SuggestToken {
private final int start;
private final int end;
private final String suggestion;
private final String tokenImageName;
/**
* Constructor.
*
* @param start
* the character position of the start of the token
* @param end
* the character position of the end of the token
* @param tokenImageName
* the entered name of the token, e.g. could be the beginning of
* the suggestion like 'na' or 'name'
* @param suggestion
* the token suggestion
*/
public SuggestToken(final int start, final int end, final String tokenImageName, final String suggestion) {
this.start = start;
this.end = end;
this.tokenImageName = tokenImageName;
this.suggestion = suggestion;
}
public int getStart() {
return start;
}
public int getEnd() {
return end;
}
public String getSuggestion() {
return suggestion;
}
public String getTokenImageName() {
return tokenImageName;
}
@Override
public String toString() {
return "SuggestToken [start=" + start + ", end=" + end + ", suggestion=" + suggestion + ", tokenImageName="
+ tokenImageName + "]";
}
}

View File

@@ -0,0 +1,69 @@
/**
* 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.rsql;
import java.util.ArrayList;
import java.util.List;
/**
* The context which holds suggestions for the current cursor position.
*/
public class SuggestionContext {
private String rsqlQuery;
private int cursorPosition;
private List<SuggestToken> suggestions = new ArrayList<>();
/**
* Default constructor.
*/
public SuggestionContext() {
// nothing to initialize
}
/**
* Constructor.
*
* @param rsqlQuery
* the original RSQL based query the suggestions based on
* @param cursorPosition
* the current cursor position
* @param suggestions
* the suggestions for the current cursor position
*/
public SuggestionContext(final String rsqlQuery, final int cursorPosition, final List<SuggestToken> suggestions) {
this.rsqlQuery = rsqlQuery;
this.cursorPosition = cursorPosition;
this.suggestions = suggestions;
}
public List<SuggestToken> getSuggestions() {
return suggestions;
}
public int getCursorPosition() {
return cursorPosition;
}
public String getRsqlQuery() {
return rsqlQuery;
}
public void setRsqlQuery(final String rsqlQuery) {
this.rsqlQuery = rsqlQuery;
}
public void setCursorPosition(final int cursorPosition) {
this.cursorPosition = cursorPosition;
}
public void setSuggestions(final List<SuggestToken> suggestions) {
this.suggestions = suggestions;
}
}

View File

@@ -0,0 +1,56 @@
/**
* 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.rsql;
/**
* An syntax error context object which holds the character position of the
* syntax error and message.
*/
public class SyntaxErrorContext {
private int characterPosition = -1;
private String errorMessage;
/**
* Default constructor.
*/
public SyntaxErrorContext() {
// nothing to initialize
}
/**
* Constructor.
*
* @param characterPosition
* the position of the character within the RSQL query string the
* error occurs.
* @param errorMessage
* the error message with further information
*/
public SyntaxErrorContext(final int characterPosition, final String errorMessage) {
this.characterPosition = characterPosition;
this.errorMessage = errorMessage;
}
public int getCharacterPosition() {
return characterPosition;
}
public void setCharacterPosition(final int characterPosition) {
this.characterPosition = characterPosition;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(final String errorMessage) {
this.errorMessage = errorMessage;
}
}

View File

@@ -0,0 +1,46 @@
/**
* 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.rsql;
/**
* A context object which contains information about validation and suggestions
* of a parsed RSQL query.
*/
public class ValidationOracleContext {
private boolean syntaxError;
private SuggestionContext suggestionContext;
private SyntaxErrorContext syntaxErrorContext;
public boolean isSyntaxError() {
return syntaxError;
}
public SuggestionContext getSuggestionContext() {
return suggestionContext;
}
public SyntaxErrorContext getSyntaxErrorContext() {
return syntaxErrorContext;
}
public void setSyntaxError(final boolean syntaxError) {
this.syntaxError = syntaxError;
}
public void setSuggestionContext(final SuggestionContext suggestionContext) {
this.suggestionContext = suggestionContext;
}
public void setSyntaxErrorContext(final SyntaxErrorContext syntaxErrorContext) {
this.syntaxErrorContext = syntaxErrorContext;
}
}

View File

@@ -89,6 +89,10 @@
<groupId>cz.jirutka.rsql</groupId>
<artifactId>rsql-parser</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<!-- Test -->
<dependency>

View File

@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.hawkbit.repository.ArtifactManagement;
@@ -54,6 +53,8 @@ import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantAwareHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.repository.jpa.rsql.RsqlParserValidationOracle;
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
@@ -75,6 +76,7 @@ import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import com.google.common.collect.Maps;
import com.google.common.eventbus.EventBus;
/**
@@ -94,6 +96,12 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Autowired
private EventBus eventBus;
@Bean
@ConditionalOnMissingBean
public RsqlValidationOracle rsqlValidationOracle() {
return new RsqlParserValidationOracle();
}
/**
* @return the {@link SystemSecurityContext} singleton bean which make it
* accessible in beans which cannot access the service directly,
@@ -199,7 +207,7 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
@Override
protected Map<String, Object> getVendorProperties() {
final Map<String, Object> properties = new HashMap<>();
final Map<String, Object> properties = Maps.newHashMapWithExpectedSize(5);
// Turn off dynamic weaving to disable LTW lookup in static weaving mode
properties.put("eclipselink.weaving", "false");
// needed for reports

View File

@@ -30,6 +30,7 @@ import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -103,7 +104,7 @@ public interface ActionRepository extends BaseEntityRepository<JpaAction, Long>,
* @return the found {@link Action}
*/
@EntityGraph(value = "Action.ds", type = EntityGraphType.LOAD)
Optional<Action> findFirstByTargetAndActiveOrderByIdAsc(final JpaTarget target, boolean active);
Optional<Action> findFirstByTargetAndActive(final Sort sort, final JpaTarget target, boolean active);
/**
* Retrieves latest {@link UpdateAction} for given target and

View File

@@ -29,7 +29,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaExternalArtifactProvider;
import org.eclipse.hawkbit.repository.jpa.model.JpaLocalArtifact;
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
import org.eclipse.hawkbit.repository.jpa.specifications.SoftwareModuleSpecification;
import org.eclipse.hawkbit.repository.model.Artifact;
import org.eclipse.hawkbit.repository.model.ExternalArtifact;
import org.eclipse.hawkbit.repository.model.ExternalArtifactProvider;
import org.eclipse.hawkbit.repository.model.LocalArtifact;
@@ -194,7 +193,7 @@ public class JpaArtifactManagement implements ArtifactManagement {
}
@Override
public Artifact findArtifact(final Long id) {
public LocalArtifact findLocalArtifact(final Long id) {
return localArtifactRepository.findOne(id);
}

View File

@@ -9,7 +9,7 @@
package org.eclipse.hawkbit.repository.jpa;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -54,6 +54,8 @@ import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.transaction.annotation.Isolation;
@@ -156,6 +158,15 @@ public class JpaControllerManagement implements ControllerManagement {
return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, localArtifact)) > 0;
}
@Override
public boolean hasTargetArtifactAssigned(final Long targetId, final LocalArtifact localArtifact) {
final Target target = targetRepository.findOne(targetId);
if (target == null) {
return false;
}
return actionRepository.count(ActionSpecifications.hasTargetAssignedArtifact(target, localArtifact)) > 0;
}
@Override
public List<Action> findActiveActionByTarget(final Target target) {
return actionRepository.findByTargetAndActiveOrderByIdAsc((JpaTarget) target, true);
@@ -163,12 +174,15 @@ public class JpaControllerManagement implements ControllerManagement {
@Override
public Optional<Action> findOldestActiveActionByTarget(final Target target) {
return actionRepository.findFirstByTargetAndActiveOrderByIdAsc((JpaTarget) target, true);
// used in favorite to findFirstByTargetAndActiveOrderByIdAsc due to
// DATAJPA-841 issue.
return actionRepository.findFirstByTargetAndActive(new Sort(Direction.ASC, "id"), (JpaTarget) target, true);
}
@Override
public List<SoftwareModule> findSoftwareModulesByDistributionSet(final DistributionSet distributionSet) {
return new ArrayList<>(softwareModuleRepository.findByAssignedTo((JpaDistributionSet) distributionSet));
return Collections
.unmodifiableList(softwareModuleRepository.findByAssignedTo((JpaDistributionSet) distributionSet));
}
@Override
@@ -451,12 +465,6 @@ public class JpaControllerManagement implements ControllerManagement {
return actionStatusRepository.save((JpaActionStatus) statusMessage);
}
@Override
public String getSecurityTokenByControllerId(final String controllerId) {
final Target target = targetRepository.findByControllerId(controllerId);
return target != null ? target.getSecurityToken() : null;
}
@Override
@Modifying
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@@ -470,4 +478,14 @@ public class JpaControllerManagement implements ControllerManagement {
cacheWriteNotify.downloadProgress(statusId, requestedBytes, shippedBytesSinceLast, shippedBytesOverall);
}
@Override
public Target findByControllerId(final String controllerId) {
return targetRepository.findByControllerId(controllerId);
}
@Override
public Target findByTargetId(final long targetId) {
return targetRepository.findOne(targetId);
}
}

View File

@@ -367,14 +367,13 @@ public class JpaDeploymentManagement implements DeploymentManagement {
private void assignDistributionSetEvent(final JpaTarget target, final Long actionId,
final List<JpaSoftwareModule> modules) {
((JpaTargetInfo) target.getTargetInfo()).setUpdateStatus(TargetUpdateStatus.PENDING);
final String targetSecurityToken = systemSecurityContext.runAsSystem(() -> target.getSecurityToken());
@SuppressWarnings({ "unchecked", "rawtypes" })
final Collection<SoftwareModule> softwareModules = (Collection) modules;
afterCommit.afterCommit(() -> {
eventBus.post(new TargetInfoUpdateEvent(target.getTargetInfo()));
eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(),
target.getControllerId(), actionId, softwareModules, target.getTargetInfo().getAddress(),
targetSecurityToken));
eventBus.post(new TargetAssignDistributionSetEvent(target.getOptLockRevision(), target.getTenant(), target,
actionId, softwareModules));
});
}
@@ -608,7 +607,7 @@ public class JpaDeploymentManagement implements DeploymentManagement {
multiselect.where(cb.equal(actionRoot.get(JpaAction_.target), target));
multiselect.orderBy(cb.desc(actionRoot.get(JpaAction_.id)));
multiselect.groupBy(actionRoot.get(JpaAction_.id));
return new ArrayList<>(entityManager.createQuery(multiselect).getResultList());
return Collections.unmodifiableList(entityManager.createQuery(multiselect).getResultList());
}
@Override

View File

@@ -15,7 +15,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -67,6 +66,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
/**
@@ -129,26 +129,24 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
final DistributionSetTag myTag = tagManagement.findDistributionSetTag(tagName);
DistributionSetTagAssignmentResult result;
final List<JpaDistributionSet> toBeChangedDSs = new ArrayList<>();
for (final JpaDistributionSet set : sets) {
if (set.getTags().add(myTag)) {
toBeChangedDSs.add(set);
}
}
final List<JpaDistributionSet> toBeChangedDSs = sets.stream().filter(set -> set.addTag(myTag))
.collect(Collectors.toList());
// un-assignment case
if (toBeChangedDSs.isEmpty()) {
for (final JpaDistributionSet set : sets) {
if (set.getTags().remove(myTag)) {
if (set.removeTag(myTag)) {
toBeChangedDSs.add(set);
}
}
result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), 0,
toBeChangedDSs.size(), Collections.emptyList(),
new ArrayList<>(distributionSetRepository.save(toBeChangedDSs)), myTag);
Collections.unmodifiableList(distributionSetRepository.save(toBeChangedDSs)), myTag);
} else {
result = new DistributionSetTagAssignmentResult(dsIds.size() - toBeChangedDSs.size(), toBeChangedDSs.size(),
0, new ArrayList<>(distributionSetRepository.save(toBeChangedDSs)), Collections.emptyList(), myTag);
0, Collections.unmodifiableList(distributionSetRepository.save(toBeChangedDSs)),
Collections.emptyList(), myTag);
}
final DistributionSetTagAssignmentResult resultAssignment = result;
@@ -177,8 +175,6 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Modifying
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public void deleteDistributionSet(final Long... distributionSetIDs) {
final List<Long> toHardDelete = new ArrayList<>();
final List<Long> assigned = distributionSetRepository
.findAssignedToTargetDistributionSetsById(distributionSetIDs);
assigned.addAll(distributionSetRepository.findAssignedToRolloutDistributionSetsById(distributionSetIDs));
@@ -191,13 +187,10 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
}
// mark the rest as hard delete
for (final Long setId : distributionSetIDs) {
if (!assigned.contains(setId)) {
toHardDelete.add(setId);
}
}
final List<Long> toHardDelete = Arrays.stream(distributionSetIDs).filter(setId -> !assigned.contains(setId))
.collect(Collectors.toList());
// hard delete the rest if exixts
// hard delete the rest if exists
if (!toHardDelete.isEmpty()) {
// don't give the delete statement an empty list, JPA/Oracle cannot
// handle the empty list
@@ -244,7 +237,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@SuppressWarnings({ "unchecked", "rawtypes" })
final Collection<JpaDistributionSet> toSave = (Collection) distributionSets;
return new ArrayList<>(distributionSetRepository.save(toSave));
return Collections.unmodifiableList(distributionSetRepository.save(toSave));
}
@Override
@@ -297,7 +290,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
}
private static Page<DistributionSetType> convertDsTPage(final Page<JpaDistributionSetType> findAll) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()));
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()));
}
@Override
@@ -315,7 +308,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
private static Page<DistributionSet> convertDsPage(final Page<JpaDistributionSet> findAll,
final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
/**
@@ -338,7 +331,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override
public Page<DistributionSet> findDistributionSetsByDeletedAndOrCompleted(final Pageable pageReq,
final Boolean deleted, final Boolean complete) {
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>();
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>(2);
if (deleted != null) {
final Specification<JpaDistributionSet> spec = DistributionSetSpecification.isDeleted(deleted);
@@ -359,11 +352,12 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
final Specification<JpaDistributionSet> spec = RSQLUtility.parse(rsqlParam, DistributionSetFields.class);
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>();
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>(2);
if (deleted != null) {
specList.add(DistributionSetSpecification.isDeleted(deleted));
}
specList.add(spec);
return convertDsPage(findByCriteriaAPI(pageReq, specList), pageReq);
}
@@ -388,7 +382,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
final Page<DistributionSet> findDistributionSetsByFilters = findDistributionSetsByFilters(pageable,
dsFilterWithNoTargetLinked);
final List<DistributionSet> resultSet = new LinkedList<>(findDistributionSetsByFilters.getContent());
final List<DistributionSet> resultSet = new ArrayList<>(findDistributionSetsByFilters.getContent());
int orderIndex = 0;
if (installedDS != null) {
final boolean remove = resultSet.remove(installedDS);
@@ -419,18 +413,15 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override
public List<DistributionSet> findDistributionSetsAll(final Collection<Long> dist) {
return new ArrayList<>(distributionSetRepository.findAll(DistributionSetSpecification.byIds(dist)));
return Collections
.unmodifiableList(distributionSetRepository.findAll(DistributionSetSpecification.byIds(dist)));
}
@Override
public Long countDistributionSetsAll() {
final List<Specification<JpaDistributionSet>> specList = new LinkedList<>();
final Specification<JpaDistributionSet> spec = DistributionSetSpecification.isDeleted(Boolean.FALSE);
specList.add(spec);
return distributionSetRepository.count(SpecificationsBuilder.combineWithAnd(specList));
return distributionSetRepository.count(SpecificationsBuilder.combineWithAnd(Lists.newArrayList(spec)));
}
@Override
@@ -560,7 +551,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@Override
public List<DistributionSetMetadata> findDistributionSetMetadataByDistributionSetId(final Long distributionSetId) {
return new ArrayList<>(distributionSetMetadataRepository
return Collections.unmodifiableList(distributionSetMetadataRepository
.findAll((Specification<JpaDistributionSetMetadata>) (root, query, cb) -> cb.equal(
root.get(JpaDistributionSetMetadata_.distributionSet).get(JpaDistributionSet_.id),
distributionSetId)));
@@ -584,7 +575,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
private static Page<DistributionSetMetadata> convertMdPage(final Page<JpaDistributionSetMetadata> findAll,
final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
@Override
@@ -609,7 +600,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
private static List<Specification<JpaDistributionSet>> buildDistributionSetSpecifications(
final DistributionSetFilter distributionSetFilter) {
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>();
final List<Specification<JpaDistributionSet>> specList = new ArrayList<>(7);
Specification<JpaDistributionSet> spec;
@@ -710,9 +701,9 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
public List<DistributionSet> assignTag(final Collection<Long> dsIds, final DistributionSetTag tag) {
final List<JpaDistributionSet> allDs = findDistributionSetListWithDetails(dsIds);
allDs.forEach(ds -> ds.getTags().add(tag));
allDs.forEach(ds -> ds.addTag(tag));
final List<DistributionSet> save = new ArrayList<>(distributionSetRepository.save(allDs));
final List<DistributionSet> save = Collections.unmodifiableList(distributionSetRepository.save(allDs));
afterCommit.afterCommit(() -> {
@@ -732,7 +723,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
@SuppressWarnings({ "unchecked", "rawtypes" })
final Collection<JpaDistributionSet> distributionSets = (Collection) tag.getAssignedToDistributionSet();
return new ArrayList<>(unAssignTag(distributionSets, tag));
return Collections.unmodifiableList(unAssignTag(distributionSets, tag));
}
@Override
@@ -746,7 +737,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
private List<JpaDistributionSet> unAssignTag(final Collection<JpaDistributionSet> distributionSets,
final DistributionSetTag tag) {
distributionSets.forEach(ds -> ds.getTags().remove(tag));
distributionSets.forEach(ds -> ds.removeTag(tag));
return distributionSetRepository.save(distributionSets);
}

View File

@@ -43,11 +43,13 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.eclipse.hawkbit.repository.model.TargetFilterQuery;
import org.eclipse.hawkbit.repository.model.TargetTag;
import org.springframework.validation.annotation.Validated;
/**
* JPA Implementation of {@link EntityFactory}.
*
*/
@Validated
public class JpaEntityFactory implements EntityFactory {
@Override

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -81,11 +81,11 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
}
private static Page<RolloutGroup> convertPage(final Page<JpaRolloutGroup> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
private static Page<Target> convertTPage(final Page<JpaTarget> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
@Override
@@ -114,7 +114,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
for (final RolloutGroup rolloutGroup : rolloutGroups) {
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(
allStatesForRollout.get(rolloutGroup.getId()), rolloutGroup.getTotalTargets());
allStatesForRollout.get(rolloutGroup.getId()), Long.valueOf(rolloutGroup.getTotalTargets()));
rolloutGroup.setTotalTargetCountStatus(totalTargetCountStatus);
}
@@ -128,7 +128,7 @@ public class JpaRolloutGroupManagement implements RolloutGroupManagement {
.getStatusCountByRolloutGroupId(rolloutGroupId);
final TotalTargetCountStatus totalTargetCountStatus = new TotalTargetCountStatus(rolloutStatusCountItems,
rolloutGroup.getTotalTargets());
Long.valueOf(rolloutGroup.getTotalTargets()));
rolloutGroup.setTotalTargetCountStatus(totalTargetCountStatus);
return rolloutGroup;

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -140,11 +140,11 @@ public class JpaRolloutManagement implements RolloutManagement {
}
private static Page<Rollout> convertPage(final Page<JpaRollout> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
private static Slice<Rollout> convertPage(final Slice<JpaRollout> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0);
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, 0);
}
@Override
@@ -651,7 +651,7 @@ public class JpaRolloutManagement implements RolloutManagement {
@Override
public float getFinishedPercentForRunningGroup(final Long rolloutId, final RolloutGroup rolloutGroup) {
final Long totalGroup = rolloutGroup.getTotalTargets();
final int totalGroup = rolloutGroup.getTotalTargets();
final Long finished = actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rolloutId,
rolloutGroup.getId(), Action.Status.FINISHED);
if (totalGroup == 0) {

View File

@@ -11,12 +11,15 @@ package org.eclipse.hawkbit.repository.jpa;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
@@ -65,6 +68,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
@@ -166,7 +170,7 @@ public class JpaSoftwareManagement implements SoftwareManagement {
@SuppressWarnings({ "unchecked", "rawtypes" })
final Collection<JpaSoftwareModule> jpaCast = (Collection) swModules;
return new ArrayList<>(softwareModuleRepository.save(jpaCast));
return Collections.unmodifiableList(softwareModuleRepository.save(jpaCast));
}
@Override
@@ -185,22 +189,22 @@ public class JpaSoftwareManagement implements SoftwareManagement {
private static Slice<SoftwareModule> convertSmPage(final Slice<JpaSoftwareModule> findAll,
final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0);
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, 0);
}
private static Page<SoftwareModule> convertSmPage(final Page<JpaSoftwareModule> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
private static Page<SoftwareModuleMetadata> convertSmMdPage(final Page<JpaSoftwareModuleMetadata> findAll,
final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
@Override
public Long countSoftwareModulesByType(final SoftwareModuleType type) {
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>();
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(2);
Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.equalType((JpaSoftwareModuleType) type);
specList.add(spec);
@@ -277,7 +281,7 @@ public class JpaSoftwareManagement implements SoftwareManagement {
@Override
public Slice<SoftwareModule> findSoftwareModulesAll(final Pageable pageable) {
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>();
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(2);
Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
specList.add(spec);
@@ -296,13 +300,9 @@ public class JpaSoftwareManagement implements SoftwareManagement {
@Override
public Long countSoftwareModulesAll() {
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>();
final Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
specList.add(spec);
return countSwModuleByCriteriaAPI(specList);
return countSwModuleByCriteriaAPI(Lists.newArrayList(spec));
}
@Override
@@ -327,20 +327,20 @@ public class JpaSoftwareManagement implements SoftwareManagement {
private static Page<SoftwareModuleType> convertSmTPage(final Page<JpaSoftwareModuleType> findAll,
final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
@Override
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
public List<SoftwareModule> findSoftwareModulesById(final Collection<Long> ids) {
return new ArrayList<>(softwareModuleRepository.findByIdIn(ids));
return Collections.unmodifiableList(softwareModuleRepository.findByIdIn(ids));
}
@Override
public Slice<SoftwareModule> findSoftwareModuleByFilters(final Pageable pageable, final String searchText,
final SoftwareModuleType type) {
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>();
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(4);
Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
specList.add(spec);
@@ -438,7 +438,7 @@ public class JpaSoftwareManagement implements SoftwareManagement {
private static List<Specification<JpaSoftwareModule>> buildSpecificationList(final String searchText,
final JpaSoftwareModuleType type) {
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>();
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
if (!Strings.isNullOrEmpty(searchText)) {
specList.add(SoftwareModuleSpecification.likeNameOrVersion(searchText));
}
@@ -452,18 +452,15 @@ public class JpaSoftwareManagement implements SoftwareManagement {
private Predicate[] specificationsToPredicate(final List<Specification<JpaSoftwareModule>> specifications,
final Root<JpaSoftwareModule> root, final CriteriaQuery<?> query, final CriteriaBuilder cb,
final Predicate... additionalPredicates) {
final List<Predicate> predicates = new ArrayList<>();
specifications.forEach(spec -> predicates.add(spec.toPredicate(root, query, cb)));
for (final Predicate predicate : additionalPredicates) {
predicates.add(predicate);
}
return predicates.toArray(new Predicate[predicates.size()]);
return Stream.concat(specifications.stream().map(spec -> spec.toPredicate(root, query, cb)),
Arrays.stream(additionalPredicates)).toArray(Predicate[]::new);
}
@Override
public Long countSoftwareModuleByFilters(final String searchText, final SoftwareModuleType type) {
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>();
final List<Specification<JpaSoftwareModule>> specList = new ArrayList<>(3);
Specification<JpaSoftwareModule> spec = SoftwareModuleSpecification.isDeletedFalse();
specList.add(spec);
@@ -573,7 +570,7 @@ public class JpaSoftwareManagement implements SoftwareManagement {
checkAndThrowAlreadyExistsIfSoftwareModuleMetadataExists(softwareModuleMetadata.getId());
}
metadata.forEach(m -> entityManager.merge((JpaSoftwareModule) m.getSoftwareModule()).setLastModifiedAt(-1L));
return new ArrayList<>(softwareModuleMetadataRepository.save(metadata));
return Collections.unmodifiableList(softwareModuleMetadataRepository.save(metadata));
}
@Override
@@ -623,8 +620,8 @@ public class JpaSoftwareManagement implements SoftwareManagement {
@Override
public List<SoftwareModuleMetadata> findSoftwareModuleMetadataBySoftwareModuleId(final Long softwareModuleId) {
return new ArrayList<>(
softwareModuleMetadataRepository
return Collections
.unmodifiableList(softwareModuleMetadataRepository
.findAll((Specification<JpaSoftwareModuleMetadata>) (root, query,
cb) -> cb.and(cb.equal(
root.get(JpaSoftwareModuleMetadata_.softwareModule).get(JpaSoftwareModule_.id),

View File

@@ -303,4 +303,9 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
Constants.DST_DEFAULT_OS_WITH_APPS_NAME, "Default type with Firmware/OS and optional app(s).")
.addMandatoryModuleType(os).addOptionalModuleType(app));
}
@Override
public TenantMetaData getTenantMetadata(final Long tenantId) {
return tenantMetaDataRepository.findOne(tenantId);
}
}

View File

@@ -10,8 +10,8 @@ package org.eclipse.hawkbit.repository.jpa;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -111,7 +111,7 @@ public class JpaTagManagement implements TagManagement {
}
});
final List<TargetTag> save = new ArrayList<>(targetTagRepository.save(targetTags));
final List<TargetTag> save = Collections.unmodifiableList(targetTagRepository.save(targetTags));
afterCommit
.afterCommit(() -> eventBus.post(new TargetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save)));
return save;
@@ -125,7 +125,7 @@ public class JpaTagManagement implements TagManagement {
final List<JpaTarget> changed = new LinkedList<>();
for (final JpaTarget target : targetRepository.findByTag(tag)) {
target.getTags().remove(tag);
target.removeTag(tag);
changed.add(target);
}
@@ -141,7 +141,7 @@ public class JpaTagManagement implements TagManagement {
@Override
public List<TargetTag> findAllTargetTags() {
return new ArrayList<>(targetTagRepository.findAll());
return Collections.unmodifiableList(targetTagRepository.findAll());
}
@Override
@@ -152,12 +152,12 @@ public class JpaTagManagement implements TagManagement {
}
private static Page<TargetTag> convertTPage(final Page<JpaTargetTag> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
private static Page<DistributionSetTag> convertDsPage(final Page<JpaDistributionSetTag> findAll,
final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
@Override
@@ -213,7 +213,8 @@ public class JpaTagManagement implements TagManagement {
throw new EntityAlreadyExistsException();
}
}
final List<DistributionSetTag> save = new ArrayList<>(distributionSetTagRepository.save(distributionSetTags));
final List<DistributionSetTag> save = Collections
.unmodifiableList(distributionSetTagRepository.save(distributionSetTags));
afterCommit.afterCommit(
() -> eventBus.post(new DistributionSetTagCreatedBulkEvent(tenantAware.getCurrentTenant(), save)));
@@ -228,7 +229,7 @@ public class JpaTagManagement implements TagManagement {
final List<JpaDistributionSet> changed = new LinkedList<>();
for (final JpaDistributionSet set : distributionSetRepository.findByTag(tag)) {
set.getTags().remove(tag);
set.removeTag(tag);
changed.add(set);
}
@@ -254,7 +255,7 @@ public class JpaTagManagement implements TagManagement {
@Override
public List<DistributionSetTag> findAllDistributionSetTags() {
return new ArrayList<>(distributionSetTagRepository.findAll());
return Collections.unmodifiableList(distributionSetTagRepository.findAll());
}
@Override

View File

@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
@@ -128,7 +129,7 @@ public class JpaTargetManagement implements TargetManagement {
@Override
public List<Target> findTargetByControllerID(final Collection<String> controllerIDs) {
return new ArrayList<>(targetRepository
return Collections.unmodifiableList(targetRepository
.findAll(TargetSpecifications.byControllerIdWithStatusAndAssignedInJoin(controllerIDs)));
}
@@ -194,7 +195,7 @@ public class JpaTargetManagement implements TargetManagement {
toUpdate.forEach(target -> target.setNew(false));
return new ArrayList<>(targetRepository.save(toUpdate));
return Collections.unmodifiableList(targetRepository.save(toUpdate));
}
@Override
@@ -237,11 +238,11 @@ public class JpaTargetManagement implements TargetManagement {
}
private static Page<Target> convertPage(final Page<JpaTarget> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, findAll.getTotalElements());
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, findAll.getTotalElements());
}
private static Slice<Target> convertPage(final Slice<JpaTarget> findAll, final Pageable pageable) {
return new PageImpl<>(new ArrayList<>(findAll.getContent()), pageable, 0);
return new PageImpl<>(Collections.unmodifiableList(findAll.getContent()), pageable, 0);
}
@Override
@@ -290,7 +291,7 @@ public class JpaTargetManagement implements TargetManagement {
private static List<Specification<JpaTarget>> buildSpecificationList(final Collection<TargetUpdateStatus> status,
final String searchText, final Long installedOrAssignedDistributionSetId,
final Boolean selectTargetWithNoTag, final boolean fetch, final String... tagNames) {
final List<Specification<JpaTarget>> specList = new ArrayList<>();
final List<Specification<JpaTarget>> specList = new LinkedList<>();
if (status != null && !status.isEmpty()) {
specList.add(TargetSpecifications.hasTargetUpdateStatus(status, fetch));
}
@@ -343,7 +344,7 @@ public class JpaTargetManagement implements TargetManagement {
// all are already assigned -> unassign
if (alreadyAssignedTargets.size() == allTargets.size()) {
alreadyAssignedTargets.forEach(target -> target.getTags().remove(tag));
alreadyAssignedTargets.forEach(target -> target.removeTag(tag));
final TargetTagAssignmentResult result = new TargetTagAssignmentResult(0, 0, alreadyAssignedTargets.size(),
Collections.emptyList(), alreadyAssignedTargets, tag);
@@ -353,9 +354,10 @@ public class JpaTargetManagement implements TargetManagement {
allTargets.removeAll(alreadyAssignedTargets);
// some or none are assigned -> assign
allTargets.forEach(target -> target.getTags().add(tag));
allTargets.forEach(target -> target.addTag(tag));
final TargetTagAssignmentResult result = new TargetTagAssignmentResult(alreadyAssignedTargets.size(),
allTargets.size(), 0, new ArrayList<>(targetRepository.save(allTargets)), Collections.emptyList(), tag);
allTargets.size(), 0, Collections.unmodifiableList(targetRepository.save(allTargets)),
Collections.emptyList(), tag);
afterCommit.afterCommit(() -> eventBus.post(new TargetTagAssigmentResultEvent(result)));
@@ -371,8 +373,8 @@ public class JpaTargetManagement implements TargetManagement {
final List<JpaTarget> allTargets = targetRepository
.findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(targetIds));
allTargets.forEach(target -> target.getTags().add(tag));
final List<Target> save = new ArrayList<>(targetRepository.save(allTargets));
allTargets.forEach(target -> target.addTag(tag));
final List<Target> save = Collections.unmodifiableList(targetRepository.save(allTargets));
afterCommit.afterCommit(() -> {
final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, save.size(), 0, save,
@@ -384,11 +386,12 @@ public class JpaTargetManagement implements TargetManagement {
}
private List<Target> unAssignTag(final Collection<Target> targets, final TargetTag tag) {
@SuppressWarnings({ "unchecked", "rawtypes" })
final Collection<JpaTarget> toUnassign = (Collection) targets;
toUnassign.forEach(target -> target.getTags().remove(tag));
toUnassign.forEach(target -> target.removeTag(tag));
final List<Target> save = new ArrayList<>(targetRepository.save(toUnassign));
final List<Target> save = Collections.unmodifiableList(targetRepository.save(toUnassign));
afterCommit.afterCommit(() -> {
final TargetTagAssignmentResult assigmentResult = new TargetTagAssignmentResult(0, 0, save.size(),
Collections.emptyList(), save, tag);
@@ -408,7 +411,7 @@ public class JpaTargetManagement implements TargetManagement {
@Modifying
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public Target unAssignTag(final String controllerID, final TargetTag targetTag) {
final List<Target> allTargets = new ArrayList<>(targetRepository
final List<Target> allTargets = Collections.unmodifiableList(targetRepository
.findAll(TargetSpecifications.byControllerIdWithStatusAndTagsInJoin(Arrays.asList(controllerID))));
final List<Target> unAssignTag = unAssignTag(allTargets, targetTag);
return unAssignTag.isEmpty() ? null : unAssignTag.get(0);
@@ -464,7 +467,7 @@ public class JpaTargetManagement implements TargetManagement {
final List<JpaTarget> resultList = entityManager.createQuery(query).setFirstResult(pageable.getOffset())
.setMaxResults(pageSize + 1).getResultList();
final boolean hasNext = resultList.size() > pageSize;
return new SliceImpl<>(new ArrayList<>(resultList), pageable, hasNext);
return new SliceImpl<>(Collections.unmodifiableList(resultList), pageable, hasNext);
}
private static Predicate[] specificationsToPredicate(final List<Specification<JpaTarget>> specifications,
@@ -546,11 +549,8 @@ public class JpaTargetManagement implements TargetManagement {
targetRoot.get(JpaTarget_.controllerId), targetRoot.get(JpaTarget_.name), targetRoot.get(sortProperty));
final Specification<JpaTarget> spec = RSQLUtility.parse(targetFilterQuery.getQuery(), TargetFields.class);
final List<Specification<JpaTarget>> specList = new ArrayList<>();
specList.add(spec);
final Predicate[] specificationsForMultiSelect = specificationsToPredicate(specList, targetRoot, multiselect,
cb);
final Predicate[] specificationsForMultiSelect = specificationsToPredicate(Lists.newArrayList(spec), targetRoot,
multiselect, cb);
// if we have some predicates then add it to the where clause of the
// multiselect
@@ -637,18 +637,16 @@ public class JpaTargetManagement implements TargetManagement {
targets.stream().map(target -> target.getControllerId()).collect(Collectors.toList())) > 0) {
throw new EntityAlreadyExistsException();
}
final List<Target> savedTargets = new ArrayList<>();
for (final Target t : targets) {
final Target myTarget = createTarget(t, TargetUpdateStatus.UNKNOWN, null, t.getTargetInfo().getAddress());
savedTargets.add(myTarget);
}
return savedTargets;
return targets.stream()
.map(t -> createTarget(t, TargetUpdateStatus.UNKNOWN, null, t.getTargetInfo().getAddress()))
.collect(Collectors.toList());
}
@Override
public List<Target> findTargetsByTag(final String tagName) {
final JpaTargetTag tag = targetTagRepository.findByNameEquals(tagName);
return new ArrayList<>(targetRepository.findByTag(tag));
return Collections.unmodifiableList(targetRepository.findByTag(tag));
}
@Override

View File

@@ -10,7 +10,6 @@ package org.eclipse.hawkbit.repository.jpa.aspects;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -36,6 +35,8 @@ import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.transaction.TransactionSystemException;
import com.google.common.collect.Maps;
/**
* {@link Aspect} catches persistence exceptions and wraps them to custom
* specific exceptions Additionally it checks and prevents access to certain
@@ -49,14 +50,14 @@ public class ExceptionMappingAspectHandler implements Ordered {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionMappingAspectHandler.class);
private static final Map<String, String> EXCEPTION_MAPPING = new HashMap<>();
private static final Map<String, String> EXCEPTION_MAPPING = Maps.newHashMapWithExpectedSize(4);
/**
* this is required to enable a certain order of exception and to select the
* most specific mappable exception according to the type hierarchy of the
* exception.
*/
private static final List<Class<?>> MAPPED_EXCEPTION_ORDER = new ArrayList<>();
private static final List<Class<?>> MAPPED_EXCEPTION_ORDER = new ArrayList<>(4);
@Autowired
private JpaVendorAdapter jpaVendorAdapter;

View File

@@ -32,7 +32,7 @@ public abstract class AbstractJpaArtifact extends AbstractJpaTenantAwareBaseEnti
private String md5Hash;
@Column(name = "file_size")
private Long size;
private long size;
@Override
public abstract SoftwareModule getSoftwareModule();
@@ -56,11 +56,11 @@ public abstract class AbstractJpaArtifact extends AbstractJpaTenantAwareBaseEnti
}
@Override
public Long getSize() {
public long getSize() {
return size;
}
public void setSize(final Long size) {
public void setSize(final long size) {
this.size = size;
}
}

View File

@@ -48,7 +48,7 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
@Version
@Column(name = "optlock_revision")
private long optLockRevision;
private int optLockRevision;
/**
* Default constructor needed for JPA entities.
@@ -106,11 +106,11 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
}
@Override
public long getOptLockRevision() {
public int getOptLockRevision() {
return optLockRevision;
}
public void setOptLockRevision(final long optLockRevision) {
public void setOptLockRevision(final int optLockRevision) {
this.optLockRevision = optLockRevision;
}
@@ -142,7 +142,7 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
final int prime = 31;
int result = 1;
result = prime * result + (id == null ? 0 : id.hashCode());
result = prime * result + (int) (optLockRevision ^ optLockRevision >>> 32);
result = prime * result + optLockRevision;
result = prime * result + this.getClass().getName().hashCode();
return result;
}
@@ -179,5 +179,4 @@ public abstract class AbstractJpaBaseEntity implements BaseEntity {
return true;
}
}

View File

@@ -26,7 +26,7 @@ public abstract class AbstractJpaMetaData implements MetaData {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "meta_key", length = 128)
@Column(name = "meta_key", nullable = false, length = 128)
@Size(min = 1, max = 128)
@NotNull
private String key;
@@ -37,7 +37,6 @@ public abstract class AbstractJpaMetaData implements MetaData {
private String value;
public AbstractJpaMetaData(final String key, final String value) {
super();
this.key = key;
this.value = value;
}

View File

@@ -40,7 +40,7 @@ public abstract class AbstractJpaNamedEntity extends AbstractJpaTenantAwareBaseE
* Default constructor.
*/
public AbstractJpaNamedEntity() {
super();
// Default constructor needed for JPA entities
}
/**

View File

@@ -47,7 +47,7 @@ public abstract class AbstractJpaNamedVersionedEntity extends AbstractJpaNamedEn
}
AbstractJpaNamedVersionedEntity() {
super();
// Default constructor needed for JPA entities
}
@Override

View File

@@ -31,7 +31,7 @@ public abstract class AbstractJpaTag extends AbstractJpaNamedEntity implements T
private String colour;
protected AbstractJpaTag() {
super();
// Default constructor needed for JPA entities
}
/**

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Collections;
import java.util.List;
import javax.persistence.CascadeType;
@@ -134,7 +135,11 @@ public class JpaAction extends AbstractJpaTenantAwareBaseEntity implements Actio
@Override
public List<ActionStatus> getActionStatus() {
return actionStatus;
if (actionStatus == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(actionStatus);
}
@Override

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.persistence.CollectionTable;
@@ -48,6 +49,8 @@ import com.google.common.base.Splitter;
// sub entities
@SuppressWarnings("squid:S2160")
public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements ActionStatus {
private static final int MESSAGE_ENTRY_LENGTH = 512;
private static final long serialVersionUID = 1L;
@Column(name = "target_occurred_at")
@@ -67,14 +70,14 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
@CollectionTable(name = "sp_action_status_messages", joinColumns = @JoinColumn(name = "action_status_id", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_stat_msg_act_stat")), indexes = {
@Index(name = "sp_idx_action_status_msgs_01", columnList = "action_status_id") })
@Column(name = "detail_message", length = 512)
private final List<String> messages = new ArrayList<>();
private List<String> messages;
/**
* Note: filled only in {@link Status#DOWNLOAD}.
*/
@Transient
@CacheField(key = CacheKeys.DOWNLOAD_PROGRESS_PERCENT)
private int downloadProgressPercent;
private short downloadProgressPercent;
/**
* Creates a new {@link ActionStatus} object.
@@ -86,7 +89,7 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
* @param occurredAt
* the occurred timestamp
*/
public JpaActionStatus(final Action action, final Status status, final Long occurredAt) {
public JpaActionStatus(final Action action, final Status status, final long occurredAt) {
this.action = (JpaAction) action;
this.status = status;
this.occurredAt = occurredAt;
@@ -119,7 +122,7 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
}
@Override
public int getDownloadProgressPercent() {
public short getDownloadProgressPercent() {
return downloadProgressPercent;
}
@@ -136,13 +139,20 @@ public class JpaActionStatus extends AbstractJpaTenantAwareBaseEntity implements
@Override
public final void addMessage(final String message) {
if (message != null) {
Splitter.fixedLength(512).split(message).forEach(messages::add);
if (messages == null) {
messages = new ArrayList<>((message.length() / MESSAGE_ENTRY_LENGTH) + 1);
}
Splitter.fixedLength(MESSAGE_ENTRY_LENGTH).split(message).forEach(messages::add);
}
}
@Override
public List<String> getMessages() {
return messages;
if (messages == null) {
messages = Collections.emptyList();
}
return Collections.unmodifiableList(messages);
}
@Override

View File

@@ -59,7 +59,7 @@ public class JpaActionWithStatusCount implements ActionWithStatusCount {
// Exception squid:S00107 - needed this way for JPA to fill the view
@SuppressWarnings("squid:S00107")
public JpaActionWithStatusCount(final Long actionId, final ActionType actionType, final boolean active,
final long forcedTime, final Status status, final Long actionCreatedAt, final Long actionLastModifiedAt,
final Long forcedTime, final Status status, final Long actionCreatedAt, final Long actionLastModifiedAt,
final Long dsId, final String dsName, final String dsVersion, final Long actionStatusCount,
final String rolloutName) {
this.dsId = dsId;

View File

@@ -8,7 +8,6 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -83,13 +82,13 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@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<>();
private Set<SoftwareModule> modules;
@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<>();
private Set<DistributionSetTag> tags;
@Column(name = "deleted")
private boolean deleted;
@@ -110,7 +109,7 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@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<>();
private List<DistributionSetMetadata> metadata;
@ManyToOne(fetch = FetchType.LAZY, targetEntity = JpaDistributionSetType.class)
@JoinColumn(name = "ds_id", nullable = false, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_ds_dstype_ds"))
@@ -124,7 +123,7 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
* Default constructor.
*/
public JpaDistributionSet() {
super();
// Default constructor for JPA
}
/**
@@ -156,7 +155,29 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@Override
public Set<DistributionSetTag> getTags() {
return tags;
if (tags == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(tags);
}
@Override
public boolean addTag(final DistributionSetTag tag) {
if (tags == null) {
tags = new HashSet<>();
}
return tags.add(tag);
}
@Override
public boolean removeTag(final DistributionSetTag tag) {
if (tags == null) {
return false;
}
return tags.remove(tag);
}
@Override
@@ -166,11 +187,19 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@Override
public List<DistributionSetMetadata> getMetadata() {
if (metadata == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(metadata);
}
public List<Action> getActions() {
return actions;
if (actions == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(actions);
}
@Override
@@ -190,14 +219,13 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
return this;
}
public DistributionSet setTags(final Set<DistributionSetTag> tags) {
this.tags = tags;
return this;
}
@Override
public List<Target> getAssignedTargets() {
return assignedToTargets;
if (assignedToTargets == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(assignedToTargets);
}
@Override
@@ -207,7 +235,11 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@Override
public List<TargetInfo> getInstalledTargets() {
return installedAtTargets;
if (installedAtTargets == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(installedAtTargets);
}
@Override
@@ -218,21 +250,20 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@Override
public Set<SoftwareModule> getModules() {
if (modules == null) {
return Collections.emptySet();
}
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();
if (modules == null) {
modules = new HashSet<>();
}
// check if it is allowed to such a module to this DS type
if (!type.containsModuleType(softwareModule.getType())) {
throw new UnsupportedSoftwareModuleForThisDistributionSetException();
}
checkTypeCompatability(softwareModule);
final Optional<SoftwareModule> found = modules.stream()
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
@@ -258,8 +289,24 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
return false;
}
private void checkTypeCompatability(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();
}
}
@Override
public boolean removeModule(final SoftwareModule softwareModule) {
if (modules == null) {
return false;
}
final Optional<SoftwareModule> found = modules.stream()
.filter(module -> module.getId().equals(softwareModule.getId())).findFirst();
@@ -275,6 +322,10 @@ public class JpaDistributionSet extends AbstractJpaNamedVersionedEntity implemen
@Override
public SoftwareModule findFirstModuleByType(final SoftwareModuleType type) {
if (modules == null) {
return null;
}
final Optional<SoftwareModule> result = modules.stream().filter(module -> module.getType().equals(type))
.findFirst();

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Collections;
import java.util.List;
import javax.persistence.Entity;
@@ -68,26 +69,10 @@ public class JpaDistributionSetTag extends AbstractJpaTag implements Distributio
@Override
public List<DistributionSet> getAssignedToDistributionSet() {
return assignedToDistributionSet;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.getClass().getName().hashCode();
return result;
}
@Override
public boolean equals(final Object obj) { // NOSONAR - as this is generated
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof DistributionSetTag)) {
return false;
if (assignedToDistributionSet == null) {
return Collections.emptyList();
}
return true;
return Collections.unmodifiableList(assignedToDistributionSet);
}
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
@@ -24,6 +25,7 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Size;
import org.apache.commons.collections4.CollectionUtils;
import org.eclipse.hawkbit.repository.model.DistributionSet;
import org.eclipse.hawkbit.repository.model.DistributionSetType;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
@@ -48,7 +50,7 @@ public class JpaDistributionSetType extends AbstractJpaNamedEntity implements Di
@OneToMany(targetEntity = DistributionSetTypeElement.class, cascade = {
CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "distribution_set_type", insertable = false, updatable = false)
private final Set<DistributionSetTypeElement> elements = new HashSet<>();
private Set<DistributionSetTypeElement> elements;
@Column(name = "type_key", nullable = false, length = 64)
@Size(max = 64)
@@ -108,23 +110,52 @@ public class JpaDistributionSetType extends AbstractJpaNamedEntity implements Di
@Override
public Set<SoftwareModuleType> getMandatoryModuleTypes() {
if (elements == null) {
return Collections.emptySet();
}
return elements.stream().filter(element -> element.isMandatory()).map(element -> element.getSmType())
.collect(Collectors.toSet());
}
@Override
public Set<SoftwareModuleType> getOptionalModuleTypes() {
if (elements == null) {
return Collections.emptySet();
}
return elements.stream().filter(element -> !element.isMandatory()).map(element -> element.getSmType())
.collect(Collectors.toSet());
}
@Override
public boolean areModuleEntriesIdentical(final DistributionSetType dsType) {
if (!(dsType instanceof JpaDistributionSetType) || isOneModuleListEmpty(dsType)) {
return false;
} else if (areBothModuleListsEmpty(dsType)) {
return true;
}
return new HashSet<DistributionSetTypeElement>(((JpaDistributionSetType) dsType).elements).equals(elements);
}
private boolean isOneModuleListEmpty(final DistributionSetType dsType) {
return (!CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements)
&& CollectionUtils.isEmpty(elements))
|| (CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements)
&& !CollectionUtils.isEmpty(elements));
}
private boolean areBothModuleListsEmpty(final DistributionSetType dsType) {
return CollectionUtils.isEmpty(((JpaDistributionSetType) dsType).elements) && CollectionUtils.isEmpty(elements);
}
@Override
public DistributionSetType addOptionalModuleType(final SoftwareModuleType smType) {
if (elements == null) {
elements = new HashSet<>();
}
elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, false));
return this;
@@ -132,6 +163,10 @@ public class JpaDistributionSetType extends AbstractJpaNamedEntity implements Di
@Override
public DistributionSetType addMandatoryModuleType(final SoftwareModuleType smType) {
if (elements == null) {
elements = new HashSet<>();
}
elements.add(new DistributionSetTypeElement(this, (JpaSoftwareModuleType) smType, true));
return this;
@@ -139,6 +174,10 @@ public class JpaDistributionSetType extends AbstractJpaNamedEntity implements Di
@Override
public DistributionSetType removeModuleType(final Long smTypeId) {
if (elements == null) {
return this;
}
// we search by id (standard equals compares also revison)
final Optional<DistributionSetTypeElement> found = elements.stream()
.filter(element -> element.getSmType().getId().equals(smTypeId)).findFirst();
@@ -177,7 +216,11 @@ public class JpaDistributionSetType extends AbstractJpaNamedEntity implements Di
}
public Set<DistributionSetTypeElement> getElements() {
return elements;
if (elements == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(elements);
}
@Override

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Collections;
import java.util.List;
import javax.persistence.Column;
@@ -108,11 +109,11 @@ public class JpaRollout extends AbstractJpaNamedEntity implements Rollout, Event
@Override
public List<RolloutGroup> getRolloutGroups() {
return rolloutGroups;
}
if (rolloutGroups == null) {
return Collections.emptyList();
}
public void setRolloutGroups(final List<RolloutGroup> rolloutGroups) {
this.rolloutGroups = rolloutGroups;
return Collections.unmodifiableList(rolloutGroups);
}
@Override

View File

@@ -8,7 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.persistence.CascadeType;
@@ -58,7 +58,7 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
@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<>();
private List<RolloutTargetGroup> rolloutTargetGroup;
@ManyToOne(fetch = FetchType.LAZY)
private JpaRolloutGroup parent;
@@ -92,7 +92,7 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
private String errorActionExp;
@Column(name = "total_targets")
private long totalTargets;
private int totalTargets;
@Transient
private transient TotalTargetCountStatus totalTargetCountStatus;
@@ -118,7 +118,11 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
}
public List<RolloutTargetGroup> getRolloutTargetGroup() {
return rolloutTargetGroup;
if (rolloutTargetGroup == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(rolloutTargetGroup);
}
@Override
@@ -201,11 +205,11 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
}
@Override
public long getTotalTargets() {
public int getTotalTargets() {
return totalTargets;
}
public void setTotalTargets(final long totalTargets) {
public void setTotalTargets(final int totalTargets) {
this.totalTargets = totalTargets;
}
@@ -223,7 +227,7 @@ public class JpaRolloutGroup extends AbstractJpaNamedEntity implements RolloutGr
@Override
public TotalTargetCountStatus getTotalTargetCountStatus() {
if (totalTargetCountStatus == null) {
totalTargetCountStatus = new TotalTargetCountStatus(totalTargets);
totalTargetCountStatus = new TotalTargetCountStatus(new Long(totalTargets));
}
return totalTargetCountStatus;
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
@@ -40,6 +41,8 @@ import org.eclipse.hawkbit.repository.model.SoftwareModuleMetadata;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.persistence.annotations.CascadeOnDelete;
import com.google.common.collect.Lists;
/**
* Base Software Module that is supported by OS level provisioning mechanism on
* the edge controller, e.g. OS, JVM, AgentHub.
@@ -64,7 +67,7 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
private JpaSoftwareModuleType type;
@ManyToMany(mappedBy = "modules", targetEntity = JpaDistributionSet.class, fetch = FetchType.LAZY)
private final List<DistributionSet> assignedTo = new ArrayList<>();
private List<DistributionSet> assignedTo;
@Column(name = "deleted")
private boolean deleted;
@@ -82,13 +85,13 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
@CascadeOnDelete
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.REMOVE }, targetEntity = JpaSoftwareModuleMetadata.class)
@JoinColumn(name = "sw_id", insertable = false, updatable = false)
private final List<SoftwareModuleMetadata> metadata = new ArrayList<>();
private List<SoftwareModuleMetadata> metadata;
/**
* Default constructor.
*/
public JpaSoftwareModule() {
super();
// Default constructor for JPA
}
/**
@@ -120,6 +123,8 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
public void addArtifact(final LocalArtifact artifact) {
if (null == artifacts) {
artifacts = new ArrayList<>(4);
artifacts.add(artifact);
return;
}
if (!artifacts.contains(artifact)) {
@@ -134,7 +139,9 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
@Override
public void addArtifact(final ExternalArtifact artifact) {
if (null == externalArtifacts) {
externalArtifacts = new ArrayList<>(4);
externalArtifacts = new LinkedList<>();
externalArtifacts.add(artifact);
return;
}
if (!externalArtifacts.contains(artifact)) {
@@ -143,28 +150,18 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
}
/**
* @param artifactId
* to look for
* @return found {@link Artifact}
*/
@Override
public Optional<LocalArtifact> getLocalArtifact(final Long artifactId) {
if (null == artifacts) {
if (artifacts == null) {
return Optional.empty();
}
return artifacts.stream().filter(artifact -> artifact.getId().equals(artifactId)).findFirst();
}
/**
* @param fileName
* to look for
* @return found {@link Artifact}
*/
@Override
public Optional<LocalArtifact> getLocalArtifactByFilename(final String fileName) {
if (null == artifacts) {
if (artifacts == null) {
return Optional.empty();
}
@@ -177,11 +174,18 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
*/
@Override
public List<Artifact> getArtifacts() {
final List<Artifact> result = new ArrayList<>();
result.addAll(artifacts);
if (artifacts == null && externalArtifacts == null) {
return Collections.emptyList();
} else if (artifacts == null) {
return Collections.unmodifiableList(externalArtifacts);
} else if (externalArtifacts == null) {
return Collections.unmodifiableList(artifacts);
}
final List<Artifact> result = Lists.newLinkedList(artifacts);
result.addAll(externalArtifacts);
return result;
return Collections.unmodifiableList(result);
}
/**
@@ -207,7 +211,7 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
*/
@Override
public void removeArtifact(final LocalArtifact artifact) {
if (null != artifacts) {
if (artifacts != null) {
artifacts.remove(artifact);
}
}
@@ -218,7 +222,7 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
*/
@Override
public void removeArtifact(final ExternalArtifact artifact) {
if (null != externalArtifacts) {
if (externalArtifacts != null) {
externalArtifacts.remove(artifact);
}
}
@@ -248,11 +252,12 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
this.type = (JpaSoftwareModuleType) type;
}
/**
* @return immutable list of meta data elements.
*/
@Override
public List<SoftwareModuleMetadata> getMetadata() {
if (metadata == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(metadata);
}
@@ -262,12 +267,13 @@ public class JpaSoftwareModule extends AbstractJpaNamedVersionedEntity implement
+ ", revision=" + getOptLockRevision() + ", Id=" + getId() + ", type=" + getType().getName() + "]";
}
/**
* @return the assignedTo
*/
@Override
public List<DistributionSet> getAssignedTo() {
return assignedTo;
if (assignedTo == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(assignedTo);
}
}

View File

@@ -9,6 +9,7 @@
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -85,13 +86,13 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
@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<>();
private Set<TargetTag> tags;
@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<>();
private List<Action> actions;
@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"))
@@ -114,7 +115,7 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
@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<>();
private List<RolloutTargetGroup> rolloutTargetGroup;
/**
* Constructor.
@@ -141,12 +142,8 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
targetInfo = new JpaTargetInfo(this);
}
/**
* empty constructor for JPA.
*/
JpaTarget() {
controllerId = null;
securityToken = null;
// empty constructor for JPA.
}
@Override
@@ -161,7 +158,37 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
@Override
public Set<TargetTag> getTags() {
return tags;
if (tags == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(tags);
}
public List<RolloutTargetGroup> getRolloutTargetGroup() {
if (rolloutTargetGroup == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(rolloutTargetGroup);
}
@Override
public boolean addTag(final TargetTag tag) {
if (tags == null) {
tags = new HashSet<>();
}
return tags.add(tag);
}
@Override
public boolean removeTag(final TargetTag tag) {
if (tags == null) {
return false;
}
return tags.remove(tag);
}
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
@@ -172,13 +199,21 @@ public class JpaTarget extends AbstractJpaNamedEntity implements Persistable<Lon
this.controllerId = controllerId;
}
public void setTags(final Set<TargetTag> tags) {
this.tags = tags;
}
@Override
public List<Action> getActions() {
return actions;
if (actions == null) {
return Collections.emptyList();
}
return Collections.unmodifiableList(actions);
}
public boolean addAction(final Action action) {
if (actions == null) {
actions = new ArrayList<>();
}
return actions.add(action);
}
@Override

View File

@@ -220,7 +220,7 @@ public class JpaTargetInfo implements Persistable<Long>, TargetInfo, EventAwareE
return lastTargetQuery;
}
public void setLastTargetQuery(final Long lastTargetQuery) {
public void setLastTargetQuery(final long lastTargetQuery) {
this.lastTargetQuery = lastTargetQuery;
}

View File

@@ -8,6 +8,7 @@
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.Collections;
import java.util.List;
import javax.persistence.Entity;
@@ -65,27 +66,11 @@ public class JpaTargetTag extends AbstractJpaTag implements TargetTag {
@Override
public List<Target> getAssignedToTargets() {
return assignedToTargets;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + this.getClass().getName().hashCode();
return result;
}
@Override
public boolean equals(final Object obj) {
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof TargetTag)) {
return false;
if (assignedToTargets == null) {
return Collections.emptyList();
}
return true;
return Collections.unmodifiableList(assignedToTargets);
}
}

View File

@@ -29,8 +29,8 @@ public class ThresholdRolloutGroupSuccessCondition implements RolloutGroupCondit
@Override
public boolean eval(final Rollout rollout, final RolloutGroup rolloutGroup, final String expression) {
final Long totalGroup = rolloutGroup.getTotalTargets();
final Long finished = this.actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rollout.getId(),
final long totalGroup = rolloutGroup.getTotalTargets();
final long finished = this.actionRepository.countByRolloutIdAndRolloutGroupIdAndStatus(rollout.getId(),
rolloutGroup.getId(), Action.Status.FINISHED);
try {
final Integer threshold = Integer.valueOf(expression);

View File

@@ -0,0 +1,188 @@
/**
* 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.rsql;
import java.lang.reflect.Field;
import java.util.Arrays;
import com.google.common.base.Throwables;
import cz.jirutka.rsql.parser.ParseException;
/**
* A {@link ParseException} wrapper which allows to access the parsing
* information from the exception using reflection due there is no other access
* of this information. See issue for requesting feature
* <a href="https://github.com/jirutka/rsql-parser/issues/22">https://github.com
* /jirutka/rsql-parser/issues/22</a>
*/
public class ParseExceptionWrapper {
private static final String FIELD_EXPECTED_TOKEN_SEQ = "expectedTokenSequences";
private static final String FIELD_CURRENT_TOKEN = "currentToken";
private final ParseException parseException;
private final Class<? extends ParseException> parseExceptionClass;
private Field expectedTokenSequenceField;
private Field currentTokenField;
/**
* Constructor.
*
* @param parseException
* the original parsing exception object to access its field
* using reflection
*/
public ParseExceptionWrapper(final ParseException parseException) {
this.parseException = parseException;
parseExceptionClass = parseException.getClass();
try {
expectedTokenSequenceField = getAccessibleField(parseExceptionClass, FIELD_EXPECTED_TOKEN_SEQ);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
expectedTokenSequenceField = null;
}
try {
currentTokenField = getAccessibleField(parseExceptionClass, FIELD_CURRENT_TOKEN);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
currentTokenField = null;
}
}
public int[][] getExpectedTokenSequence() {
if (expectedTokenSequenceField == null) {
return new int[0][0];
}
return (int[][]) getValue(expectedTokenSequenceField, parseException);
}
public TokenWrapper getCurrentToken() {
if (currentTokenField == null) {
return null;
}
return new TokenWrapper(getValue(currentTokenField, parseException));
}
@Override
public String toString() {
return "ParseExceptionWrapper [getExpectedTokenSequence()=" + Arrays.toString(getExpectedTokenSequence())
+ ", getCurrentToken()=" + getCurrentToken() + "]";
}
private static Field getAccessibleField(final Class<?> clazz, final String field) throws NoSuchFieldException {
final Field declaredField = clazz.getDeclaredField(field);
declaredField.setAccessible(true);
return declaredField;
}
private static Object getValue(final Field field, final Object instance) {
try {
return field.get(instance);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw Throwables.propagate(e);
}
}
/**
* A {@link TokenWrapper} which wraps the
* {@code cz.jirutka.rsql.parser.Token} class of the {@link ParseException}
* which otherwise is not accessible.
*/
public static final class TokenWrapper {
private static final String FIELD_NEXT = "next";
private static final String FIELD_KIND = "kind";
private static final String FIELD_IMAGE = "image";
private static final String FIELD_BEGIN_COL = "beginColumn";
private static final String FIELD_END_COL = "endColumn";
private final Object tokenInstance;
private Field nextTokenField;
private Field kindTokenField;
private Field imageTokenField;
private Field beginColumnTokenField;
private Field endColumnTokenField;
private TokenWrapper(final Object tokenField) {
this.tokenInstance = tokenField;
try {
nextTokenField = getAccessibleField(tokenField.getClass(), FIELD_NEXT);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
nextTokenField = null;
}
try {
kindTokenField = getAccessibleField(tokenField.getClass(), FIELD_KIND);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
kindTokenField = null;
}
try {
imageTokenField = getAccessibleField(tokenField.getClass(), FIELD_IMAGE);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
imageTokenField = null;
}
try {
beginColumnTokenField = getAccessibleField(tokenField.getClass(), FIELD_BEGIN_COL);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
beginColumnTokenField = null;
}
try {
endColumnTokenField = getAccessibleField(tokenField.getClass(), FIELD_END_COL);
} catch (@SuppressWarnings("squid:S1166") final NoSuchFieldException e) {
endColumnTokenField = null;
}
}
public TokenWrapper getNext() {
final Object nextToken = getValue(nextTokenField, tokenInstance);
return nextToken != null ? new TokenWrapper(nextToken) : null;
}
public int getKind() {
if (kindTokenField == null) {
return 0;
}
return (int) getValue(kindTokenField, tokenInstance);
}
public String getImage() {
if (imageTokenField == null) {
return null;
}
return (String) getValue(imageTokenField, tokenInstance);
}
public int getBeginColumn() {
if (beginColumnTokenField == null) {
return 0;
}
return (int) getValue(beginColumnTokenField, tokenInstance);
}
public int getEndColumn() {
if (endColumnTokenField == null) {
return 0;
}
return (int) getValue(endColumnTokenField, tokenInstance);
}
@Override
public String toString() {
return "TokenWrapper [tokenInstance=" + tokenInstance + ", getNext()=" + getNext() + ", getKind()="
+ getKind() + ", getImage()=" + getImage() + ", getBeginColumn()=" + getBeginColumn()
+ ", getEndColumn()=" + getEndColumn() + "]";
}
}
}

View File

@@ -0,0 +1,321 @@
/**
* 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.rsql;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.TargetManagement;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.jpa.rsql.ParseExceptionWrapper.TokenWrapper;
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
import org.eclipse.hawkbit.repository.rsql.SuggestToken;
import org.eclipse.hawkbit.repository.rsql.SuggestionContext;
import org.eclipse.hawkbit.repository.rsql.SyntaxErrorContext;
import org.eclipse.hawkbit.repository.rsql.ValidationOracleContext;
import org.eclipse.persistence.exceptions.ConversionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.orm.jpa.JpaSystemException;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import cz.jirutka.rsql.parser.ParseException;
import cz.jirutka.rsql.parser.RSQLParserException;
/**
* An implementation of {@link RsqlValidationOracle} which retrieves the
* exception using the {@link ParseException} to retrieve the suggestions.
*
* The suggestion only works when there are syntax errors existing because the
* information about current and next tokens in the RSQL syntax are from the
* {@link ParseException}.
*
* There is a feature request on the GitHub project
* <a href="https://github.com/jirutka/rsql-parser/issues/22">https://github.com
* /jirutka/rsql-parser/issues/22</a>
*
*/
public class RsqlParserValidationOracle implements RsqlValidationOracle {
private static final Logger LOGGER = LoggerFactory.getLogger(RsqlParserValidationOracle.class);
@Autowired
private TargetManagement targetManagement;
@Override
public ValidationOracleContext suggest(final String rsqlQuery, final int cursorPosition) {
final List<SuggestToken> expectedTokens = new ArrayList<>();
final ValidationOracleContext context = new ValidationOracleContext();
context.setSyntaxError(true);
final SuggestionContext suggestionContext = new SuggestionContext();
context.setSuggestionContext(suggestionContext);
final SyntaxErrorContext errorContext = new SyntaxErrorContext();
context.setSyntaxErrorContext(errorContext);
try {
targetManagement.findTargetsAll(rsqlQuery, new PageRequest(0, 1));
context.setSyntaxError(false);
suggestionContext.getSuggestions().addAll(getLogicalOperatorSuggestion(rsqlQuery));
} catch (final RSQLParameterSyntaxException | RSQLParserException ex) {
setExceptionDetails(new Exception(ex.getCause().getCause()), expectedTokens);
errorContext.setErrorMessage(getCustomMessage(ex.getCause().getMessage(), expectedTokens));
suggestionContext.setSuggestions(expectedTokens);
LOGGER.trace("Syntax exception on parsing :", ex);
} catch (final RSQLParameterUnsupportedFieldException | IllegalArgumentException ex) {
errorContext.setErrorMessage(getCustomMessage(ex.getMessage(), null));
LOGGER.trace("Illegal argument on parsing :", ex);
} catch (@SuppressWarnings("squid:S1166") final ConversionException | JpaSystemException e) {
// noop
}
return context;
}
private static Collection<? extends SuggestToken> getLogicalOperatorSuggestion(final String rsqlQuery) {
if (!rsqlQuery.endsWith(" ")) {
return Collections.emptyList();
}
if (rsqlQuery.endsWith(" ")) {
final int currentQueryLength = rsqlQuery.length();
// only return and/or suggestion when there is a space at the end
final Collection<String> tokenImages = TokenDescription.getTokenImage(TokenDescription.LOGICAL_OP);
final List<SuggestToken> logicalOps = new ArrayList<>(tokenImages.size());
for (final String tokenImage : tokenImages) {
logicalOps.add(new SuggestToken(currentQueryLength, currentQueryLength + tokenImage.length(), null,
tokenImage));
}
return logicalOps;
}
return Collections.emptyList();
}
private static void setExceptionDetails(final Exception ex, final List<SuggestToken> expectedTokens) {
expectedTokens.addAll(getNextTokens(ex));
}
private static List<SuggestToken> getNextTokens(final Exception e) {
final ParseException parseException = findParseException(e);
if (parseException == null) {
return Collections.emptyList();
}
final List<SuggestToken> listTokens = new ArrayList<>();
final ParseExceptionWrapper parseExceptionWrapper = new ParseExceptionWrapper(parseException);
final int[][] expectedTokenSequence = parseExceptionWrapper.getExpectedTokenSequence();
final TokenWrapper currentToken = parseExceptionWrapper.getCurrentToken();
final TokenWrapper nextToken = currentToken.getNext();
final int currentTokenKind = currentToken.getKind();
final String currentTokenImageName = currentToken.getImage();
final int nextTokenBeginColumn = nextToken.getBeginColumn();
final int currentTokenEndColumn = currentToken.getEndColumn();
// token == 5 is the field token, reverse engineering.
if (currentTokenKind == 5) {
final Optional<List<SuggestToken>> handleFieldTokenSuggestion = handleFieldTokenSuggestion(
currentTokenImageName, nextTokenBeginColumn, currentTokenEndColumn);
if (handleFieldTokenSuggestion.isPresent()) {
return handleFieldTokenSuggestion.get();
}
}
for (final int[] is : expectedTokenSequence) {
for (final int i : is) {
final Collection<String> tokenImage = TokenDescription.getTokenImage(i);
if (tokenImage != null && !tokenImage.isEmpty()) {
tokenImage.forEach(image -> listTokens.add(new SuggestToken(currentTokenEndColumn + 1,
nextTokenBeginColumn + image.length(), null, image)));
}
}
}
return listTokens;
}
private static Optional<List<SuggestToken>> handleFieldTokenSuggestion(final String currentTokenImageName,
final int nextTokenBeginColumn, final int currentTokenEndColumn) {
final boolean containsDot = currentTokenImageName.indexOf('.') != -1;
if (shouldSuggestTopLevelFieldNames(currentTokenImageName, containsDot)) {
return Optional
.of(FieldNameDescription.toTopSuggestToken(nextTokenBeginColumn - currentTokenImageName.length(),
nextTokenBeginColumn + currentTokenImageName.length(), currentTokenImageName));
} else if (shouldSuggestDotToken(currentTokenImageName, containsDot)) {
return Optional.of(
Lists.newArrayList(new SuggestToken(currentTokenEndColumn, nextTokenBeginColumn + 1, null, ".")));
} else if (shouldSuggestSubTokenFieldNames(currentTokenImageName, containsDot)) {
return handleSubtokenSuggestion(currentTokenImageName, nextTokenBeginColumn);
}
return Optional.empty();
}
private static boolean shouldSuggestSubTokenFieldNames(final String currentTokenImageName,
final boolean containsDot) {
return containsDot && !FieldNameDescription.containsValue(currentTokenImageName);
}
private static boolean shouldSuggestDotToken(final String currentTokenImageName, final boolean containsDot) {
return !containsDot && FieldNameDescription.hasSubEntries(currentTokenImageName);
}
private static boolean shouldSuggestTopLevelFieldNames(final String currentTokenImageName,
final boolean containsDot) {
return !containsDot && !FieldNameDescription.containsValue(currentTokenImageName)
&& !FieldNameDescription.hasSubEntries(currentTokenImageName);
}
private static Optional<List<SuggestToken>> handleSubtokenSuggestion(final String currentTokenImageName,
final int nextTokenBeginColumn) {
final String[] split = currentTokenImageName.split("\\.");
for (final String string : split) {
if (FieldNameDescription.containsValue(string)) {
final String subTokenImage = split.length > 1 ? split[1] : null;
final int subTokenBegin = nextTokenBeginColumn + currentTokenImageName.indexOf('.') + 1;
return Optional.of(FieldNameDescription.toSubSuggestToken(subTokenBegin, subTokenBegin + 1, string,
subTokenImage));
}
}
return Optional.empty();
}
private static ParseException findParseException(final Throwable e) {
if (e instanceof ParseException) {
return (ParseException) e;
} else if (e.getCause() != null) {
return findParseException(e.getCause());
}
return null;
}
private static String getCustomMessage(final String message, final List<SuggestToken> expectedTokens) {
String builder = message;
if (!message.contains(":")) {
return builder;
}
builder = message.substring(message.indexOf(':') + 1, message.length());
if (builder.indexOf("Was expecting") != -1) {
builder = builder.substring(0, builder.lastIndexOf("Was expecting"));
}
if (expectedTokens != null && !expectedTokens.isEmpty()) {
final StringBuilder tokens = new StringBuilder();
expectedTokens.stream().forEach(value -> tokens.append(value.getSuggestion() + ","));
builder = builder.concat("Was expecting :" + tokens.toString().substring(0, tokens.length() - 1));
}
builder = builder.replace('\r', ' ');
builder = builder.replace('\n', ' ');
builder = builder.replaceAll(">", " ");
builder = builder.replaceAll("<", " ");
return builder;
}
// Token map with logical and comparator operator that are used for context
// sensitive help on search query.
private static final class TokenDescription {
private static final Multimap<Integer, String> TOKEN_MAP = ArrayListMultimap.create();
private static final int LOGICAL_OP = 8;
private static final int COMPARATOR = 12;
static {
TOKEN_MAP.put(LOGICAL_OP, "and");
TOKEN_MAP.put(LOGICAL_OP, "or");
TOKEN_MAP.put(COMPARATOR, "==");
TOKEN_MAP.put(COMPARATOR, "!=");
TOKEN_MAP.put(COMPARATOR, "=ge=");
TOKEN_MAP.put(COMPARATOR, "=le=");
TOKEN_MAP.put(COMPARATOR, "=gt=");
TOKEN_MAP.put(COMPARATOR, "=lt=");
TOKEN_MAP.put(COMPARATOR, "=in=");
TOKEN_MAP.put(COMPARATOR, "=out=");
}
private TokenDescription() {
}
private static Collection<String> getTokenImage(final int tokenIndex) {
return TOKEN_MAP.get(tokenIndex);
}
}
private static final class FieldNameDescription {
private static final Set<String> FIELD_NAMES = Arrays.stream(TargetFields.values())
.map(field -> field.toString().toLowerCase()).collect(Collectors.toSet());
private static final Map<String, List<String>> SUB_NAMES = Arrays.stream(TargetFields.values()).collect(
Collectors.toMap(field -> field.toString().toLowerCase(), field -> field.getSubEntityAttributes()));
private FieldNameDescription() {
}
private static boolean hasSubEntries(final String tokenImageName) {
String tmpTokenName = tokenImageName;
if (tokenImageName.contains(".")) {
final String[] split = tokenImageName.split("\\.");
if (split.length <= 0) {
return false;
}
tmpTokenName = split[0];
}
final String finalTmpTokenName = tmpTokenName;
return Arrays.stream(TargetFields.values())
.filter(field -> field.toString().equalsIgnoreCase(finalTmpTokenName))
.map(field -> field.getSubEntityAttributes()).flatMap(subentities -> subentities.stream())
.count() > 0;
}
private static List<SuggestToken> toTopSuggestToken(final int beginToken, final int endToken,
final String tokenImageName) {
return FIELD_NAMES.stream()
.map(field -> new SuggestToken(beginToken, endToken, tokenImageName, field.toLowerCase()))
.collect(Collectors.toList());
}
private static List<SuggestToken> toSubSuggestToken(final int beginToken, final int endToken,
final String topToken, final String tokenImageName) {
return Arrays.stream(TargetFields.values()).filter(field -> field.toString().equalsIgnoreCase(topToken))
.map(field -> field.getSubEntityAttributes()).flatMap(list -> list.stream())
.map(subentity -> new SuggestToken(beginToken, endToken, tokenImageName, subentity))
.collect(Collectors.toList());
}
private static boolean containsValue(final String imageName) {
if (!imageName.contains(".")) {
return FIELD_NAMES.stream().filter(value -> value.equalsIgnoreCase(imageName)).count() > 0;
}
final String[] split = imageName.split("\\.");
if (split.length > 1 && FIELD_NAMES.contains(split[0].toLowerCase())) {
return SUB_NAMES.get(split[0].toLowerCase()).stream()
.filter(subname -> new String(split[0] + "." + subname).equalsIgnoreCase(imageName))
.count() > 0;
}
return FIELD_NAMES.stream().filter(value -> value.equalsIgnoreCase(imageName)).count() > 0;
}
}
}

View File

@@ -279,23 +279,23 @@ public class ArtifactManagementTest extends AbstractJpaIntegrationTestWithMongoD
/**
* Test method for
* {@link org.eclipse.hawkbit.repository.ArtifactManagement#findArtifact(java.lang.Long)}
* {@link org.eclipse.hawkbit.repository.ArtifactManagement#findLocalArtifact(java.lang.Long)}
* .
*
* @throws IOException
* @throws NoSuchAlgorithmException
*/
@Test
@Description("Loads an artifact based on given ID.")
public void findArtifact() throws NoSuchAlgorithmException, IOException {
@Description("Loads an local artifact based on given ID.")
public void findLocalArtifact() throws NoSuchAlgorithmException, IOException {
SoftwareModule sm = new JpaSoftwareModule(softwareManagement.findSoftwareModuleTypeByKey("os"), "name 1",
"version 1", null, null);
sm = softwareManagement.createSoftwareModule(sm);
final Artifact result = artifactManagement.createLocalArtifact(new RandomGeneratedInputStream(5 * 1024),
final LocalArtifact result = artifactManagement.createLocalArtifact(new RandomGeneratedInputStream(5 * 1024),
sm.getId(), "file1", false);
assertThat(artifactManagement.findArtifact(result.getId())).isEqualTo(result);
assertThat(artifactManagement.findLocalArtifact(result.getId())).isEqualTo(result);
}
/**

View File

@@ -106,7 +106,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
assertThat(findActionsWithStatusCountByTarget).as("wrong action size").hasSize(1);
assertThat(findActionsWithStatusCountByTarget.get(0).getActionStatusCount()).as("wrong action status size")
.isEqualTo(3L);
.isEqualTo(3);
}
@Test
@@ -842,8 +842,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet("a");
// assign ds to create an action
final DistributionSetAssignmentResult assignDistributionSet = deploymentManagement.assignDistributionSet(
ds.getId(), ActionType.SOFT, org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME,
target.getControllerId());
ds.getId(), ActionType.SOFT,
org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME, target.getControllerId());
final Action action = deploymentManagement.findActionWithDetails(assignDistributionSet.getActions().get(0));
// verify preparation
Action findAction = deploymentManagement.findAction(action.getId());
@@ -865,8 +865,8 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet("a");
// assign ds to create an action
final DistributionSetAssignmentResult assignDistributionSet = deploymentManagement.assignDistributionSet(
ds.getId(), ActionType.FORCED, org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME,
target.getControllerId());
ds.getId(), ActionType.FORCED,
org.eclipse.hawkbit.repository.model.RepositoryModelConstants.NO_FORCE_TIME, target.getControllerId());
final Action action = deploymentManagement.findActionWithDetails(assignDistributionSet.getActions().get(0));
// verify perparation
Action findAction = deploymentManagement.findAction(action.getId());
@@ -937,7 +937,7 @@ public class DeploymentManagementTest extends AbstractJpaIntegrationTest {
for (final Target myt : targets) {
boolean found = false;
for (final TargetAssignDistributionSetEvent event : events) {
if (event.getControllerId().equals(myt.getControllerId())) {
if (event.getTarget().getControllerId().equals(myt.getControllerId())) {
found = true;
final List<Action> activeActionsByTarget = deploymentManagement.findActiveActionsByTarget(myt);
assertThat(activeActionsByTarget).as("size of active actions for target is wrong").isNotEmpty();

View File

@@ -396,14 +396,14 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
// create a DS
final DistributionSet ds = testdataFactory.createDistributionSet("testDs");
// initial opt lock revision must be zero
assertThat(ds.getOptLockRevision()).isEqualTo(1L);
assertThat(ds.getOptLockRevision()).isEqualTo(1);
// create an DS meta data entry
final DistributionSetMetadata dsMetadata = distributionSetManagement
.createDistributionSetMetadata(new JpaDistributionSetMetadata(knownKey, ds, knownValue));
DistributionSet changedLockRevisionDS = distributionSetManagement.findDistributionSetById(ds.getId());
assertThat(changedLockRevisionDS.getOptLockRevision()).isEqualTo(2L);
assertThat(changedLockRevisionDS.getOptLockRevision()).isEqualTo(2);
// modifying the meta data value
dsMetadata.setValue(knownUpdateValue);
@@ -419,7 +419,7 @@ public class DistributionSetManagementTest extends AbstractJpaIntegrationTest {
// module so opt lock
// revision must be three
changedLockRevisionDS = distributionSetManagement.findDistributionSetById(ds.getId());
assertThat(changedLockRevisionDS.getOptLockRevision()).isEqualTo(3L);
assertThat(changedLockRevisionDS.getOptLockRevision()).isEqualTo(3);
assertThat(changedLockRevisionDS.getLastModifiedAt()).isGreaterThan(0L);
// verify updated meta data contains the updated value

View File

@@ -848,7 +848,7 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
final SoftwareModule ah = softwareManagement
.createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, ""));
assertThat(ah.getOptLockRevision()).isEqualTo(1L);
assertThat(ah.getOptLockRevision()).isEqualTo(1);
final SoftwareModuleMetadata swMetadata1 = new JpaSoftwareModuleMetadata(knownKey1, ah, knownValue1);
@@ -858,7 +858,7 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
.createSoftwareModuleMetadata(Lists.newArrayList(swMetadata1, swMetadata2));
final SoftwareModule changedLockRevisionModule = softwareManagement.findSoftwareModuleById(ah.getId());
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(2L);
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(2);
assertThat(softwareModuleMetadata).hasSize(2);
assertThat(softwareModuleMetadata.get(0)).isNotNull();
@@ -900,7 +900,7 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
final SoftwareModule ah = softwareManagement
.createSoftwareModule(new JpaSoftwareModule(appType, "agent-hub", "1.0.1", null, ""));
// initial opt lock revision must be 1
assertThat(ah.getOptLockRevision()).isEqualTo(1L);
assertThat(ah.getOptLockRevision()).isEqualTo(1);
// create an software module meta data entry
final List<SoftwareModuleMetadata> softwareModuleMetadata = softwareManagement.createSoftwareModuleMetadata(
@@ -910,7 +910,7 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
// because we are modifying the
// base software module
SoftwareModule changedLockRevisionModule = softwareManagement.findSoftwareModuleById(ah.getId());
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(2L);
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(2);
// modifying the meta data value
softwareModuleMetadata.get(0).setValue(knownUpdateValue);
@@ -925,7 +925,7 @@ public class SoftwareManagementTest extends AbstractJpaIntegrationTestWithMongoD
// module so opt lock
// revision must be two
changedLockRevisionModule = softwareManagement.findSoftwareModuleById(ah.getId());
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(3L);
assertThat(changedLockRevisionModule.getOptLockRevision()).isEqualTo(3);
// verify updated meta data contains the updated value
assertThat(updated).isNotNull();

View File

@@ -679,7 +679,8 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
final DistributionSet ds = testdataFactory.createDistributionSet("a");
targAssigned = deploymentManagement.assignDistributionSet(ds, targAssigned).getAssignedEntity();
targAssigned = Lists
.newLinkedList(deploymentManagement.assignDistributionSet(ds, targAssigned).getAssignedEntity());
targInstalled = deploymentManagement.assignDistributionSet(ds, targInstalled).getAssignedEntity();
targInstalled = sendUpdateActionStatusToTargets(ds, targInstalled, Status.FINISHED, "installed");
@@ -769,7 +770,7 @@ public class TargetManagementSearchTest extends AbstractJpaIntegrationTest {
private List<Target> sendUpdateActionStatusToTargets(final DistributionSet dsA, final Iterable<Target> targs,
final Status status, final String... msgs) {
final List<Target> result = new ArrayList<Target>();
final List<Target> result = new ArrayList<>();
for (final Target t : targs) {
final List<Action> findByTarget = actionRepository.findByTarget((JpaTarget) t);
for (final Action action : findByTarget) {

View File

@@ -541,28 +541,30 @@ public class TargetManagementTest extends AbstractJpaIntegrationTest {
@Test
@Description("Tests the assigment of tags to the a single target.")
public void targetTagAssignment() {
Target t1 = testdataFactory.generateTarget("id-1", "blablub");
final Target t1 = testdataFactory.generateTarget("id-1", "blablub");
final int noT2Tags = 4;
final int noT1Tags = 3;
final List<TargetTag> t1Tags = tagManagement
.createTargetTags(testdataFactory.generateTargetTags(noT1Tags, "tag1"));
t1.getTags().addAll(t1Tags);
t1 = targetManagement.createTarget(t1);
Target t2 = testdataFactory.generateTarget("id-2", "blablub");
t1Tags.forEach(tag -> ((JpaTarget) t1).addTag(tag));
targetManagement.createTarget(t1);
final Target t2 = testdataFactory.generateTarget("id-2", "blablub");
final List<TargetTag> t2Tags = tagManagement
.createTargetTags(testdataFactory.generateTargetTags(noT2Tags, "tag2"));
t2.getTags().addAll(t2Tags);
t2 = targetManagement.createTarget(t2);
t1 = targetManagement.findTargetByControllerID(t1.getControllerId());
assertThat(t1.getTags()).as("Tag size is wrong").hasSize(noT1Tags).containsAll(t1Tags);
assertThat(t1.getTags()).as("Tag size is wrong").hasSize(noT1Tags)
t2Tags.forEach(tag -> ((JpaTarget) t2).addTag(tag));
targetManagement.createTarget(t2);
final Target t11 = targetManagement.findTargetByControllerID(t1.getControllerId());
assertThat(t11.getTags()).as("Tag size is wrong").hasSize(noT1Tags).containsAll(t1Tags);
assertThat(t11.getTags()).as("Tag size is wrong").hasSize(noT1Tags)
.doesNotContain(Iterables.toArray(t2Tags, TargetTag.class));
t2 = targetManagement.findTargetByControllerID(t2.getControllerId());
assertThat(t2.getTags()).as("Tag size is wrong").hasSize(noT2Tags).containsAll(t2Tags);
assertThat(t2.getTags()).as("Tag size is wrong").hasSize(noT2Tags)
final Target t21 = targetManagement.findTargetByControllerID(t2.getControllerId());
assertThat(t21.getTags()).as("Tag size is wrong").hasSize(noT2Tags).containsAll(t2Tags);
assertThat(t21.getTags()).as("Tag size is wrong").hasSize(noT2Tags)
.doesNotContain(Iterables.toArray(t1Tags, TargetTag.class));
}

View File

@@ -18,7 +18,6 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaAction;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.Action.ActionType;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.domain.PageRequest;
@@ -32,7 +31,7 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Stories("RSQL filter actions")
public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
private Target target;
private JpaTarget target;
private JpaAction action;
@Before
@@ -42,7 +41,7 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
targetManagement.createTarget(target);
action = new JpaAction();
action.setActionType(ActionType.SOFT);
target.getActions().add(action);
target.addAction(action);
action.setTarget(target);
actionRepository.save(action);
for (int i = 0; i < 10; i++) {
@@ -51,7 +50,7 @@ public class RSQLActionFieldsTest extends AbstractJpaIntegrationTest {
newAction.setActive(i % 2 == 0);
newAction.setTarget(target);
actionRepository.save(newAction);
target.getActions().add(newAction);
target.addAction(newAction);
}
}

View File

@@ -0,0 +1,81 @@
/**
* 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.rsql;
import static org.fest.assertions.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.repository.TargetFields;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle;
import org.eclipse.hawkbit.repository.rsql.ValidationOracleContext;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Repository")
@Stories("RSQL filter suggestion")
public class RsqlParserValidationOracleTest extends AbstractJpaIntegrationTest {
@Autowired
private RsqlValidationOracle rsqlValidationOracle;
private static final String[] OP_SUGGESTIONS = new String[] { "==", "!=", "=ge=", "=le=", "=gt=", "=lt=", "=in=",
"=out=" };
private static final String[] FIELD_SUGGESTIONS = Arrays.stream(TargetFields.values())
.map(field -> field.name().toLowerCase()).toArray(size -> new String[size]);
private static final String[] AND_OR_SUGGESTIONS = new String[] { "and", "or" };
private static final String[] NAME_VERSION_SUGGESTIONS = new String[] { "name", "version" };
@Test
@Description("Verifies that suggestions contains all possible field names")
public void suggestionContainsAllFieldNames() {
final String rsqlQuery = "na";
final List<String> currentSuggestions = getSuggestions(rsqlQuery);
assertThat(currentSuggestions).containsOnly(FIELD_SUGGESTIONS);
}
@Test
@Description("Verifies that suggestions only contains the allowed operators")
public void suggestionContainsOnlyOperators() {
final String rsqlQuery = "name";
final List<String> currentSuggestions = getSuggestions(rsqlQuery);
assertThat(currentSuggestions).containsOnly(OP_SUGGESTIONS);
}
@Test
@Description("Verifies that suggestions only contains operator to combine RSQL filters (and, or)")
public void suggestionContainsOnlyAndOrOperator() {
final String rsqlQuery = "name==a ";
final List<String> currentSuggestions = getSuggestions(rsqlQuery);
assertThat(currentSuggestions).containsOnly(AND_OR_SUGGESTIONS);
}
@Test
@Description("Verifies that sub suggestions are shown")
public void suggestionContainsSubFieldSuggestions() {
final String rsqlQuery = "assignedds.";
final List<String> currentSuggestions = getSuggestions(rsqlQuery);
assertThat(currentSuggestions).containsOnly(NAME_VERSION_SUGGESTIONS);
}
private List<String> getSuggestions(final String rsqlQuery) {
final ValidationOracleContext suggest = rsqlValidationOracle.suggest(rsqlQuery, -1);
final List<String> currentSuggestions = suggest.getSuggestionContext().getSuggestions().stream()
.map(suggestion -> suggestion.getSuggestion()).collect(Collectors.toList());
return currentSuggestions;
}
}

View File

@@ -11,6 +11,8 @@ package org.eclipse.hawkbit;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import org.eclipse.hawkbit.api.ArtifactUrlHandlerProperties;
import org.eclipse.hawkbit.api.PropertyBasedArtifactUrlHandler;
import org.eclipse.hawkbit.cache.CacheConstants;
import org.eclipse.hawkbit.cache.TenancyCacheManager;
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
@@ -49,7 +51,8 @@ import com.mongodb.MongoClientOptions;
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.PROXY, proxyTargetClass = false, securedEnabled = true)
@EnableConfigurationProperties({ HawkbitServerProperties.class, DdiSecurityProperties.class })
@EnableConfigurationProperties({ HawkbitServerProperties.class, DdiSecurityProperties.class,
ArtifactUrlHandlerProperties.class })
@Profile("test")
@EnableAutoConfiguration
public class TestConfiguration implements AsyncConfigurer {
@@ -63,6 +66,12 @@ public class TestConfiguration implements AsyncConfigurer {
return new TestdataFactory();
}
@Bean
public PropertyBasedArtifactUrlHandler testPropertyBasedArtifactUrlHandler(
final ArtifactUrlHandlerProperties urlHandlerProperties) {
return new PropertyBasedArtifactUrlHandler(urlHandlerProperties);
}
@Bean
public MongoClientOptions options() {
return MongoClientOptions.builder().connectTimeout(500).maxWaitTime(500).connectionsPerHost(2)