Merge remote-tracking branch 'eclipse/master' into hawkbit-sandbox

This commit is contained in:
Kai Zimmermann
2016-04-02 13:29:45 +02:00
44 changed files with 510 additions and 390 deletions

View File

@@ -1,7 +1,9 @@
# Examples
Example projects that show how hawkBit can be used to create, run or access an hawkBit empowered update server.
Example projects that show how _hawkBit_ can be used to create, run or access an _hawkBit_ empowered update server.
- `hawkbit-device-simulator` : Simulates device software updates, leveraging the hawkBit device integration options.
- `hawkbit-example-app` : Allows you to run a Spring Boot and hawkBit based update server. Includes all _hawkBit_ interfaces, i.e. DDI, DMF, Mgmt-API, Mgmt-UI.
- `hawkbit-custom-theme-example` : Example for a customized theme for Management UI.
- `hawkbit-mgmt-api-client` : Example client for the _hawkBit_ Management API.
`hawkbit-device-simulator` : Simulates device software updates, leveraging the hawkBit device integration options.
`hawkbit-example-app` : Allows you to run a Spring Boot and hawkBit based update server.
`hawkbit-mgmt-api-client` : Example client for the hawkBit management API.

View File

@@ -0,0 +1 @@
Theme customization example for Eclipse hawkBit. See wiki for the theme customization guide.

View File

