diff --git a/README.md b/README.md
index 1a33e0c60..bc00c5c8d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
Build: [](https://circleci.com/gh/eclipse/hawkbit)
+
+
# Eclipse.IoT hawkBit - Update Server
[hawkBit](https://projects.eclipse.org/projects/iot.hawkbit) is an domain independent back end solution for rolling out software updates to constrained edge devices as well as more powerful controllers and gateways connected to IP based networking infrastructure.
diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java
index 0a696fdb6..472c161ff 100644
--- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java
+++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/repository/TargetFields.java
@@ -64,7 +64,12 @@ public enum TargetFields implements FieldNameProvider {
/**
* The tags field.
*/
- TAG("tags.name");
+ TAG("tags.name"),
+
+ /**
+ * Last time the target or DMF client polled.
+ */
+ LASTCONTROLLERREQUESTAT("targetInfo.lastTargetQuery");
private final String fieldName;
private List subEntityAttribues;
diff --git a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java
index a528438bb..f647106af 100644
--- a/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java
+++ b/hawkbit-mgmt-resource/src/test/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtTargetResourceTest.java
@@ -8,12 +8,14 @@
*/
package org.eclipse.hawkbit.mgmt.rest.resource;
+import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.notNullValue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@@ -33,7 +35,6 @@ import org.eclipse.hawkbit.exception.SpServerError;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.repository.ActionFields;
-import org.eclipse.hawkbit.repository.ActionStatusFields;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.jpa.model.JpaTarget;
import org.eclipse.hawkbit.repository.jpa.model.JpaTargetInfo;
@@ -90,6 +91,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
private static final String JSON_PATH_FIELD_CONTENT = ".content";
private static final String JSON_PATH_FIELD_SIZE = ".size";
private static final String JSON_PATH_FIELD_TOTAL = ".total";
+ private static final String JSON_PATH_FIELD_LAST_REQUEST_AT = ".lastControllerRequestAt";
// target
// $.field
@@ -101,6 +103,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
private static final String JSON_PATH_ID = JSON_PATH_ROOT + JSON_PATH_FIELD_ID;
private static final String JSON_PATH_CONTROLLERID = JSON_PATH_ROOT + JSON_PATH_FIELD_CONTROLLERID;
private static final String JSON_PATH_DESCRIPTION = JSON_PATH_ROOT + JSON_PATH_FIELD_DESCRIPTION;
+ private static final String JSON_PATH_LAST_REQUEST_AT = JSON_PATH_ROOT + JSON_PATH_FIELD_LAST_REQUEST_AT;
@Test
@Description("Ensures that actions list is in exptected order.")
@@ -425,6 +428,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
.andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].controllerId", equalTo(idA)))
.andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].createdBy", equalTo("bumlux")))
.andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].updateStatus", equalTo("unknown")))
+ .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].lastControllerRequestAt", notNullValue()))
// idB
.andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0]._links.self.href",
equalTo(linksHrefPrefix + idB)))
@@ -433,6 +437,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
.andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0].controllerId", equalTo(idB)))
.andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0].createdBy", equalTo("bumlux")))
.andExpect(jsonPath("$content.[?(@.name==" + idB + ")][0].updateStatus", equalTo("unknown")))
+ .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].lastControllerRequestAt", notNullValue()))
// idC
.andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0]._links.self.href",
equalTo(linksHrefPrefix + idC)))
@@ -440,7 +445,8 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
.andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].description", equalTo(idC)))
.andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].controllerId", equalTo(idC)))
.andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].createdBy", equalTo("bumlux")))
- .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].updateStatus", equalTo("unknown")));
+ .andExpect(jsonPath("$content.[?(@.name==" + idC + ")][0].updateStatus", equalTo("unknown")))
+ .andExpect(jsonPath("$content.[?(@.name==" + idA + ")][0].lastControllerRequestAt", notNullValue()));
}
@Test
@@ -518,7 +524,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
// create first a target which can be retrieved by rest interface
final String knownControllerId = "1";
final String knownName = "someName";
- createSingleTarget(knownControllerId, knownName);
+ final Target target = createSingleTarget(knownControllerId, knownName);
final String hrefPrefix = "http://localhost/rest/v1/targets/" + knownControllerId + "/";
// test
mvc.perform(get(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/" + knownControllerId))
@@ -526,6 +532,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
.andExpect(jsonPath(JSON_PATH_NAME, equalTo(knownName)))
.andExpect(jsonPath(JSON_PATH_CONTROLLERID, equalTo(knownControllerId)))
.andExpect(jsonPath(JSON_PATH_DESCRIPTION, equalTo(TARGET_DESCRIPTION_TEST)))
+ .andExpect(jsonPath(JSON_PATH_LAST_REQUEST_AT, equalTo(target.getTargetInfo().getLastTargetQuery())))
.andExpect(jsonPath("$.pollStatus", hasKey("lastRequestAt")))
.andExpect(jsonPath("$.pollStatus", hasKey("nextExpectedRequestAt")))
.andExpect(jsonPath("$.pollStatus.overdue", equalTo(false)))
@@ -1075,8 +1082,6 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
private List generateTargetWithTwoUpdatesWithOneOverride(final String knownTargetId)
throws InterruptedException {
- final PageRequest pageRequest = new PageRequest(0, 100, Direction.ASC, ActionStatusFields.ID.getFieldName());
-
Target target = entityFactory.generateTarget(knownTargetId);
target = targetManagement.createTarget(target);
final List targets = new ArrayList<>();
@@ -1122,7 +1127,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
@Test
public void assignDistributionSetToTarget() throws Exception {
- final Target target = targetManagement.createTarget(entityFactory.generateTarget("fsdfsd"));
+ targetManagement.createTarget(entityFactory.generateTarget("fsdfsd"));
final DistributionSet set = testdataFactory.createDistributionSet("one");
mvc.perform(post(MgmtRestConstants.TARGET_V1_REQUEST_MAPPING + "/fsdfsd/assignedDS")
@@ -1299,19 +1304,20 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
+ "\"}]";
}
- private void createSingleTarget(final String controllerId, final String name) {
+ private Target createSingleTarget(final String controllerId, final String name) {
final Target target = entityFactory.generateTarget(controllerId);
target.setName(name);
target.setDescription(TARGET_DESCRIPTION_TEST);
targetManagement.createTarget(target);
- controllerManagament.updateLastTargetQuery(controllerId, null);
+ return controllerManagament.updateLastTargetQuery(controllerId, null);
}
/**
- * creating targets with the given amount by setting name, id etc from the
- * alphabet [a-z] using the ASCII.
- *
+ * Creating targets with the given amount by setting name, id etc from the
+ * alphabet [a-z] using ASCII.
+ *
* @param amount
+ * The number of targets to create
*/
private void createTargetsAlphabetical(final int amount) {
char character = 'a';
@@ -1320,15 +1326,15 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
final Target target = entityFactory.generateTarget(str);
target.setName(str);
target.setDescription(str);
- final Target savedTarget = targetManagement.createTarget(target);
- assertThat(savedTarget.getLastModifiedBy()).isNotNull();
+ targetManagement.createTarget(target);
+ controllerManagament.updateLastTargetQuery(str, null);
character++;
}
}
/**
- * helper method to give feedback mark an target IN_SNCY
- *
+ * helper method to give feedback mark an target IN_SYNC
+ *
*/
private void feedbackToByInSync(final Long actionId) {
final Action action = deploymentManagement.findAction(actionId);
@@ -1339,7 +1345,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
/**
* helper method to create a target and start an action on it.
- *
+ *
* @return The targetid of the created target.
*/
private Target createTargetAndStartAction() {
@@ -1348,7 +1354,7 @@ public class MgmtTargetResourceTest extends AbstractRestIntegrationTest {
final Target tA = targetManagement
.createTarget(testdataFactory.generateTarget("target-id-A", "first description"));
// assign a distribution set so we get an active update action
- deploymentManagement.assignDistributionSet(dsA, Lists.newArrayList(tA));
+ deploymentManagement.assignDistributionSet(dsA, newArrayList(tA));
// verify active action
final Slice actionsByTarget = deploymentManagement.findActionsByTarget(new PageRequest(0, 100), tA);
assertThat(actionsByTarget.getContent()).hasSize(1);
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java
index 84e069538..3b7f77b47 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaSystemManagement.java
@@ -31,8 +31,6 @@ import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.cache.annotation.CacheEvict;
-import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.data.jpa.repository.Modifying;
@@ -214,7 +212,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
}
@Override
- @CacheEvict(value = { "tenantMetadata" }, key = "#tenant.toUpperCase()", cacheManager = "directCacheManager")
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Modifying
public void deleteTenant(final String tenant) {
@@ -241,7 +238,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
}
@Override
- @Cacheable(value = "tenantMetadata", keyGenerator = "tenantKeyGenerator", cacheManager = "directCacheManager")
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Modifying
public TenantMetaData getTenantMetadata() {
@@ -276,7 +272,6 @@ public class JpaSystemManagement implements CurrentTenantCacheKeyGenerator, Syst
}
@Override
- @CachePut(value = "tenantMetadata", key = "#metaData.tenant.toUpperCase()", cacheManager = "directCacheManager")
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Modifying
public TenantMetaData updateTenantMetadata(final TenantMetaData metaData) {
diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java
index 2cccd655b..cdac51614 100644
--- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java
+++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLTargetFieldTest.java
@@ -37,6 +37,8 @@ import ru.yandex.qatools.allure.annotations.Stories;
@Features("Component Tests - Repository")
@Stories("RSQL filter target")
public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
+ private static final long LAST_TARGET_QUERY = 10000;
+ private static final long LAST_TARGET_QUERY_SMALLER = 1000;
@Before
public void seuptBeforeTest() {
@@ -48,14 +50,16 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
final TargetInfo targetInfo = target.getTargetInfo();
targetInfo.getControllerAttributes().put("revision", "1.1");
((JpaTargetInfo) target.getTargetInfo()).setUpdateStatus(TargetUpdateStatus.PENDING);
-
+ ((JpaTargetInfo) target.getTargetInfo()).setLastTargetQuery(LAST_TARGET_QUERY);
targetManagement.createTarget(target);
+
final JpaTarget target2 = new JpaTarget("targetId1234");
target2.setDescription("targetId1234");
- final TargetInfo targetInfo2 = new JpaTargetInfo(target2);
+ final TargetInfo targetInfo2 = target2.getTargetInfo();
targetInfo2.getControllerAttributes().put("revision", "1.2");
- target2.setTargetInfo(targetInfo2);
+ ((JpaTargetInfo) target2.getTargetInfo()).setLastTargetQuery(LAST_TARGET_QUERY_SMALLER);
targetManagement.createTarget(target2);
+
targetManagement.createTarget(new JpaTarget("targetId1235"));
targetManagement.createTarget(new JpaTarget("targetId1236"));
@@ -166,6 +170,17 @@ public class RSQLTargetFieldTest extends AbstractJpaIntegrationTest {
assertRSQLQuery(TargetFields.TAG.name() + "=out=(Tag1,notexist)", 0);
}
+ @Test
+ @Description("Test filter target by lastTargetQuery")
+ public void testFilterByLastTargetQuery() {
+ assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "==" + LAST_TARGET_QUERY, 1);
+ assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "!=" + LAST_TARGET_QUERY, 1);
+ assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + LAST_TARGET_QUERY, 1);
+ assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=lt=" + LAST_TARGET_QUERY_SMALLER, 0);
+ assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=gt=" + LAST_TARGET_QUERY_SMALLER, 1);
+ assertRSQLQuery(TargetFields.LASTCONTROLLERREQUESTAT.name() + "=gt=" + LAST_TARGET_QUERY, 0);
+ }
+
private void assertRSQLQuery(final String rsqlParam, final long expcetedTargets) {
final Page findTargetPage = targetManagement.findTargetsAll(rsqlParam, new PageRequest(0, 100));
final long countTargetsAll = findTargetPage.getTotalElements();
diff --git a/hawkbit_logo.png b/hawkbit_logo.png
new file mode 100644
index 000000000..3fe796127
Binary files /dev/null and b/hawkbit_logo.png differ
diff --git a/pom.xml b/pom.xml
index 5995b8faf..e699db0f1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -68,7 +68,7 @@
2.5.5
5.2.4.Final
1.2.0.RELEASE
- 1.6.0.RELEASE
+ 1.6.1.RELEASE
3.6.2
0.18.0.RELEASE