@@ -0,0 +1,112 @@
<!--
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
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-examples-parent</artifactId>
<version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>hawkbit-custom-theme-example</artifactId>
<name>hawkBit :: Custom Theme Example App</name>
<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.plugin.version}</version>
<configuration>
<warSourceDirectory>src/main/resources</warSourceDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>update-theme</goal>
<goal>compile-theme</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<outputDirectory>${baseDir}</outputDirectory>
<addResources>false</addResources>
<mainClass>org.eclipse.hawkbit.app.Start</mainClass>
<layout>JAR</layout>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Hawkbit -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-autoconfigure</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-ui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-security-integration</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-http-security</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
</project>

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.app;
import org.eclipse.hawkbit.ui.login.HawkbitLoginUI;
import org.eclipse.hawkbit.ui.themes.HawkbitTheme;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.spring.annotation.SpringUI;
/**
* Example hawkBit login UI implementation.
*
* A {@link SpringUI} annotated class must be present in the classpath for the
* login path. The easiest way to get an hawkBit login UI running is to extend
* the {@link HawkbitLoginUI} and to annotated it with {@link SpringUI} as in
* this example to the defined {@link HawkbitTheme#LOGIN_UI_PATH}.
*
*/
@SpringUI(path = HawkbitTheme.LOGIN_UI_PATH)
@Title("hawkBit Theme example")
@Theme(value = "exampletheme")
public class MyLoginUI extends HawkbitLoginUI {
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,45 @@
package org.eclipse.hawkbit.app;
/**
* 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
*/
import org.eclipse.hawkbit.ui.HawkbitUI;
import org.eclipse.hawkbit.ui.UIEventProvider;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.eventbus.EventBus;
import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.Transport;
import com.vaadin.spring.annotation.SpringUI;
/**
* Example hawkBit UI implementation.
*
* A {@link SpringUI} annotated class must be present in the classpath. The
* easiest way to get an hawkBit UI running is to extend the {@link HawkbitUI}
* and to annotated it with {@link SpringUI} as in this example.
*
*/
@SpringUI
@Push(value = PushMode.AUTOMATIC, transport = Transport.WEBSOCKET)
@Title("hawkBit Theme example")
@Theme(value = "exampletheme")
public class MyUI extends HawkbitUI {
private static final long serialVersionUID = 1L;
@Autowired
public MyUI(final EventBus systemEventBus, final org.vaadin.spring.events.EventBus.SessionEventBus eventBus,
final UIEventProvider provider) {
super(new DelayedEventBusPushStrategy(eventBus, systemEventBus, provider));
}
}

View File

@@ -0,0 +1,36 @@
package org.eclipse.hawkbit.app;
/**
* 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
*/
import org.eclipse.hawkbit.RepositoryApplicationConfiguration;
import org.eclipse.hawkbit.autoconfigure.security.EnableHawkbitManagedSecurityConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
/**
* A {@link SpringBootApplication} annotated class with a main method to start.
* The minimal configuration for the stand alone hawkBit server.
*
*/
@SpringBootApplication
@Import({ RepositoryApplicationConfiguration.class })
@EnableHawkbitManagedSecurityConfiguration
public class Start {
/**
* Main method to start the spring-boot application.
*
* @param args
* the VM arguments.
*/
public static void main(final String[] args) {
SpringApplication.run(Start.class, args);
}
}

View File

@@ -0,0 +1,2 @@
/addons.scss
/styles.css

View File

@@ -0,0 +1,24 @@
/**
* 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
*/
$dark-gray: #848484;
//Example color change
$hawkbit-primary-color: $dark-gray;
$hawkbit-primary-color-light: #D8D8D8;
$app-selection-item-selection-color: $dark-gray;
$app-focus-color: $dark-gray;
$app-selection-color: $dark-gray;
$tag-text-color: $dark-gray;
$tab-sheet-caption-color: $dark-gray;
$table-details-tab-font-color: $dark-gray;
$widget-caption-color: $dark-gray;
$accordion-action-history-title-color: $dark-gray;
$menu-title-bg-color: $dark-gray;
$button-icon-color: $dark-gray;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,29 @@
<!--
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
-->
<head>
<style>
.footer-content {
margin-top: 20px ;
}
.doc-link {
color: #26547a !important;
text-decoration: none !important;
}
</style>
</head>
<footer>
<div class="footer-content">
<div style="color: #333; font-family: Helvetica Neue,Helvetica,Arial,sans-serif; font-size: 0.8em !important;line-height: 20px;">
<!-- Footer text goes here -->
<a class="doc-link" target="_blank" href="https://projects.eclipse.org/projects/iot.hawkbit">Eclipe hawkBit Project Page</a>
</div>
</div>
</footer>

View File

@@ -0,0 +1,19 @@
/**
* 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
*/
@import "../hawkbit/customstyles/hawkbitvariables";
@import "customstyles/examplevariables";
@import "../hawkbit/hawkbittheme";
@import "addons";
// This file prefixes all rules with the theme name to avoid causing conflicts with other themes.
.exampletheme {
@include addons;
@include hawkbittheme;
}

View File

@@ -0,0 +1,16 @@
#
# 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
#
# UI demo account
hawkbit.server.ui.demo.password=admin
hawkbit.server.ui.demo.user=admin
hawkbit.server.ui.demo.tenant=DEFAULT
# UI help links
hawkbit.server.ui.links.documentation.root=https://github.com/eclipse/hawkbit

View File

@@ -31,7 +31,7 @@ public class ControllerPollProperties {
* Maximum polling time that can be configured by a tenant in HH:MM:SS
* notation.
*/
private String maxPollingTime = "23:59:00";
private String maxPollingTime = "23:59:59";
/**
* Minimum polling time that can be configured by a tenant in HH:MM:SS

View File

@@ -36,8 +36,15 @@ public final class DurationHelper {
this.max = max;
}
/**
* Checks if the requested duration is in the defined min/max range.
*
* @param duration
* to checked
* @return <code>true</code> if in time range
*/
public boolean isWithinRange(final Duration duration) {
return duration.compareTo(min) > 0 && duration.compareTo(max) < 0;
return duration.compareTo(min) >= 0 && duration.compareTo(max) <= 0;
}
}

View File

@@ -24,10 +24,10 @@ public interface AmqpSenderService {
*
* @param message
* the amqp message
* @param uri
* @param replyTo
* the reply to uri
*/
void sendMessage(Message message, URI uri);
void sendMessage(Message message, URI replyTo);
/**
* Extract the exchange from the uri. Default implementation removes the

View File

@@ -59,7 +59,7 @@ public class BaseAmqpService {
*/
@SuppressWarnings("unchecked")
public <T> T convertMessage(final Message message, final Class<T> clazz) {
if (message == null || message.getBody() == null) {
if (isMessageBodyEmpty(message)) {
return null;
}
message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME,
@@ -67,6 +67,10 @@ public class BaseAmqpService {
return (T) rabbitTemplate.getMessageConverter().fromMessage(message);
}
private boolean isMessageBodyEmpty(final Message message) {
return message == null || message.getBody() == null || message.getBody().length == 0;
}
/**
* Is needed to convert a incoming message to is originally list object
* type.
@@ -79,7 +83,7 @@ public class BaseAmqpService {
*/
@SuppressWarnings("unchecked")
public <T> List<T> convertMessageList(final Message message, final Class<T> clazz) {
if (message == null || message.getBody() == null) {
if (isMessageBodyEmpty(message)) {
return Collections.emptyList();
}
message.getMessageProperties().getHeaders().put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME,
@@ -105,7 +109,7 @@ public class BaseAmqpService {
}
protected final void logAndThrowMessageError(final Message message, final String error) {
LOGGER.error("Error \"{}\" reported by message {}", error, message.getMessageProperties().getMessageId());
LOGGER.warn("Error \"{}\" reported by message: {}", error, message);
throw new IllegalArgumentException(error);
}

View File

@@ -10,6 +10,7 @@ package org.eclipse.hawkbit.amqp;
import java.net.URI;
import org.eclipse.hawkbit.util.IpUtil;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -33,8 +34,12 @@ public class DefaultAmqpSenderService implements AmqpSenderService {
}
@Override
public void sendMessage(final Message message, final URI uri) {
internalAmqpTemplate.send(extractExchange(uri), null, message);
public void sendMessage(final Message message, final URI replyTo) {
if (!IpUtil.isAmqpUri(replyTo)) {
return;
}
internalAmqpTemplate.send(extractExchange(replyTo), null, message);
}
}

View File

@@ -67,6 +67,10 @@
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>

View File

@@ -259,7 +259,7 @@ public class SoftwareManagement {
}
/**
* retrieves {@link SoftwareModule}s by their name AND version.
* retrieves {@link SoftwareModule} by their name AND version AND type..
*
* @param name
* of the {@link SoftwareModule}

View File

@@ -52,7 +52,7 @@ import org.eclipse.persistence.annotations.CascadeOnDelete;
@NamedEntityGraph(name = "Action.all", attributeNodes = { @NamedAttributeNode("distributionSet"),
@NamedAttributeNode(value = "target", subgraph = "target.ds") }, subgraphs = @NamedSubgraph(name = "target.ds", attributeNodes = @NamedAttributeNode("assignedDistributionSet"))) })
@Entity
public class Action extends TenantAwareBaseEntity implements Comparable<Action> {
public class Action extends TenantAwareBaseEntity {
private static final long serialVersionUID = 1L;
/**
@@ -198,14 +198,6 @@ public class Action extends TenantAwareBaseEntity implements Comparable<Action>
this.rollout = rollout;
}
@Override
public int compareTo(final Action o) {
if (super.getId() == null || o == null || o.getId() == null) {
return 0;
}
return super.getId().compareTo(o.getId());
}
/**
* checks if the {@link #forcedTime} is hit by the given
* {@code hitTimeMillis}, by means if the given milliseconds are greater
@@ -254,26 +246,6 @@ public class Action extends TenantAwareBaseEntity implements Comparable<Action>
return "Action [distributionSet=" + distributionSet + ", getId()=" + getId() + "]";
}
@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 Action)) {
return false;
}
return true;
}
/**
* Action status as reported by the controller.
*

View File

@@ -140,24 +140,4 @@ public class ActionStatus extends TenantAwareBaseEntity {
this.status = status;
}
@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 ActionStatus)) {
return false;
}
return true;
}
}

View File

@@ -53,24 +53,4 @@ public abstract class Artifact extends TenantAwareBaseEntity {
public void setSize(final Long size) {
this.size = size;
}
@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 Artifact)) {
return false;
}
return true;
}
}

View File

@@ -108,6 +108,11 @@ public abstract class BaseEntity implements Serializable, Identifiable<Long> {
return optLockRevision;
}
// for test purposes only
void setOptLockRevision(final long optLockRevision) {
this.optLockRevision = optLockRevision;
}
@Override
public Long getId() {
return id;
@@ -135,6 +140,7 @@ public abstract class BaseEntity implements Serializable, Identifiable<Long> {
int result = 1;
result = prime * result + (id == null ? 0 : id.hashCode());
result = prime * result + (int) (optLockRevision ^ optLockRevision >>> 32);
result = prime * result + this.getClass().getName().hashCode();
return result;
}
@@ -154,7 +160,7 @@ public abstract class BaseEntity implements Serializable, Identifiable<Long> {
if (obj == null) {
return false;
}
if (!(obj instanceof BaseEntity)) {
if (!(this.getClass().isInstance(obj))) {
return false;
}
final BaseEntity other = (BaseEntity) obj;

View File

@@ -150,26 +150,6 @@ public class DistributionSet extends NamedVersionedEntity {
return actions;
}
@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 DistributionSet)) {
return false;
}
return true;
}
public boolean isRequiredMigrationStep() {
return requiredMigrationStep;
}

View File

@@ -285,24 +285,4 @@ public class DistributionSetType extends NamedEntity {
return "DistributionSetType [key=" + key + ", isDeleted()=" + isDeleted() + ", getId()=" + getId() + "]";
}
@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 DistributionSetType)) {
return false;
}
return true;
}
}

View File

@@ -73,24 +73,4 @@ public class ExternalArtifactProvider extends NamedEntity {
this.defaultSuffix = defaultSuffix;
}
@Override
public int hashCode() { // NOSONAR - as this is generated
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 ExternalArtifactProvider)) {
return false;
}
return true;
}
}

View File

@@ -60,24 +60,4 @@ public abstract class NamedEntity extends TenantAwareBaseEntity {
public void setName(final String name) {
this.name = name;
}
@Override
public int hashCode() { // NOSONAR - as this is generated
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 NamedEntity)) {
return false;
}
return true;
}
}

View File

@@ -47,25 +47,4 @@ public abstract class NamedVersionedEntity extends NamedEntity {
public void setVersion(final String version) {
this.version = version;
}
@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 NamedVersionedEntity)) {
return false;
}
return true;
}
}

View File

@@ -231,24 +231,4 @@ public class Rollout extends NamedEntity {
*/
ERROR_STARTING;
}
@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 Rollout)) {
return false;
}
return true;
}
}

View File

@@ -476,25 +476,4 @@ public class RolloutGroup extends NamedEntity {
return this;
}
}
@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 RolloutGroup)) {
return false;
}
return true;
}
}

View File

@@ -233,26 +233,6 @@ public class SoftwareModule extends NamedVersionedEntity {
+ ", revision=" + getOptLockRevision() + ", Id=" + getId() + ", type=" + getType().getName() + "]";
}
@Override
public int hashCode() { // NOSONAR - as this is generated
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 SoftwareModule)) {
return false;
}
return true;
}
/**
* @return the assignedTo
*/

View File

@@ -114,24 +114,4 @@ public class SoftwareModuleType extends NamedEntity {
public String toString() {
return "SoftwareModuleType [key=" + key + ", getName()=" + getName() + ", getId()=" + getId() + "]";
}
@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 SoftwareModuleType)) {
return false;
}
return true;
}
}

View File

@@ -56,24 +56,4 @@ public abstract class Tag extends NamedEntity implements Identifiable<Long> {
public String toString() {
return "Tag [getOptLockRevision()=" + getOptLockRevision() + ", getId()=" + getId() + "]";
}
@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 Tag)) {
return false;
}
return true;
}
}

View File

@@ -131,31 +131,6 @@ public class Target extends NamedEntity implements Persistable<Long> {
securityToken = null;
}
/**
* Note: For Target we extended the general strategy by adding controllerId
* as well.
*
* @see org.eclipse.hawkbit.repository.model.BaseEntity#equals(java.lang.Object)
*/
@Override
public boolean equals(final Object obj) {// NOSONAR - as this is generated
if (obj == null) {
return false;
}
if (!(obj instanceof Target)) {
return false;
}
final Target other = (Target) obj;
if (controllerId == null) {
if (other.controllerId != null) {
return false;
}
} else if (!controllerId.equals(other.controllerId)) {
return false;
}
return true;
}
public DistributionSet getAssignedDistributionSet() {
return assignedDistributionSet;
}
@@ -168,14 +143,6 @@ public class Target extends NamedEntity implements Persistable<Long> {
return tags;
}
@Override
public int hashCode() { // NOSONAR - as this is generated
final int prime = 31;
int result = 1;
result = prime * result + (controllerId == null ? 0 : controllerId.hashCode());
return result;
}
public void setAssignedDistributionSet(final DistributionSet assignedDistributionSet) {
this.assignedDistributionSet = assignedDistributionSet;
}

View File

@@ -55,24 +55,4 @@ public class TargetFilterQuery extends TenantAwareBaseEntity {
public void setQuery(final String query) {
this.query = query;
}
@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 TargetFilterQuery)) {
return false;
}
return true;
}
}

View File

@@ -99,9 +99,6 @@ public abstract class TenantAwareBaseEntity extends BaseEntity {
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof TenantAwareBaseEntity)) {
return false;
}
final TenantAwareBaseEntity other = (TenantAwareBaseEntity) obj;
if (tenant == null) {
if (other.tenant != null) {

View File

@@ -52,54 +52,20 @@ public class TenantConfiguration extends TenantAwareBaseEntity implements Serial
}
/**
* @return the key
*/
public String getKey() {
return key;
}
/**
* @param key
* the key to set
*/
public void setKey(final String key) {
this.key = key;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @param value
* the value to set
*/
public void setValue(final String value) {
this.value = value;
}
@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 TenantConfiguration)) {
return false;
}
return true;
}
}

View File

@@ -18,6 +18,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.eclipse.hawkbit.Constants;
@@ -386,7 +387,7 @@ public class DeploymentManagementTest extends AbstractIntegrationTest {
.createTargets(TestDataUtil.buildTargetFixtures(10, myCtrlIDPref, "first description"));
final String myDeployedCtrlIDPref = "myDeployedCtrlID";
final List<Target> savedDeployedTargets = targetManagement
List<Target> savedDeployedTargets = targetManagement
.createTargets(TestDataUtil.buildTargetFixtures(20, myDeployedCtrlIDPref, "first description"));
final DistributionSet ds = TestDataUtil.generateDistributionSet("", softwareManagement,
@@ -399,6 +400,10 @@ public class DeploymentManagementTest extends AbstractIntegrationTest {
final Iterable<Target> allFoundTargets = targetManagement.findTargetsAll(pageReq).getContent();
// get final updated version of targets
savedDeployedTargets = targetManagement.findTargetByControllerID(
savedDeployedTargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
assertThat(allFoundTargets).as("founded targets are wrong").containsAll(savedDeployedTargets)
.containsAll(savedNakedTargets);
assertThat(savedDeployedTargets).as("saved target are wrong")
@@ -602,8 +607,12 @@ public class DeploymentManagementTest extends AbstractIntegrationTest {
.assignDistributionSet(dsA, deployResWithDsB.getDeployedTargets()).getAssignedTargets();
actionRepository.findByDistributionSet(pageRequest, dsA).getContent().get(1);
assertThat(deployed2DS).as("deployed ds is wrong").containsAll(deployResWithDsB.getDeployedTargets());
assertThat(deployed2DS).as("deployed ds is wrong").hasSameSizeAs(deployResWithDsB.getDeployedTargets());
// get final updated version of targets
final List<Target> deployResWithDsBTargets = targetManagement.findTargetByControllerID(deployResWithDsB
.getDeployedTargets().stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
assertThat(deployed2DS).as("deployed ds is wrong").containsAll(deployResWithDsBTargets);
assertThat(deployed2DS).as("deployed ds is wrong").hasSameSizeAs(deployResWithDsBTargets);
for (final Target t_ : deployed2DS) {
final Target t = targetManagement.findTargetByControllerID(t_.getControllerId());

View File

@@ -109,6 +109,14 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
both.add(TargetUpdateStatus.UNKNOWN);
both.add(TargetUpdateStatus.PENDING);
// get final updated version of targets
targAs = targetManagement.findTargetByControllerID(
targAs.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
targBs = targetManagement.findTargetByControllerID(
targBs.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
targCs = targetManagement.findTargetByControllerID(
targCs.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
// try to find several targets with different filter settings
verifyThatRepositoryContains400Targets();
verifyThat200TargetsHaveTagD(targTagW, concat(targBs, targCs));
@@ -708,11 +716,14 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
final DistributionSet assignedSet = TestDataUtil.generateDistributionSet("", softwareManagement,
distributionSetManagement);
targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned"));
final List<Target> assignedtargets = targetManagement
.createTargets(TestDataUtil.generateTargets(10, "assigned"));
List<Target> assignedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned"));
deploymentManagement.assignDistributionSet(assignedSet, assignedtargets);
// get final updated version of targets
assignedtargets = targetManagement.findTargetByControllerID(
assignedtargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
assertThat(targetManagement.findTargetByAssignedDistributionSet(assignedSet.getId(), pageReq))
.as("Contains the assigned targets").containsAll(assignedtargets)
.as("and that means the following expected amount").hasSize(10);
@@ -727,8 +738,7 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
final DistributionSet installedSet = TestDataUtil.generateDistributionSet("another", softwareManagement,
distributionSetManagement);
targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned"));
final List<Target> assignedtargets = targetManagement
.createTargets(TestDataUtil.generateTargets(10, "assigned"));
List<Target> assignedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned"));
// set on installed and assign another one
deploymentManagement.assignDistributionSet(installedSet, assignedtargets).getActions().forEach(actionId -> {
@@ -739,11 +749,13 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
});
deploymentManagement.assignDistributionSet(assignedSet, assignedtargets);
assignedtargets = targetManagement.findTargetByControllerID(
assignedtargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
assertThat(targetManagement.findTargetByAssignedDistributionSet(assignedSet.getId(),
TargetSpecifications.hasInstalledDistributionSet(installedSet.getId()), pageReq))
.as("Contains the assigned targets").containsAll(assignedtargets)
.as("and that means the following expected amount").hasSize(10);
}
@Test
@@ -754,8 +766,7 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
final DistributionSet installedSet = TestDataUtil.generateDistributionSet("another", softwareManagement,
distributionSetManagement);
targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned"));
final List<Target> installedtargets = targetManagement
.createTargets(TestDataUtil.generateTargets(10, "assigned"));
List<Target> installedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned"));
// set on installed and assign another one
deploymentManagement.assignDistributionSet(installedSet, installedtargets).getActions().forEach(actionId -> {
@@ -766,6 +777,10 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
});
deploymentManagement.assignDistributionSet(assignedSet, installedtargets);
// get final updated version of targets
installedtargets = targetManagement.findTargetByControllerID(
installedtargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
assertThat(targetManagement.findTargetByInstalledDistributionSet(installedSet.getId(), pageReq))
.as("Contains the assigned targets").containsAll(installedtargets)
.as("and that means the following expected amount").hasSize(10);
@@ -780,8 +795,7 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
final DistributionSet installedSet = TestDataUtil.generateDistributionSet("another", softwareManagement,
distributionSetManagement);
targetManagement.createTargets(TestDataUtil.generateTargets(10, "unassigned"));
final List<Target> installedtargets = targetManagement
.createTargets(TestDataUtil.generateTargets(10, "assigned"));
List<Target> installedtargets = targetManagement.createTargets(TestDataUtil.generateTargets(10, "assigned"));
// set on installed and assign another one
deploymentManagement.assignDistributionSet(installedSet, installedtargets).getActions().forEach(actionId -> {
@@ -792,6 +806,10 @@ public class TargetManagementSearchTest extends AbstractIntegrationTest {
});
deploymentManagement.assignDistributionSet(assignedSet, installedtargets);
// get final updated version of targets
installedtargets = targetManagement.findTargetByControllerID(
installedtargets.stream().map(target -> target.getControllerId()).collect(Collectors.toList()));
assertThat(targetManagement.findTargetByInstalledDistributionSet(installedSet.getId(),
TargetSpecifications.hasAssignedDistributionSet(assignedSet.getId()), pageReq))
.as("Contains the assigned targets").containsAll(installedtargets)

View File

@@ -0,0 +1,102 @@
/**
* 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.model;
import static org.fest.assertions.api.Assertions.assertThat;
import org.eclipse.hawkbit.AbstractIntegrationTest;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
@Features("Unit Tests - Repository")
@Stories("Repository Model")
public class ModelEqualsHashcodeTest extends AbstractIntegrationTest {
@Test
@Description("Verfies that different objects even with identical primary key, version and tenant "
+ "return different hash codes.")
public void differentEntitiesReturnDifferentHashCodes() {
assertThat(new Action().hashCode()).as("action should have different hashcode than action status")
.isNotEqualTo(new ActionStatus().hashCode());
assertThat(new DistributionSet().hashCode())
.as("Distribution set should have different hashcode than software module")
.isNotEqualTo(new SoftwareModule().hashCode());
assertThat(new DistributionSet().hashCode())
.as("Distribution set should have different hashcode than action status")
.isNotEqualTo(new ActionStatus().hashCode());
assertThat(new DistributionSetType().hashCode())
.as("Distribution set type should have different hashcode than action status")
.isNotEqualTo(new ActionStatus().hashCode());
}
@Test
@Description("Verfies that different object even with identical primary key, version and tenant "
+ "are not equal.")
public void differentEntitiesAreNotEqual() {
assertThat(new Action().equals(new ActionStatus())).as("action equals action status").isFalse();
assertThat(new DistributionSet().equals(new SoftwareModule())).as("Distribution set equals software module")
.isFalse();
assertThat(new DistributionSet().equals(new ActionStatus())).as("Distribution set equals action status")
.isFalse();
assertThat(new DistributionSetType().equals(new ActionStatus()))
.as("Distribution set type equals action status").isFalse();
}
@Test
@Description("Verfies that updated entities are not equal.")
public void changedEntitiesAreNotEqual() {
final SoftwareModuleType type = softwareManagement
.createSoftwareModuleType(new SoftwareModuleType("test", "test", "test", 1));
assertThat(type).as("persited entity is not equal to regular object")
.isNotEqualTo(new SoftwareModuleType("test", "test", "test", 1));
type.setDescription("another");
final SoftwareModuleType updated = softwareManagement.updateSoftwareModuleType(type);
assertThat(type).as("Changed entity is not equal to the previous version").isNotEqualTo(updated);
}
@Test
@Description("Verify that no proxy of the entity manager has an influence on the equals or hashcode result.")
public void managedEntityIsEqualToUnamangedObjectWithSameKey() {
final SoftwareModuleType type = softwareManagement
.createSoftwareModuleType(new SoftwareModuleType("test", "test", "test", 1));
final SoftwareModuleType mock = new SoftwareModuleType("test", "test", "test", 1);
mock.setId(type.getId());
mock.setOptLockRevision(type.getOptLockRevision());
mock.setTenant(type.getTenant());
assertThat(type).as("managed entity is equal to regular object with same content").isEqualTo(mock);
assertThat(type.hashCode()).as("managed entity has same hash code as regular object with same content")
.isEqualTo(mock.hashCode());
}
@Test
@Description("Verfies that updated entities do not have the same hashcode.")
public void updatedEntitiesHaveDifferentHashcodes() {
final SoftwareModuleType type = softwareManagement
.createSoftwareModuleType(new SoftwareModuleType("test", "test", "test", 1));
assertThat(type.hashCode()).as("persited entity does not have same hashcode as regular object")
.isNotEqualTo(new SoftwareModuleType("test", "test", "test", 1).hashCode());
final int beforeChange = type.hashCode();
type.setDescription("another");
assertThat(type.hashCode())
.as("Changed entity has no different hashcode than the previous version until updated in repository")
.isEqualTo(beforeChange);
final SoftwareModuleType updated = softwareManagement.updateSoftwareModuleType(type);
assertThat(type.hashCode()).as("Updated entity has different hashcode than the previous version")
.isNotEqualTo(updated.hashCode());
}
}

View File

@@ -24,7 +24,6 @@
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>

View File

@@ -809,7 +809,7 @@ public final class HawkbitCommonUtil {
public static boolean isDuplicate(final String name, final String version, final String type) {
final SoftwareManagement swMgmtService = SpringContextHelper.getBean(SoftwareManagement.class);
final SoftwareModule swModule = swMgmtService.findSoftwareModuleByNameAndVersion(name, version,
swMgmtService.findSoftwareModuleTypeByKey(type));
swMgmtService.findSoftwareModuleTypeByName(type));
boolean duplicate = false;
if (swModule != null) {
duplicate = true;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -84,6 +84,7 @@
<!-- Vaadin versions - END -->
<!-- Misc libraries versions - START -->
<validation-api.version>1.1.0.Final</validation-api.version>
<fest-assert.version>1.4</fest-assert.version>
<org.easytesting.version>2.0M10</org.easytesting.version>
<allure.version>1.4.22</allure.version>
@@ -419,6 +420,11 @@
</dependency>
<!-- Misc -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation-api.version}</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>