diff --git a/.gitignore b/.gitignore
index 9f1bace10..487dc5a4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,10 +8,17 @@ pom.xml.releaseBackup
release.properties
/target
-/FROST-Server.MQTT.Moquette/target/
-/FROST-Server.SQL.PGLong/target/
+/FROST-Server.Core/target/
/FROST-Server.SQL/target/
+/FROST-Server.SQL.PGLong/target/
/FROST-Server.SQL.PGString/target/
-/FROST-Server.Core/target/
-/FROST-Server.HTTP/target/
/FROST-Server.SQL.PGUuid/target/
+/FROST-Server.HTTP/target/
+/FROST-Server.HTTP.Common/target/
+/FROST-Server.MQTT/target/
+/FROST-Server.MQTT.Moquette/target/
+/FROST-Server.MQTTP/target/
+
+FROST-Server.HTTP/keycloak.json
+FROST-Server.MQTT/FrostMqtt.properties
+logs
diff --git a/.travis.yml b/.travis.yml
index 80114475a..3f51944b4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,21 +5,71 @@ jdk:
branches:
only:
- master
+ - actuation
- "/^v[0-9]+(\\.[0-9]+)+/"
-after_success:
-- test "${TRAVIS_PULL_REQUEST}" == "false" && test "${TRAVIS_TAG}" != "" && mvn deploy --settings travis-settings.xml
-- mvn dockerfile:build -pl FROST-Server.HTTP
-- mvn dockerfile:tag@tag-version -pl FROST-Server.HTTP
-- mvn dockerfile:push@push-latest -Ddockerfile.useMavenSettingsForAuth=true -pl FROST-Server.HTTP --settings travis-settings.xml
-- mvn dockerfile:push@push-version -Ddockerfile.useMavenSettingsForAuth=true -pl FROST-Server.HTTP --settings travis-settings.xml
+install:
+ - wget http://storage.googleapis.com/kubernetes-helm/helm-${HELM_VERSION}-linux-amd64.tar.gz -O /tmp/helm.tar.gz
+ - tar xzf /tmp/helm.tar.gz -C /tmp --strip-components=1
+ - chmod +x /tmp/helm
+ - /tmp/helm init --client-only
+ - chmod +x ./helm/build.sh
+ - chmod +x ./helm/upload.sh
+ - chmod +x ./travis-deploy.sh
+ - chmod +x ./travis-deploy-docker.sh
+ - chmod +x ./setBranchVariable.sh
+ - source ./setBranchVariable.sh
+
+stages:
+ - compile
+ - test
+ - deploy
+
+jobs:
+ include:
+ - stage: compile
+ name: "Maven build"
+ script:
+ - mvn package
+ - mvn org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar
+ - stage: compile
+ name: "Helm build"
+ script:
+ - ./helm/build.sh
+ - stage: test
+ name: "Maven test"
+ script:
+ - mvn test
+ - stage: deploy
+ name: "Deploy Docker"
+ script:
+ - ./travis-deploy-docker.sh
+ - stage: deploy
+ name: "Deploy helm chart"
+ script:
+ - ./helm/upload.sh
+ - stage: deploy
+ name: "Maven deploy version"
+ script:
+ - ./travis-deploy.sh
+
sudo: required
services:
- docker
+addons:
+ sonarcloud:
+ organization: "fraunhofer-iosb"
+
+cache:
+ directories:
+ - '$HOME/.m2/repository'
+ - '$HOME/.sonar/cache'
+
env:
global:
+ - HELM_VERSION="v2.9.1"
# travis encrypt BINTRAY_USER=[username]
- secure: pfl5pPDTyRB20+dX2PvVGChQoAVRYKiMefXZWX+tvosw40HR/XJ0cL+8skTVe6rJklKvnanWDUZUTJg1bRlq5AygHdF+g76dejaD95EcoMz/cecbxlXyAT+CISEdgzhuTpaVDEP653SCCQlUNyrJQEaROmfc/GxY9nQENZTeLxjQde+/JM1apktH0uIKvBfK7sZrdy9wNjO99fZqD3S6gVRdLLos/jha/f1rpcktnqxnF8Q6OQpmqGUiuuloIh4IYBQg3xcl/1tPauhnVqCdeMrYdLIeLEIM4U405UdOfPthvQkMHfrIkdA0ZZTaX8bgdDMebJc3+FtZSPL42PBC5O6/dQPoyp9iU86wbUnxX46pkQVTk5NyRWul0a930QjYeINdvfvg7Zh5WgBY7l42iSogknRzh5w8LHD5TTVY2jT825inuCV8aR5NHw4jguWBzeNrK5ZrXQk/J6hVxu16obd5OZe3/yw1qStGIxAOnda0LH8Y2jdT8ZQntD+FNv7nSWdUGcGxrMyaSH7PJisBQCvh8NghAmuwfN72zVM9UiDQPelHRdeUDLpTp7laHrbRKgb1rUfRLaopeLw3ORq0EyBtML5OqKEW8QHdkrgkAEYBUClu+9JN7NmttH1XGTIE5ZWm/SBd+iENAlElCh3hjWdCbjVeDF8gDoddS+3LHBg=
# travis encrypt BINTRAY_API_KEY=[api key]
@@ -28,3 +78,5 @@ env:
- secure: P+z967jQUEzWJkAtCUMWotUr2Ft/FkKYHJmXK2/LlzsFFSB7HP+wOlxLNVMFauek1M5ZZ5jyt1s0nvmftSP4STSIfE63I05Wkjz9A5rrmG4SzUvYFF5mDOS5fa8YTNgnZhBUBP2Ip6WtVnlbbi+bxK44GJFF70ymofWAy+uEmJ+qQFf+PMYa8CS4gY3jGrV/YCY/a3fl8tL240VdjDL0Bv35MTEtMH9x3DR04mAAFlq+6cuaYq/m8eTwivNV7BcC/hz69SroWIk7RnAht6pcVT08W32hib67TXF4zt5kljxuH7hsG+trh9bZFUh2XMGXTZV0ps89WFI6/qTe0olrj++xYuRgglhhUUmpqY3npxGpsq7Z65xoK6UyInVuy+JVUHm77/QIucQY6bxpWx1NyEVUSaQpLGVXp/ABZ6n98OJcosf1e18urBVoV8F2rZYNcRLtuHwmw1rtpI2PCZOvc4ewnJy6hGKmoDa1CzK7Xj8hQ9wtKR9+0m9x7X+qZ/vrfaN7jJ7uLPfgzgZlip4mWTkFw6GSeso6iYjgv+ARHPFwfe46M3K1QzNq5CRLrn++f2r2doWBfpYtd06YYKH8JT8u/q1IFL8nrqwJ6jT22CXO06+EZV5V5ZSEtrrK9/kII81LLG4xIFyvZ5C2csVLdzGg2Mdcna+UZU6zCbGvT3g=
# travis encrypt DOCKER_PASSWORD=[username]
- secure: tMi5jaBO/iaK/Lc3x5WTXqgGfP35v4KZFvc5AD59qEETI1GmQ22e0maqq5YZfZWz5g3ZzS2irWRzKfrYln1lgx2LJ1AI4qHW5CQI0dlEj7OIxzK8FXlJz5tkovlfIHkniL5XyFc4eUSo+d878h8CyNRDoKQlGQie3rP0oaMl5r+CfhsdA4FRxWFY3xerlxUF20XDceVOc2tW7+HB7ROf/jFzlSxMqShbmHOvmcBxMYChPEv9xDsV16LJ+dHAg5H+DNBwFwaoMzFRmFTECrQD5xroo+Jn9eoDvWQ1OXJNQCRulbdZcq/rUOE7YQqjTuO3/aGocNPNH+5GUCf/nDSfweCPoBtaaZU7anWfJbzP9DwA6bQ490mBzgSas8n/ar0zgD8+sjwcghcPVPqH7+ZLXvw/GRs+FVd4eFs2iMgA8CoIGPqs20sYj1PGULCLeQnCDGujQnAfXMsmd49pRlOAnP4d5dgchETK2jf05UPX3Ou65yJght2NoRl5x+NPo8iei/nGtGIM8hSzyb0nPt6TiznYPGB5p0Fob2r23H/uyFVgKriEstYR7STCb1asKFZrARmVhYmngmsO/UX8poSj500ipSi5ymgVZZ/u6361Ghy38c1la62H+DgylPR3Of21DGlb11smfgfhggYJ/f7pMT1tV+Prjr+k9WhD8i2i2Mc=
+ # travis encrypt GITHUB_API_KEY
+ - secure: W3jIZLR8Dk/Wj3rhjT4AJrp95A070XhQXeQrKgQDjgxvnQEGa0/7a10RBhOWxD1zr8hlTfUsTVKG/lvFeVv8nIZuk1nBLalSXXwSH7LUXV6pL0Cus0eGDPP7BiEsh7E2Qey3C0kGdtGNW8wwm7qsM9ww+npis1WmhIir1AB0xYCIItc4ABcZTSKuOCxaEiVKXf9Gvu28QysANmk2H2QOhcl3xnWINJiNfJZhyoPg/eeZiNR9OpZ1XJZ6AQr/aTmvN+veRQwLq8tRA7Vp4312mlhb+FeTwO4AVp3Vvsl/OPOTxVNYuynIiDX84KAi8xx6qvpAdZrt9ZusnD6Vi9j/Ml3S81U/zXt05rlTsBRYUqKzrUe55tFQwrPu3oSHhH775kUCQ61/c38fGRAKznMze6s/nU2ohJvMq1VX2jKytybdZd7Hsesxl/th8UvEUk/NWx9faOVMcXK6mF0HQPR3wa62QcclUUwZAEbjA3TUct/8L3lfgo3VVA45AzqRX3cFe95I3CBcEEjnVe2YUenqUmWOhXVIRF/B/pcd1MCrdkgsHKmnEFUNPkYMn/E0m266qzDjs+Ag4MH+yIWE/6Cp4cs/KpLRLCHtp/3Qz7HOKjE3r1PEdD3BX3qdeK/QzcbbvtYbrgZ/T9CKJuoRYQoLaIx27b6bxsjZGdE7ypZkUng=
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8e876d2a..20a951dbc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,83 @@
+# Release Version 1.9
+Version 1.9 is not released yet.
+
+**New Features**
+* Added experimental DELETE on Collections, with filters. Allows easier data cleanup.
+ See https://github.com/opengeospatial/sensorthings/issues/44
+* Added experimental way to change the location of a Thing, without generating a
+ HistoricalLocation with a time of now(). See #66 and https://github.com/opengeospatial/sensorthings/issues/30
+
+
+# Release Version 1.8
+Version 1.8 was released on 2018-08-24.
+
+**New Features**
+* Upgraded moquette to v0.11.
+* Allow setting of the moquette persistent store path and storage class.
+* Enabling the tomcat CorsFilter to allow cross-site-scripting can be done from environment variables.
+* Added option to automatically run the liquibase database upgrade.
+
+**Bugfixes**
+* Fixed #59, incorrect nextLink when filtering on unitOfMeasurement/name.
+* Fixed `MultiDatastream.observationType` being required even though we set it automatically.
+* Prioritise `persistence_db_url` over `persistence_db_jndi_datasource`. This way there is no longer the need to add an empty environment variable `persistence_db_jndi_datasource` for the HTTP and MQTTP component when configuring using environment variables.
+* Fixed string ids in next- and selfLink not being urlEncoded.
+
+
+# Release Version 1.7
+Version 1.7 was released on 2018-07-02.
+
+**New Features**
+* Observation.result can be explicitly set to null. This is useful in cases where
+ an observation did not produce a value, but the fact that an observation was attempted
+ must still be recorded.
+* Exposed database connection options `persistence.db.conn.max`, `persistence.db.conn.idle.max`, `persistence.db.conn.idle.min`
+
+**Bugfixes**
+* Fixed #53: Query parser not Unicode aware.
+* Fixed #52: Generating FeatureOfInterest did not work for Things with multiple Location entities when some of these entities were not geoJSON.
+* Fixed the 'year' function not working on interval properties.
+
+
+# Release Version 1.6
+Version 1.6 was released on 2018-05-09.
+
+**New Features**
+* User-defined-ids. FROST-Server can not be configured to allow the user to specify the id of created enitites.
+ The new setting `persistence.idGenerationMode` has three allowed values:
+ * `ServerGeneratedOnly`: No client defined ids allowed, database generates ids.
+ * `ServerAndClientGenerated`: Both, server and client generated ids, are allowed.
+ * `ClientGeneratedOnly`: Client has to provide @iot.id to create entities.
+
+ Thanks to Marcel Köpke for the patch.
+* Improved time handling in queries. FROST-Server can now calculate with times:
+
+ ```/Observations?$filter=phenomenonTime gt now() sub duration'P1D' mul Datastream/properties/days```
+
+* Separated the MQTT and HTTP parts of the server.
+ The MQTT and HTTP parts of the server are now separated in to stand-alone programs:
+ * FROST-Server.HTTP: contains a web-app handling the HTTP part of the server.
+ * FROST-Server.MQTT: contains a java application handling the MQTT part of the server.
+ * FROST-Server.MQTTP: contains a web-app combining HTTP and MQTT, like it was before.
+
+ There can be multiple MQTT and HTTP instances using the same database, to allow for horizontal
+ scaling on a cloud infrastructure. The instances communicate over a pluggable message bus.
+* There are now three docker images:
+ * The stand-alone HTTP package: fraunhoferiosb/frost-server-http.
+ * The stand-alone MQTT package: fraunhoferiosb/frost-server-mqtt.
+ * The all-in-one package: fraunhoferiosb/frost-server.
+
+ An example configuration for docker-compose can be found as docker-compose-separated.yaml,
+ that shows how the HTTP and MQTT packages can be started separately, with an MQTT message bus
+ for communication between the HTTP and MQTT instances.
+* All configuration parameters can now be overridden using environment variables.
+
+**Bugfixes**
+* Fixed service prefix in default config file.
+* Fixed Tomcat breaking selfLinks for ids that are URLs.
+* Fixed $select not working for @iot.id, in MQTT.
+* Fixed #48: creation in Observations in MultiDatastreams using DataArray formatting fails.
+
# Release Version 1.5
Version 1.5 was released on 2018-02-15.
diff --git a/FROST-Server.Core/pom.xml b/FROST-Server.Core/pom.xml
index 37a95865f..1a0eb57a5 100644
--- a/FROST-Server.Core/pom.xml
+++ b/FROST-Server.Core/pom.xml
@@ -4,7 +4,7 @@
de.fraunhofer.iosb.ilt.FROST-Server
FROST-ServerParent
- 1.6-SNAPSHOT
+ 1.9-SNAPSHOT
../pom.xml
FROST-Server.Core
@@ -55,12 +55,27 @@
slf4j-api
${slf4j-api.version}
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ ${paho.version}
+
ch.qos.logback
logback-classic
${logback.version}
test
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
@@ -68,7 +83,7 @@
org.codehaus.mojo
javacc-maven-plugin
- 2.6
+ ${javacc-maven-plugin.version}
jjtree-javacc
@@ -81,14 +96,14 @@
net.java.dev.javacc
javacc
- 6.1.2
+ ${javacc.version}
org.apache.maven.plugins
maven-compiler-plugin
- 3.1
+ ${maven-compiler-plugin.version}
${maven.compiler.source}
${maven.compiler.target}
@@ -97,18 +112,10 @@
-
- org.apache.maven.plugins
- maven-war-plugin
- 2.3
-
- false
-
-
org.apache.maven.plugins
maven-dependency-plugin
- 2.6
+ ${maven-dependency-plugin.version}
validate
@@ -130,6 +137,32 @@
+
+ pl.project13.maven
+ git-commit-id-plugin
+ ${git-commit-id-plugin.version}
+
+
+ get-the-git-infos
+
+ revision
+
+
+
+
+ ${project.basedir}/../.git
+ git
+ false
+ true
+ ${project.build.outputDirectory}/git.json
+ json
+
+ false
+ false
+ -dirty
+
+
+
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DataArrayValue.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DataArrayValue.java
index 33c175392..d6d60b1a5 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DataArrayValue.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DataArrayValue.java
@@ -104,12 +104,7 @@ public void setDataArray(List> dataArray) {
@Override
public int hashCode() {
- int hash = 7;
- hash = 29 * hash + Objects.hashCode(this.datastream);
- hash = 29 * hash + Objects.hashCode(this.multiDatastream);
- hash = 29 * hash + Objects.hashCode(this.components);
- hash = 29 * hash + Objects.hashCode(this.dataArray);
- return hash;
+ return Objects.hash(datastream, multiDatastream, components, dataArray);
}
@Override
@@ -133,10 +128,7 @@ public boolean equals(Object obj) {
if (!Objects.equals(this.components, other.components)) {
return false;
}
- if (!Objects.equals(this.dataArray, other.dataArray)) {
- return false;
- }
- return true;
+ return Objects.equals(this.dataArray, other.dataArray);
}
public static String dataArrayIdFor(Observation observation) {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DefaultResultFormater.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DefaultResultFormater.java
index a52b59b23..fa88f9aed 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DefaultResultFormater.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/formatter/DefaultResultFormater.java
@@ -1,31 +1,32 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.formatter;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntityFormatter;
import de.fraunhofer.iosb.ilt.sta.model.Observation;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.query.Query;
-import de.fraunhofer.iosb.ilt.sta.serialize.EntityFormatter;
import de.fraunhofer.iosb.ilt.sta.util.VisibilityHelper;
import java.io.IOException;
import java.util.ArrayList;
@@ -42,9 +43,6 @@
*/
public class DefaultResultFormater implements ResultFormatter {
- public DefaultResultFormater() {
- }
-
@Override
public String format(ResourcePath path, Query query, Object result, boolean useAbsoluteNavigationLinks) {
String entityJsonString = "";
@@ -53,25 +51,25 @@ public String format(ResourcePath path, Query query, Object result, boolean useA
Entity entity = (Entity) result;
VisibilityHelper.applyVisibility(entity, path, query, useAbsoluteNavigationLinks);
- entityJsonString = new EntityFormatter().writeEntity(entity);
+ entityJsonString = EntityFormatter.writeEntity(entity);
} else if (EntitySet.class.isAssignableFrom(result.getClass())) {
EntitySet entitySet = (EntitySet) result;
- if (query.getFormat() != null && query.getFormat().equalsIgnoreCase("dataarray") && entitySet.getEntityType() == EntityType.Observation) {
- return formatDataArray(path, query, entitySet, useAbsoluteNavigationLinks);
+ if (query.getFormat() != null && query.getFormat().equalsIgnoreCase("dataarray") && entitySet.getEntityType() == EntityType.OBSERVATION) {
+ return formatDataArray(path, query, entitySet);
}
VisibilityHelper.applyVisibility(entitySet, path, query, useAbsoluteNavigationLinks);
- entityJsonString = new EntityFormatter().writeEntityCollection(entitySet);
+ entityJsonString = EntityFormatter.writeEntityCollection(entitySet);
} else if (path != null && path.isValue()) {
if (result instanceof Map) {
- entityJsonString = new EntityFormatter().writeObject(result);
+ entityJsonString = EntityFormatter.writeObject(result);
} else if (result instanceof Id) {
entityJsonString = ((Id) result).getValue().toString();
} else {
entityJsonString = result.toString();
}
} else {
- entityJsonString = new EntityFormatter().writeObject(result);
+ entityJsonString = EntityFormatter.writeObject(result);
}
} catch (IOException ex) {
Logger.getLogger(DefaultResultFormater.class.getName()).log(Level.SEVERE, null, ex);
@@ -104,37 +102,37 @@ public VisibleComponents(boolean allValue) {
}
public VisibleComponents(Set select) {
- id = select.contains(EntityProperty.Id);
- phenomenonTime = select.contains(EntityProperty.PhenomenonTime);
- result = select.contains(EntityProperty.Result);
- resultTime = select.contains(EntityProperty.ResultTime);
- resultQuality = select.contains(EntityProperty.ResultQuality);
- validTime = select.contains(EntityProperty.ValidTime);
- parameters = select.contains(EntityProperty.Parameters);
+ id = select.contains(EntityProperty.ID);
+ phenomenonTime = select.contains(EntityProperty.PHENOMENONTIME);
+ result = select.contains(EntityProperty.RESULT);
+ resultTime = select.contains(EntityProperty.RESULTTIME);
+ resultQuality = select.contains(EntityProperty.RESULTQUALITY);
+ validTime = select.contains(EntityProperty.VALIDTIME);
+ parameters = select.contains(EntityProperty.PARAMETERS);
}
public List getComponents() {
List components = new ArrayList<>();
if (id) {
- components.add(EntityProperty.Id.name);
+ components.add(EntityProperty.ID.entitiyName);
}
if (phenomenonTime) {
- components.add(EntityProperty.PhenomenonTime.name);
+ components.add(EntityProperty.PHENOMENONTIME.entitiyName);
}
if (result) {
- components.add(EntityProperty.Result.name);
+ components.add(EntityProperty.RESULT.entitiyName);
}
if (resultTime) {
- components.add(EntityProperty.ResultTime.name);
+ components.add(EntityProperty.RESULTTIME.entitiyName);
}
if (resultQuality) {
- components.add(EntityProperty.ResultQuality.name);
+ components.add(EntityProperty.RESULTQUALITY.entitiyName);
}
if (validTime) {
- components.add(EntityProperty.ValidTime.name);
+ components.add(EntityProperty.VALIDTIME.entitiyName);
}
if (parameters) {
- components.add(EntityProperty.Parameters.name);
+ components.add(EntityProperty.PARAMETERS.entitiyName);
}
return components;
}
@@ -166,7 +164,7 @@ public List fromObservation(Observation o) {
}
}
- public String formatDataArray(ResourcePath path, Query query, EntitySet entitySet, boolean useAbsoluteNavigationLinks) throws IOException {
+ public String formatDataArray(ResourcePath path, Query query, EntitySet entitySet) throws IOException {
VisibleComponents visComps;
if (query == null || query.getSelect().isEmpty()) {
visComps = new VisibleComponents(true);
@@ -178,11 +176,10 @@ public String formatDataArray(ResourcePath path, Query query, EntitySet dataArraySet = new LinkedHashMap<>();
for (Observation obs : entitySet) {
String dataArrayId = DataArrayValue.dataArrayIdFor(obs);
- DataArrayValue dataArray = dataArraySet.get(dataArrayId);
- if (dataArray == null) {
- dataArray = new DataArrayValue(path, obs, components);
- dataArraySet.put(dataArrayId, dataArray);
- }
+ DataArrayValue dataArray = dataArraySet.computeIfAbsent(
+ dataArrayId,
+ k -> new DataArrayValue(path, obs, components)
+ );
dataArray.getDataArray().add(visComps.fromObservation(obs));
}
@@ -195,8 +192,7 @@ public String formatDataArray(ResourcePath path, Query query, EntitySet .
*/
package de.fraunhofer.iosb.ilt.sta.formatter;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/EntityParser.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/EntityParser.java
similarity index 61%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/EntityParser.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/EntityParser.java
index 3ac1312de..76309d914 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/EntityParser.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/EntityParser.java
@@ -15,16 +15,19 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
-import de.fraunhofer.iosb.ilt.sta.deserialize.custom.CustomDeserializationManager;
-import de.fraunhofer.iosb.ilt.sta.deserialize.custom.CustomEntityDeserializer;
-import de.fraunhofer.iosb.ilt.sta.deserialize.custom.geojson.GeoJsonDeserializier;
import de.fraunhofer.iosb.ilt.sta.formatter.DataArrayValue;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.custom.CustomDeserializationManager;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.custom.CustomEntityChangedMessageDeserializer;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.custom.CustomEntityDeserializer;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.custom.GeoJsonDeserializier;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntitySetCamelCaseNamingStrategy;
+import de.fraunhofer.iosb.ilt.sta.messagebus.EntityChangedMessage;
import de.fraunhofer.iosb.ilt.sta.model.Datastream;
import de.fraunhofer.iosb.ilt.sta.model.FeatureOfInterest;
import de.fraunhofer.iosb.ilt.sta.model.HistoricalLocation;
@@ -37,21 +40,12 @@
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.ext.UnitOfMeasurement;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.DatastreamMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.FeatureOfInterestMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.HistoricalLocationMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.LocationMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.MultiDatastreamMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.ObservationMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.ObservedPropertyMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.SensorMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.ThingMixIn;
-import de.fraunhofer.iosb.ilt.sta.model.mixin.UnitOfMeasurementMixIn;
-import de.fraunhofer.iosb.ilt.sta.serialize.EntitySetCamelCaseNamingStrategy;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.mixin.MixinUtils;
import java.io.IOException;
import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Allows parsing of STA entities from JSON. Fails on unknown properties in the
@@ -68,37 +62,97 @@ public class EntityParser {
public static final TypeReference listOfDataArrayValue = new TypeReference>() {
// Empty by design.
};
- private final ObjectMapper mapper;
+ /**
+ * The logger for this class.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(EntityParser.class);
- public EntityParser(Class extends Id> idClass) {
+ private static ObjectMapper mainMapper;
+ private static Class extends Id> mainIdClass;
+
+ private static ObjectMapper simpleObjectMapper;
+
+ /**
+ * Get an object mapper for the given id Class. If the id class is the same
+ * as for the first call, the cached mapper is returned.
+ *
+ * @param idClass The id class to use for this mapper.
+ * @return The cached or created object mapper.
+ */
+ private static ObjectMapper getObjectMapper(Class extends Id> idClass) {
+ if (mainMapper == null) {
+ initMainObjectMapper(idClass);
+ }
+ if (mainIdClass != idClass) {
+ LOGGER.warn("Object Mapper requested with different id class. {} instead of {}", idClass, mainIdClass);
+ return createObjectMapper(idClass);
+ }
+ return mainMapper;
+ }
+
+ /**
+ * Initialise the main object mapper.
+ *
+ * @param idClass The id class to use for the main object mapper.
+ */
+ private static synchronized void initMainObjectMapper(Class extends Id> idClass) {
+ if (mainMapper != null) {
+ return;
+ }
+ mainMapper = createObjectMapper(idClass);
+ mainIdClass = idClass;
+ }
+
+ /**
+ * Create a new object mapper for the given id Class.
+ *
+ * @param idClass The id class to use for this mapper.
+ * @return The created object mapper.
+ */
+ private static ObjectMapper createObjectMapper(Class extends Id> idClass) {
GeoJsonDeserializier geoJsonDeserializier = new GeoJsonDeserializier();
- for (String encodingType : GeoJsonDeserializier.encodings) {
+ for (String encodingType : GeoJsonDeserializier.ENCODINGS) {
CustomDeserializationManager.getInstance().registerDeserializer(encodingType, geoJsonDeserializier);
}
- mapper = new ObjectMapper()
+ ObjectMapper mapper = new ObjectMapper()
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
- //mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+
mapper.setPropertyNamingStrategy(new EntitySetCamelCaseNamingStrategy());
- mapper.addMixIn(Datastream.class, DatastreamMixIn.class);
- mapper.addMixIn(MultiDatastream.class, MultiDatastreamMixIn.class);
- mapper.addMixIn(FeatureOfInterest.class, FeatureOfInterestMixIn.class);
- mapper.addMixIn(HistoricalLocation.class, HistoricalLocationMixIn.class);
- mapper.addMixIn(Location.class, LocationMixIn.class);
- mapper.addMixIn(Observation.class, ObservationMixIn.class);
- mapper.addMixIn(ObservedProperty.class, ObservedPropertyMixIn.class);
- mapper.addMixIn(Sensor.class, SensorMixIn.class);
- mapper.addMixIn(Thing.class, ThingMixIn.class);
- mapper.addMixIn(UnitOfMeasurement.class, UnitOfMeasurementMixIn.class);
+
+ MixinUtils.addMixins(mapper);
+
SimpleModule module = new SimpleModule();
module.addAbstractTypeMapping(EntitySet.class, EntitySetImpl.class);
module.addAbstractTypeMapping(Id.class, idClass);
module.addDeserializer(Location.class, new CustomEntityDeserializer(Location.class));
module.addDeserializer(FeatureOfInterest.class, new CustomEntityDeserializer(FeatureOfInterest.class));
module.addDeserializer(Sensor.class, new CustomEntityDeserializer(Sensor.class));
- // TODO Datastream.observationType supplies encodingType for Observation.result. How to deserialize content when ne Observation is inserted?
- //module.addDeserializer(Datastream.class, new CustomEntityDeserializer(Datastream.class));
+ module.addDeserializer(EntityChangedMessage.class, new CustomEntityChangedMessageDeserializer());
mapper.registerModule(module);
+ return mapper;
+ }
+
+ /**
+ * get an ObjectMapper for generic, non-STA use.
+ *
+ * @return an ObjectMapper for generic, non-STA use.
+ */
+ public static ObjectMapper getSimpleObjectMapper() {
+ if (simpleObjectMapper == null) {
+ simpleObjectMapper = new ObjectMapper()
+ .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
+ }
+ return simpleObjectMapper;
+ }
+
+ /**
+ * The objectMapper for this instance of EntityParser.
+ */
+ private final ObjectMapper mapper;
+
+ public EntityParser(Class extends Id> idClass) {
+ mapper = getObjectMapper(idClass);
}
public Datastream parseDatastream(String value) throws IOException {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeInstantDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeInstantDeserializer.java
similarity index 90%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeInstantDeserializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeInstantDeserializer.java
index 98f195edd..269dabb85 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeInstantDeserializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeInstantDeserializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
@@ -37,7 +36,7 @@ public TimeInstantDeserializer() {
}
@Override
- public TimeInstant deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
+ public TimeInstant deserialize(JsonParser jp, DeserializationContext dc) throws IOException {
return TimeInstant.parse(((JsonNode) jp.getCodec().readTree(jp)).asText());
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeIntervalDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeIntervalDeserializer.java
similarity index 90%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeIntervalDeserializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeIntervalDeserializer.java
index 70a9558f2..e71ebc140 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeIntervalDeserializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeIntervalDeserializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
@@ -37,7 +36,7 @@ public TimeIntervalDeserializer() {
}
@Override
- public TimeInterval deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
+ public TimeInterval deserialize(JsonParser jp, DeserializationContext dc) throws IOException {
return TimeInterval.parse(((JsonNode) jp.getCodec().readTree(jp)).asText());
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeValueDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeValueDeserializer.java
similarity index 85%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeValueDeserializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeValueDeserializer.java
index 060ed2736..3c0b89b99 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/TimeValueDeserializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/TimeValueDeserializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
@@ -28,8 +27,9 @@
import java.io.IOException;
/**
- * Helper for deserialization of TimeValue objects from JSON. May not work properly in every case as deciding wether
- * input is a TimeInstant or a TimeInterval is based on exceptions while parsing
+ * Helper for deserialization of TimeValue objects from JSON. May not work
+ * properly in every case as deciding wether input is a TimeInstant or a
+ * TimeInterval is based on exceptions while parsing
*
* @author jab
*/
@@ -40,7 +40,7 @@ public TimeValueDeserializer() {
}
@Override
- public TimeValue deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
+ public TimeValue deserialize(JsonParser jp, DeserializationContext dc) throws IOException {
TimeValue result;
JsonNode node = jp.getCodec().readTree(jp);
try {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/ToStringDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/ToStringDeserializer.java
similarity index 89%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/ToStringDeserializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/ToStringDeserializer.java
index 653c2013a..0fe22fa33 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/ToStringDeserializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/ToStringDeserializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
@@ -36,7 +35,7 @@ public ToStringDeserializer() {
}
@Override
- public Object deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
+ public Object deserialize(JsonParser jp, DeserializationContext dc) throws IOException {
TreeNode tree = jp.getCodec().readTree(jp);
return tree.toString();
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomDeserializationManager.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomDeserializationManager.java
similarity index 96%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomDeserializationManager.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomDeserializationManager.java
index a0f38c575..52523cee7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomDeserializationManager.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomDeserializationManager.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize.custom;
import java.util.HashMap;
import java.util.Map;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomDeserializer.java
similarity index 93%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomDeserializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomDeserializer.java
index dc588f257..9591d0ea0 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomDeserializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomDeserializer.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize.custom;
import java.io.IOException;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomEntityChangedMessageDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomEntityChangedMessageDeserializer.java
new file mode 100644
index 000000000..3a909639f
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomEntityChangedMessageDeserializer.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.json.deserialize.custom;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.fraunhofer.iosb.ilt.sta.messagebus.EntityChangedMessage;
+import de.fraunhofer.iosb.ilt.sta.model.Observation;
+import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInstant;
+import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author scf
+ */
+public class CustomEntityChangedMessageDeserializer extends JsonDeserializer {
+
+ /**
+ * The logger for this class.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(CustomEntityChangedMessageDeserializer.class);
+
+ @Override
+ public EntityChangedMessage deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
+ EntityChangedMessage message = new EntityChangedMessage();
+ ObjectMapper mapper = (ObjectMapper) parser.getCodec();
+ JsonNode obj = mapper.readTree(parser);
+ Iterator> i = obj.fields();
+ EntityType type = null;
+ JsonNode entityJson = null;
+ while (i.hasNext()) {
+ Map.Entry next = i.next();
+ String name = next.getKey();
+ JsonNode value = next.getValue();
+ switch (name.toLowerCase()) {
+ case "eventtype":
+ message.setEventType(EntityChangedMessage.Type.valueOf(value.asText()));
+ break;
+
+ case "entitytype":
+ type = EntityType.valueOf(value.asText());
+ break;
+
+ case "epfields":
+ for (JsonNode field : value) {
+ String fieldName = field.asText();
+ message.addEpField(EntityProperty.valueOf(fieldName));
+ }
+ break;
+
+ case "npfields":
+ for (JsonNode field : value) {
+ String fieldName = field.asText();
+ message.addNpField(NavigationProperty.valueOf(fieldName));
+ }
+ break;
+
+ case "entity":
+ entityJson = value;
+ break;
+
+ default:
+ LOGGER.warn("Unknown field in message: {}", name);
+ break;
+ }
+ }
+ if (type == null || entityJson == null) {
+ throw new IllegalArgumentException("Message json with no type or no entity.");
+ }
+ message.setEntity(parseEntity(mapper, entityJson, type));
+ return message;
+ }
+
+ private static Entity parseEntity(ObjectMapper mapper, JsonNode entityJson, EntityType entityType) {
+ Entity entity = mapper.convertValue(entityJson, entityType.getImplementingClass());
+ if (entity instanceof Observation) {
+ Observation observation = (Observation) entity;
+ if (observation.getResultTime() == null) {
+ observation.setResultTime(new TimeInstant(null));
+ }
+ }
+ for (NavigationProperty property : entityType.getNavigationEntities()) {
+ Object parentObject = entity.getProperty(property);
+ if (parentObject instanceof Entity) {
+ Entity parentEntity = (Entity) parentObject;
+ parentEntity.setExportObject(false);
+ }
+ }
+ return entity;
+ }
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomEntityDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomEntityDeserializer.java
similarity index 57%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomEntityDeserializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomEntityDeserializer.java
index a8a5ab868..fdef0be26 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/CustomEntityDeserializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/CustomEntityDeserializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize.custom;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -27,8 +26,8 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.custom.CustomSerialization;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
-import de.fraunhofer.iosb.ilt.sta.serialize.custom.CustomSerialization;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Iterator;
@@ -50,7 +49,7 @@ public CustomEntityDeserializer(Class extends Entity> clazz) {
}
@Override
- public T deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+ public T deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
Entity result;
try {
result = clazz.newInstance();
@@ -60,16 +59,15 @@ public T deserialize(JsonParser parser, DeserializationContext ctxt) throws IOEx
// need to make subclass of this class for every Entity subclass with custom field to get expected class!!!
BeanDescription beanDescription = ctxt.getConfig().introspect(ctxt.constructType(clazz));
ObjectMapper mapper = (ObjectMapper) parser.getCodec();
- JsonNode obj = (JsonNode) mapper.readTree(parser);
+ JsonNode obj = mapper.readTree(parser);
List properties = beanDescription.findProperties();
Iterator> i = obj.fields();
// First check if we know all properties that are present.
if (ctxt.isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
- for (; i.hasNext();) {
+ while (i.hasNext()) {
Map.Entry next = i.next();
String fieldName = next.getKey();
- JsonNode field = next.getValue();
Optional findFirst = properties.stream().filter(p -> p.getName().equals(fieldName)).findFirst();
if (!findFirst.isPresent()) {
throw new UnrecognizedPropertyException(parser, "Unknown field: " + fieldName, parser.getCurrentLocation(), clazz, fieldName, null);
@@ -78,34 +76,39 @@ public T deserialize(JsonParser parser, DeserializationContext ctxt) throws IOEx
}
for (BeanPropertyDefinition classProperty : properties) {
- if (obj.has(classProperty.getName())) {
- // property is present in class and json
- Annotation annotation = classProperty.getAccessor().getAnnotation(CustomSerialization.class);
- if (annotation != null) {
- // property has custom annotation
- // check if encoding property is also present in json (and also in class itself for sanity reasons)
- CustomSerialization customAnnotation = (CustomSerialization) annotation;
- Optional encodingClassProperty = properties.stream().filter(p -> p.getName().equals(customAnnotation.encoding())).findFirst();
- if (!encodingClassProperty.isPresent()) {
- throw new IOException("Error deserializing JSON as class '" + clazz.toString() + "' \n"
- + "Reason: field '" + customAnnotation.encoding() + "' specified by annotation as encoding field is not defined in class!");
- }
- String customEncoding = null;
- if (obj.has(customAnnotation.encoding())) {
- customEncoding = obj.get(customAnnotation.encoding()).asText();
- }
- Object customDeserializedValue = CustomDeserializationManager.getInstance()
- .getDeserializer(customEncoding)
- .deserialize(mapper.writeValueAsString(obj.get(classProperty.getName())));
- classProperty.getMutator().setValue(result, customDeserializedValue);
- } else {
- // TODO type identificatin is not safe beacuase may ne be backed by field. Rather do multiple checks
- Object value = mapper.readValue(mapper.writeValueAsString(obj.get(classProperty.getName())), classProperty.getField().getType());
- classProperty.getMutator().setValue(result, value);
+ deserialiseProperty(obj, classProperty, properties, mapper, result);
+ }
+ return (T) result;
+ }
+
+ private void deserialiseProperty(JsonNode obj, BeanPropertyDefinition classProperty, List properties, ObjectMapper mapper, Entity result) throws IOException {
+ if (obj.has(classProperty.getName())) {
+ // property is present in class and json
+ Annotation annotation = classProperty.getAccessor().getAnnotation(CustomSerialization.class);
+ if (annotation == null) {
+ // TODO type identificatin is not safe beacuase may not be backed by field. Rather do multiple checks
+ // TODO this seems inefficient. Use mapper.convertValue ?
+ Object value = mapper.readValue(mapper.writeValueAsString(obj.get(classProperty.getName())), classProperty.getField().getType());
+ classProperty.getMutator().setValue(result, value);
+ } else {
+ // property has custom annotation
+ // check if encoding property is also present in json (and also in class itself for sanity reasons)
+ CustomSerialization customAnnotation = (CustomSerialization) annotation;
+ Optional encodingClassProperty = properties.stream().filter(p -> p.getName().equals(customAnnotation.encoding())).findFirst();
+ if (!encodingClassProperty.isPresent()) {
+ throw new IOException("Error deserializing JSON as class '" + clazz.toString() + "' \n"
+ + "Reason: field '" + customAnnotation.encoding() + "' specified by annotation as encoding field is not defined in class!");
+ }
+ String customEncoding = null;
+ if (obj.has(customAnnotation.encoding())) {
+ customEncoding = obj.get(customAnnotation.encoding()).asText();
}
+ Object customDeserializedValue = CustomDeserializationManager.getInstance()
+ .getDeserializer(customEncoding)
+ .deserialize(mapper.writeValueAsString(obj.get(classProperty.getName())));
+ classProperty.getMutator().setValue(result, customDeserializedValue);
}
}
- return (T) result;
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/DefaultDeserializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/DefaultDeserializer.java
similarity index 75%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/DefaultDeserializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/DefaultDeserializer.java
index 675828418..b779ae0bf 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/DefaultDeserializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/DefaultDeserializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize.custom;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.EntityParser;
import java.io.IOException;
/**
@@ -29,9 +28,7 @@ public class DefaultDeserializer implements CustomDeserializer {
@Override
public Object deserialize(String json) throws IOException {
- return new ObjectMapper()
- .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
- .readValue(json, Object.class);
+ return EntityParser.getSimpleObjectMapper().readValue(json, Object.class);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/geojson/GeoJsonDeserializier.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/GeoJsonDeserializier.java
similarity index 79%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/geojson/GeoJsonDeserializier.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/GeoJsonDeserializier.java
index 0b185c761..d5c7a06ca 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/deserialize/custom/geojson/GeoJsonDeserializier.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/deserialize/custom/GeoJsonDeserializier.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.deserialize.custom.geojson;
+package de.fraunhofer.iosb.ilt.sta.json.deserialize.custom;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import de.fraunhofer.iosb.ilt.sta.deserialize.custom.CustomDeserializer;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.EntityParser;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
@@ -32,13 +31,13 @@
*/
public class GeoJsonDeserializier implements CustomDeserializer {
- public static final Set encodings = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+ public static final Set ENCODINGS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
"application/geo+json",
"application/vnd.geo+json"
)));
@Override
public Object deserialize(String json) throws IOException {
- return new ObjectMapper().readValue(json, GeoJsonObject.class);
+ return EntityParser.getSimpleObjectMapper().readValue(json, GeoJsonObject.class);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/DataArrayResultSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/DataArrayResultSerializer.java
similarity index 90%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/DataArrayResultSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/DataArrayResultSerializer.java
index eddea7708..ace4fb8b9 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/DataArrayResultSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/DataArrayResultSerializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.fraunhofer.iosb.ilt.sta.formatter.DataArrayResult;
@@ -31,7 +30,7 @@
public class DataArrayResultSerializer extends JsonSerializer {
@Override
- public void serialize(DataArrayResult value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ public void serialize(DataArrayResult value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
long count = value.getCount();
if (count >= 0) {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/DataArrayValueSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/DataArrayValueSerializer.java
similarity index 92%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/DataArrayValueSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/DataArrayValueSerializer.java
index 60e4bcb30..6dfc37f8b 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/DataArrayValueSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/DataArrayValueSerializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.fraunhofer.iosb.ilt.sta.formatter.DataArrayValue;
@@ -33,7 +32,7 @@
public class DataArrayValueSerializer extends JsonSerializer {
@Override
- public void serialize(DataArrayValue value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ public void serialize(DataArrayValue value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
Datastream datastream = value.getDatastream();
if (datastream != null) {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntityFormatter.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntityFormatter.java
new file mode 100644
index 000000000..f90a5677c
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntityFormatter.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import de.fraunhofer.iosb.ilt.sta.formatter.DataArrayResult;
+import de.fraunhofer.iosb.ilt.sta.formatter.DataArrayValue;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.custom.GeoJsonDeserializier;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.custom.CustomSerializationManager;
+import de.fraunhofer.iosb.ilt.sta.model.Datastream;
+import de.fraunhofer.iosb.ilt.sta.model.FeatureOfInterest;
+import de.fraunhofer.iosb.ilt.sta.model.HistoricalLocation;
+import de.fraunhofer.iosb.ilt.sta.model.Location;
+import de.fraunhofer.iosb.ilt.sta.model.Observation;
+import de.fraunhofer.iosb.ilt.sta.model.ObservedProperty;
+import de.fraunhofer.iosb.ilt.sta.model.Sensor;
+import de.fraunhofer.iosb.ilt.sta.model.Thing;
+import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
+import de.fraunhofer.iosb.ilt.sta.model.ext.EntitySetResult;
+import de.fraunhofer.iosb.ilt.sta.model.mixin.MixinUtils;
+import java.io.IOException;
+
+/**
+ * Enables serialization of entities as JSON.
+ *
+ * @author jab
+ */
+public class EntityFormatter {
+
+ private static ObjectMapper objectMapperInstance;
+
+ public static ObjectMapper getObjectMapper() {
+ if (objectMapperInstance == null) {
+ initObjectMapper();
+ }
+ return objectMapperInstance;
+ }
+
+ private static synchronized void initObjectMapper() {
+ if (objectMapperInstance == null) {
+ objectMapperInstance = createObjectMapper();
+ }
+ }
+
+ private static ObjectMapper createObjectMapper() {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.enable(SerializationFeature.INDENT_OUTPUT);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
+ mapper.setPropertyNamingStrategy(new EntitySetCamelCaseNamingStrategy());
+
+ MixinUtils.addMixins(mapper);
+
+ SimpleModule module = new SimpleModule();
+ GeoJsonSerializer geoJsonSerializer = new GeoJsonSerializer();
+ for (String encodingType : GeoJsonDeserializier.ENCODINGS) {
+ CustomSerializationManager.getInstance().registerSerializer(encodingType, geoJsonSerializer);
+ }
+
+ module.addSerializer(Entity.class, new EntitySerializer());
+ module.addSerializer(EntitySetResult.class, new EntitySetResultSerializer());
+ module.addSerializer(DataArrayValue.class, new DataArrayValueSerializer());
+ module.addSerializer(DataArrayResult.class, new DataArrayResultSerializer());
+ mapper.registerModule(module);
+ return mapper;
+ }
+
+ private EntityFormatter() {
+ }
+
+ public static String writeEntity(T entity) throws IOException {
+ return getObjectMapper().writeValueAsString(entity);
+ }
+
+ public static String writeEntityCollection(EntitySet entityCollection) throws IOException {
+ return getObjectMapper().writeValueAsString(new EntitySetResult(entityCollection));
+ }
+
+ public static String writeDatastream(Datastream datastream) throws IOException {
+ return writeEntity(datastream);
+ }
+
+ public static String writeFeatureOfInterest(FeatureOfInterest featureOfInterest) throws IOException {
+ return writeEntity(featureOfInterest);
+ }
+
+ public static String writeHistoricalLocation(HistoricalLocation historicalLocation) throws IOException {
+ return writeEntity(historicalLocation);
+ }
+
+ public static String writeLocation(Location location) throws IOException {
+ return writeEntity(location);
+ }
+
+ public static String writeObservation(Observation observation) throws IOException {
+ return writeEntity(observation);
+ }
+
+ public static String writeObservedProperty(ObservedProperty observedProperty) throws IOException {
+ return writeEntity(observedProperty);
+ }
+
+ public static String writeSensor(Sensor sensor) throws IOException {
+ return writeEntity(sensor);
+ }
+
+ public static String writeThing(Thing thing) throws IOException {
+ return writeEntity(thing);
+ }
+
+ public static String writeObject(Object object) throws IOException {
+ return getObjectMapper().writeValueAsString(object);
+ }
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySerializer.java
similarity index 71%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySerializer.java
index cde1408f1..02acabcff 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySerializer.java
@@ -15,11 +15,11 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
@@ -29,15 +29,17 @@
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import static com.fasterxml.jackson.databind.ser.BeanPropertyWriter.MARKER_FOR_EMPTY;
+import com.fasterxml.jackson.databind.ser.std.NullSerializer;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.custom.CustomSerialization;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.custom.CustomSerializationManager;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.NavigableElement;
-import de.fraunhofer.iosb.ilt.sta.serialize.custom.CustomSerialization;
-import de.fraunhofer.iosb.ilt.sta.serialize.custom.CustomSerializationManager;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.slf4j.LoggerFactory;
@@ -56,45 +58,29 @@ public class EntitySerializer extends JsonSerializer {
*/
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(EntitySerializer.class);
- private final List selectedProperties;
-
- public EntitySerializer() {
- this.selectedProperties = null;
- }
-
- public EntitySerializer(List selectedProperties) {
- this.selectedProperties = selectedProperties;
- }
-
@Override
- public void serialize(Entity entity, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ public void serialize(Entity entity, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
try {
BasicBeanDescription beanDescription = serializers.getConfig().introspect(serializers.constructType(entity.getClass()));
List properties = beanDescription.findProperties();
+ Set selectedProperties = entity.getSelectedPropertyNames();
for (BeanPropertyDefinition property : properties) {
// 0. check if it should be serialized
- if (selectedProperties != null) {
- if (!selectedProperties.contains(property.getName())) {
- continue;
- }
+ // If not, we still have to check if it is expanded, hence no
+ // direct continue.
+ boolean selected = true;
+ if (selectedProperties != null && !selectedProperties.contains(property.getName())) {
+ selected = false;
}
// 1. is it a NavigableElement?
if (NavigableElement.class.isAssignableFrom(property.getAccessor().getRawType())) {
- Object rawValue = property.getAccessor().getValue(entity);
- if (rawValue != null) {
- NavigableElement value = (NavigableElement) rawValue;
- // If navigation link set, output navigation link.
- if (value.getNavigationLink() != null && !value.getNavigationLink().isEmpty()) {
- gen.writeFieldName(property.getName() + "@iot.navigationLink");
- gen.writeString(value.getNavigationLink());
- }
- // If object should not be exported, skip any further processing.
- if (!value.isExportObject()) {
- continue;
- }
- }
+ selected = serialiseNavigationElement(property, entity, selected, gen);
}
+ if (!selected) {
+ continue;
+ }
+
// 2. check if property has CustomSerialization annotation -> use custom serializer
Annotation annotation = property.getAccessor().getAnnotation(CustomSerialization.class);
if (annotation != null) {
@@ -107,44 +93,64 @@ public void serialize(Entity entity, JsonGenerator gen, SerializerProvider seria
} else {
serializeField(entity, gen, serializers, beanDescription, property);
}
- // 3. check if property is EntitySet than eventually write count
+ // 3. check if property is EntitySet than write count if needed.
if (EntitySet.class.isAssignableFrom(property.getAccessor().getRawType())) {
- Object rawValue = property.getAccessor().getValue(entity);
- if (rawValue != null) {
- EntitySet set = (EntitySet) rawValue;
- long count = set.getCount();
- if (count >= 0) {
- gen.writeNumberField(property.getName() + "@iot.count", count);
- }
- String nextLink = set.getNextLink();
- if (nextLink != null) {
- gen.writeStringField(property.getName() + "@iot.nextLink", nextLink);
- }
- }
+ writeCountNextlinkForSet(property, entity, gen);
}
}
- } catch (Exception e) {
- LOGGER.error("could not serialize Entity", e);
- throw new IOException("could not serialize Entity", e);
+ } catch (Exception exc) {
+ LOGGER.error("could not serialize Entity", exc);
+ throw new IOException("could not serialize Entity", exc);
} finally {
gen.writeEndObject();
}
}
+ private void writeCountNextlinkForSet(BeanPropertyDefinition property, Entity entity, JsonGenerator gen) throws IOException {
+ Object rawValue = property.getAccessor().getValue(entity);
+ if (rawValue == null) {
+ return;
+ }
+ EntitySet set = (EntitySet) rawValue;
+ long count = set.getCount();
+ if (count >= 0) {
+ gen.writeNumberField(property.getName() + "@iot.count", count);
+ }
+ String nextLink = set.getNextLink();
+ if (nextLink != null) {
+ gen.writeStringField(property.getName() + "@iot.nextLink", nextLink);
+ }
+ }
+
+ private boolean serialiseNavigationElement(BeanPropertyDefinition property, Entity entity, boolean selected, JsonGenerator gen) throws IOException {
+ Object rawValue = property.getAccessor().getValue(entity);
+ if (rawValue == null) {
+ return selected;
+ }
+ NavigableElement value = (NavigableElement) rawValue;
+ // If navigation link set, and selected, output navigation link.
+ if (selected && value.getNavigationLink() != null && !value.getNavigationLink().isEmpty()) {
+ gen.writeFieldName(property.getName() + "@iot.navigationLink");
+ gen.writeString(value.getNavigationLink());
+ }
+ // If object should not be exported, skip any further processing.
+ return value.isExportObject();
+ }
+
protected void serializeFieldCustomized(
Entity entity,
JsonGenerator gen,
BeanPropertyDefinition property,
List properties,
- CustomSerialization annotation) throws Exception {
+ CustomSerialization annotation) throws IOException {
// check if encoding field is present in current bean
- // get calue
+ // get value
// call CustomSerializationManager
Optional encodingProperty = properties.stream().filter(p -> p.getName().equals(annotation.encoding())).findFirst();
if (!encodingProperty.isPresent()) {
- // TODO use more specific exception type
- throw new Exception("can not serialize instance of class '" + entity.getClass() + "'! \n"
- + "Reason: trying to use custom serialization for field '" + property.getName() + "' but field '" + annotation.encoding() + "' specifying enconding is not present!");
+ throw new JsonGenerationException("can not serialize instance of class '" + entity.getClass() + "'! \n"
+ + "Reason: trying to use custom serialization for field '" + property.getName() + "' but field '" + annotation.encoding() + "' specifying enconding is not present!",
+ gen);
}
Object value = encodingProperty.get().getAccessor().getValue(entity);
String encodingType = null;
@@ -188,6 +194,9 @@ protected void serializeFieldTyped(
}
}
+ JsonInclude.Value inclusion = beanPropertyDefinition.findInclusion();
+ JsonInclude.Value defaultInclusion = serializers.getConfig().getDefaultPropertyInclusion();
+ JsonInclude.Value usedInclusion = defaultInclusion.withOverrides(inclusion);
BeanPropertyWriter bpw = new BeanPropertyWriter(
beanPropertyDefinition,
beanPropertyDefinition.getAccessor(),
@@ -196,8 +205,11 @@ protected void serializeFieldTyped(
null, // will be searched automatically
typeSerializer, // will not be searched automatically
beanPropertyDefinition.getAccessor().getType(),
- suppressNulls(serializers.getConfig().getDefaultPropertyInclusion()),
+ suppressNulls(usedInclusion),
suppressableValue(serializers.getConfig().getDefaultPropertyInclusion()));
+ if (!bpw.willSuppressNulls()) {
+ bpw.assignNullSerializer(NullSerializer.instance);
+ }
bpw.serializeAsField(entity, gen, serializers);
} catch (JsonMappingException ex) {
Logger.getLogger(EntitySerializer.class.getName()).log(Level.SEVERE, null, ex);
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetCamelCaseNamingStrategy.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetCamelCaseNamingStrategy.java
similarity index 97%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetCamelCaseNamingStrategy.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetCamelCaseNamingStrategy.java
index 0ce429539..2ab16f634 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetCamelCaseNamingStrategy.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetCamelCaseNamingStrategy.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetResultSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetResultSerializer.java
similarity index 88%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetResultSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetResultSerializer.java
index a62a092ea..99658ed2e 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetResultSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetResultSerializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.fraunhofer.iosb.ilt.sta.model.ext.EntitySetResult;
@@ -31,7 +30,7 @@
public class EntitySetResultSerializer extends JsonSerializer {
@Override
- public void serialize(EntitySetResult value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ public void serialize(EntitySetResult value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
long count = value.getValues().getCount();
if (count >= 0) {
@@ -42,7 +41,6 @@ public void serialize(EntitySetResult value, JsonGenerator gen, SerializerProvid
gen.writeStringField("@iot.nextLink", nextLink);
}
- // TODO begin/end array, iterate over content
gen.writeFieldName("value");
gen.writeObject(value.getValues());
gen.writeEndObject();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetSerializer.java
similarity index 79%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetSerializer.java
index 311decb76..832f628f3 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/EntitySetSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/EntitySetSerializer.java
@@ -15,26 +15,26 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
-import java.io.IOException;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
+import java.io.IOException;
/**
- * Defines how an EntitySet is serialized. If an EntitySet has a navigationLink property
- EntityJsonSerializer makes sure that it is only serialized as a String, otherwise the EntitySet will be
- serialized using this class and only the content of the EntitySet will be serialized.
+ * Defines how an EntitySet is serialized. If an EntitySet has a navigationLink
+ * property EntityJsonSerializer makes sure that it is only serialized as a
+ * String, otherwise the EntitySet will be serialized using this class and only
+ * the content of the EntitySet will be serialized.
*
* @author jab
*/
public class EntitySetSerializer extends JsonSerializer {
@Override
- public void serialize(EntitySet value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ public void serialize(EntitySet value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeFieldName("value");
gen.writeObject(value.asList());
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/custom/geojson/GeoJsonSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/GeoJsonSerializer.java
similarity index 67%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/custom/geojson/GeoJsonSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/GeoJsonSerializer.java
index 21e2fb282..41fd5636f 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/custom/geojson/GeoJsonSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/GeoJsonSerializer.java
@@ -15,16 +15,13 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.model.custom.geojson;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
+import de.fraunhofer.iosb.ilt.sta.model.mixin.FeatureMixIn;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
-import de.fraunhofer.iosb.ilt.sta.serialize.custom.CustomSerializer;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.custom.CustomSerializer;
import org.geojson.Feature;
import org.geojson.GeoJsonObject;
@@ -34,10 +31,16 @@
*/
public class GeoJsonSerializer implements CustomSerializer {
- public static final Set encodings = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
- "application/geo+json",
- "application/vnd.geo+json"
- )));
+ private static ObjectMapper mapper;
+
+ private static ObjectMapper getMapper() {
+ if (mapper == null) {
+ mapper = new ObjectMapper()
+ .setSerializationInclusion(JsonInclude.Include.NON_NULL)
+ .addMixIn(Feature.class, FeatureMixIn.class);
+ }
+ return mapper;
+ }
@Override
public String serialize(Object object) throws JsonProcessingException {
@@ -45,10 +48,7 @@ public String serialize(Object object) throws JsonProcessingException {
return null;
}
GeoJsonObject geoJson = (GeoJsonObject) object;
- ObjectMapper mapper = new ObjectMapper();
- mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
- mapper.addMixIn(Feature.class, FeatureMixIn.class);
- return mapper.writeValueAsString(geoJson);
+ return getMapper().writeValueAsString(geoJson);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/TimeValueSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/TimeValueSerializer.java
similarity index 88%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/TimeValueSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/TimeValueSerializer.java
index 590a4f05c..0f3264d8e 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/TimeValueSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/TimeValueSerializer.java
@@ -15,10 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize;
+package de.fraunhofer.iosb.ilt.sta.json.serialize;
import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeValue;
@@ -32,7 +31,7 @@
public class TimeValueSerializer extends JsonSerializer {
@Override
- public void serialize(TimeValue value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
+ public void serialize(TimeValue value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value.asISO8601() == null) {
gen.writeNull();
} else {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerialization.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerialization.java
similarity index 95%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerialization.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerialization.java
index bb6d55e2d..cc42a2cc6 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerialization.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerialization.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.serialize.custom;
import com.fasterxml.jackson.annotation.JacksonAnnotation;
import java.lang.annotation.ElementType;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerializationManager.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerializationManager.java
similarity index 95%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerializationManager.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerializationManager.java
index 0436dd073..af43343c7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerializationManager.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerializationManager.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.serialize.custom;
import java.util.HashMap;
import java.util.Map;
@@ -52,7 +52,6 @@ public CustomSerializer getSerializer(String encodingType) {
result = customSerializers.get(encodingType);
}
if (result == null) {
- // TODO what to create here???
result = new DefaultSerializer();
}
return result;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerializer.java
similarity index 94%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerializer.java
index 9c08fb023..b1dc03065 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/CustomSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/CustomSerializer.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.serialize.custom;
import java.io.IOException;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/DefaultSerializer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/DefaultSerializer.java
similarity index 73%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/DefaultSerializer.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/DefaultSerializer.java
index f52488c60..28065092d 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/serialize/custom/DefaultSerializer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/json/serialize/custom/DefaultSerializer.java
@@ -15,9 +15,9 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.serialize.custom;
+package de.fraunhofer.iosb.ilt.sta.json.serialize.custom;
-import de.fraunhofer.iosb.ilt.sta.serialize.EntityFormatter;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntityFormatter;
import java.io.IOException;
/**
@@ -26,21 +26,11 @@
*/
class DefaultSerializer implements CustomSerializer {
- private EntityFormatter formatter;
-
@Override
public String serialize(Object object) throws IOException {
if (object == null) {
return null;
}
- return getFormatter().writeObject(object);
+ return EntityFormatter.writeObject(object);
}
-
- public EntityFormatter getFormatter() {
- if (formatter == null) {
- formatter = new EntityFormatter();
- }
- return formatter;
- }
-
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/EntityChangedMessage.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/EntityChangedMessage.java
new file mode 100644
index 000000000..4ad38fbd0
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/EntityChangedMessage.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.messagebus;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty;
+import de.fraunhofer.iosb.ilt.sta.path.Property;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ *
+ * @author scf
+ */
+public class EntityChangedMessage {
+
+ /**
+ * The types of changes that can happen to entities.
+ */
+ public enum Type {
+ CREATE,
+ UPDATE,
+ DELETE
+ }
+ /**
+ * The type of event that this message describes.
+ */
+ private Type eventType;
+ /**
+ * The fields of the entity that were affected, if the type was UPDATE. For
+ * Create and Delete this is always empty, since all fields are affected.
+ */
+ private Set epFields;
+ private Set npFields;
+ /**
+ * The type of the entity that was affected.
+ */
+ private EntityType entityType;
+ /**
+ * The new version of the entity (for create/update) or the old entity (for
+ * delete).
+ */
+ private Entity entity;
+
+ public Type getEventType() {
+ return eventType;
+ }
+
+ public EntityChangedMessage setEventType(Type eventType) {
+ this.eventType = eventType;
+ return this;
+ }
+
+ public EntityType getEntityType() {
+ return entityType;
+ }
+
+ public EntityChangedMessage setEntityType(EntityType entityType) {
+ this.entityType = entityType;
+ return this;
+ }
+
+ public Set getEpFields() {
+ return epFields;
+ }
+
+ public Set getNpFields() {
+ return npFields;
+ }
+
+ @JsonIgnore
+ public Set getFields() {
+ if (epFields == null && npFields == null) {
+ return Collections.emptySet();
+ }
+ Set fields = new HashSet<>();
+ if (epFields != null) {
+ fields.addAll(epFields);
+ }
+ if (npFields != null) {
+ fields.addAll(npFields);
+ }
+ return fields;
+ }
+
+ public EntityChangedMessage addField(Property field) {
+ if (field instanceof EntityProperty) {
+ addEpField((EntityProperty) field);
+ } else if (field instanceof NavigationProperty) {
+ addNpField((NavigationProperty) field);
+ } else {
+ throw new IllegalArgumentException("Field is not an entity or navigation property: " + field);
+ }
+ return this;
+ }
+
+ public EntityChangedMessage addEpField(EntityProperty field) {
+ if (epFields == null) {
+ epFields = new HashSet<>();
+ }
+ epFields.add(field);
+ return this;
+ }
+
+ public EntityChangedMessage addNpField(NavigationProperty field) {
+ if (npFields == null) {
+ npFields = new HashSet<>();
+ }
+ npFields.add(field);
+ return this;
+ }
+
+ public Entity getEntity() {
+ return entity;
+ }
+
+ public EntityChangedMessage setEntity(Entity entity) {
+ this.entity = entity;
+ this.entityType = entity.getEntityType();
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final EntityChangedMessage other = (EntityChangedMessage) obj;
+ if (this.eventType != other.eventType) {
+ return false;
+ }
+ if (!Objects.equals(this.epFields, other.epFields)) {
+ return false;
+ }
+ if (this.entityType != other.entityType) {
+ return false;
+ }
+ return Objects.equals(this.entity, other.entity);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(eventType, epFields, entityType, entity);
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/InternalMessageBus.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/InternalMessageBus.java
new file mode 100644
index 000000000..7775f146a
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/InternalMessageBus.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.messagebus;
+
+import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty;
+import de.fraunhofer.iosb.ilt.sta.settings.BusSettings;
+import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
+import de.fraunhofer.iosb.ilt.sta.settings.Settings;
+import de.fraunhofer.iosb.ilt.sta.util.ProcessorHelper;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A message bus implementation for in-JVM use.
+ *
+ * @author scf
+ */
+public class InternalMessageBus implements MessageBus {
+
+ public static final String TAG_WORKER_COUNT = "workerPoolSize";
+ public static final int DEFAULT_WORKER_COUNT = 2;
+ public static final String TAG_QUEUE_SIZE = "queueSize";
+ public static final int DEFAULT_QUEUE_SIZE = 100;
+ /**
+ * The logger for this class.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(InternalMessageBus.class);
+
+ private BlockingQueue entityChangedMessageQueue;
+ private ExecutorService entityChangedExecutorService;
+ private final List listeners = new CopyOnWriteArrayList<>();
+
+ @Override
+ public void init(CoreSettings settings) {
+ BusSettings busSettings = settings.getBusSettings();
+ Settings customSettings = busSettings.getCustomSettings();
+ int poolSize = customSettings.getInt(TAG_WORKER_COUNT, DEFAULT_WORKER_COUNT);
+ int queueSize = customSettings.getInt(TAG_QUEUE_SIZE, DEFAULT_QUEUE_SIZE);
+
+ entityChangedMessageQueue = new ArrayBlockingQueue<>(queueSize);
+ entityChangedExecutorService = ProcessorHelper.createProcessors(
+ poolSize,
+ entityChangedMessageQueue,
+ this::handleMessage,
+ "InternalBusProcessor");
+ }
+
+ @Override
+ public void stop() {
+ entityChangedExecutorService.shutdown();
+ try {
+ if (entityChangedExecutorService.awaitTermination(2, TimeUnit.SECONDS)) {
+ return;
+ }
+ } catch (InterruptedException ex) {
+ LOGGER.error("Interrupted while waiting for shutdown.", ex);
+ Thread.currentThread().interrupt();
+ }
+ List list = entityChangedExecutorService.shutdownNow();
+ LOGGER.warn("There were {} messages left on the queue.", list.size());
+ }
+
+ @Override
+ public void sendMessage(EntityChangedMessage message) {
+ Entity entity = message.getEntity();
+ EntityType entityType = entity.getEntityType();
+ // We directly hand the entity on without serialization step.
+ // The receivers expect the navigation entities to not be exportable.
+ for (NavigationProperty property : entityType.getNavigationEntities()) {
+ Object parentObject = entity.getProperty(property);
+ if (parentObject instanceof Entity) {
+ Entity parentEntity = (Entity) parentObject;
+ parentEntity.setExportObject(false);
+ }
+ }
+ if (!entityChangedMessageQueue.offer(message)) {
+ LOGGER.error("Failed to add message to queue. Increase the queue size to allow a bigger buffer, or increase the worker pool size to empty the buffer quicker.");
+ }
+ }
+
+ @Override
+ public void addMessageListener(MessageListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
+ public void removeMessageListener(MessageListener listener) {
+ listeners.remove(listener);
+ }
+
+ private void handleMessage(EntityChangedMessage message) {
+ for (MessageListener listener : listeners) {
+ try {
+ listener.messageReceived(message);
+ } catch (Exception ex) {
+ LOGGER.error("Listener threw exception on message reception.", ex);
+ }
+ }
+ }
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageBus.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageBus.java
new file mode 100644
index 000000000..79b54fde7
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageBus.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.messagebus;
+
+import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
+
+/**
+ *
+ * @author scf
+ */
+public interface MessageBus {
+
+ public void init(CoreSettings settings);
+
+ /**
+ * Stop the bus and clean up any worker threads.
+ */
+ public void stop();
+
+ /**
+ * Offer an event message to be sent over the bus. This should return
+ * quickly.
+ *
+ * @param message the message to send.
+ */
+ public void sendMessage(EntityChangedMessage message);
+
+ public void addMessageListener(MessageListener listener);
+
+ public void removeMessageListener(MessageListener listener);
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageBusFactory.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageBusFactory.java
new file mode 100644
index 000000000..4a91ef48d
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageBusFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.messagebus;
+
+import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
+
+/**
+ *
+ * @author scf
+ */
+public class MessageBusFactory {
+
+ private static final String ERROR_MSG = "Could not generate MessageBus instance: ";
+ private static MessageBus instance;
+
+ public static synchronized void init(CoreSettings settings) {
+ if (instance == null) {
+ if (settings == null) {
+ throw new IllegalArgumentException("settings must be non-null");
+ }
+ try {
+ String mbClsName = settings.getBusSettings().getBusImplementationClass();
+ Class> messageBusClass = Class.forName(mbClsName);
+ instance = (MessageBus) messageBusClass.newInstance();
+ instance.init(settings);
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
+ throw new IllegalArgumentException(ERROR_MSG + "Class '" + settings.getPersistenceSettings().getPersistenceManagerImplementationClass() + "' could not be found", ex);
+ }
+ }
+ }
+
+ public static MessageBus getMessageBus() {
+ if (instance == null) {
+ throw new IllegalStateException("MessageBusFactory is not initialized! Call init() before accessing the instance.");
+ }
+ return instance;
+ }
+
+ private MessageBusFactory() {
+ // should not be instantiated.
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageListener.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageListener.java
new file mode 100644
index 000000000..a69cad8d0
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MessageListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.messagebus;
+
+/**
+ *
+ * @author scf
+ */
+public interface MessageListener {
+
+ /**
+ * Informs the listener that a message was received. Listeners should not do
+ * heavy work on the thread that called this method.
+ *
+ * @param message The message that was received.
+ */
+ public void messageReceived(EntityChangedMessage message);
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MqttMessageBus.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MqttMessageBus.java
new file mode 100644
index 000000000..c3a1e60ad
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/messagebus/MqttMessageBus.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.messagebus;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.EntityParser;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntityFormatter;
+import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManagerFactory;
+import de.fraunhofer.iosb.ilt.sta.settings.BusSettings;
+import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
+import de.fraunhofer.iosb.ilt.sta.settings.Settings;
+import de.fraunhofer.iosb.ilt.sta.util.ProcessorHelper;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A message bus implementation for in-JVM use.
+ *
+ * @author scf
+ */
+public class MqttMessageBus implements MessageBus, MqttCallback {
+
+ public static final String TAG_SEND_WORKER_COUNT = "sendWorkerPoolSize";
+ public static final int DEFAULT_SEND_WORKER_COUNT = 2;
+ public static final String TAG_RECV_WORKER_COUNT = "recvWorkerPoolSize";
+ public static final int DEFAULT_RECV_WORKER_COUNT = 2;
+ public static final String TAG_SEND_QUEUE_SIZE = "sendQueueSize";
+ public static final int DEFAULT_SEND_QUEUE_SIZE = 100;
+ public static final String TAG_RECV_QUEUE_SIZE = "recvQueueSize";
+ public static final int DEFAULT_RECV_QUEUE_SIZE = 100;
+ public static final String TAG_MQTT_BROKER = "mqttBroker";
+ public static final String TAG_TOPIC_NAME = "topicName";
+ public static final String DEFAULT_TOPIC_NAME = "FROST-Bus";
+ public static final String TAG_QOS_LEVEL = "qosLevel";
+ public static final int DEFAULT_QOS_LEVEL = 2;
+ public static final String TAG_MAX_IN_FLIGHT = "maxInFlight";
+ public static final int DEFAULT_MAX_IN_FLIGHT = 50;
+
+ /**
+ * The logger for this class.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(MqttMessageBus.class);
+
+ private int sendPoolSize;
+ private int sendQueueSize;
+ private int recvPoolSize;
+ private int recvQueueSize;
+ private BlockingQueue sendQueue;
+ private ExecutorService sendService;
+ private BlockingQueue recvQueue;
+ private ExecutorService recvService;
+ private final List listeners = new CopyOnWriteArrayList<>();
+
+ private String broker;
+ private String clientId = "FROST-MQTT-Bus-" + UUID.randomUUID();
+ private MqttClient client;
+ private String topicName;
+ private int qosLevel;
+ private int maxInFlight;
+ private boolean listening = false;
+
+ private ObjectMapper formatter;
+ private EntityParser parser;
+
+ @Override
+ public void init(CoreSettings settings) {
+ BusSettings busSettings = settings.getBusSettings();
+ Settings customSettings = busSettings.getCustomSettings();
+ sendPoolSize = customSettings.getInt(TAG_SEND_WORKER_COUNT, DEFAULT_SEND_WORKER_COUNT);
+ sendQueueSize = customSettings.getInt(TAG_SEND_QUEUE_SIZE, DEFAULT_SEND_QUEUE_SIZE);
+ recvPoolSize = customSettings.getInt(TAG_RECV_WORKER_COUNT, DEFAULT_RECV_WORKER_COUNT);
+ recvQueueSize = customSettings.getInt(TAG_RECV_QUEUE_SIZE, DEFAULT_RECV_QUEUE_SIZE);
+
+ sendQueue = new ArrayBlockingQueue<>(sendQueueSize);
+ sendService = ProcessorHelper.createProcessors(
+ sendPoolSize,
+ sendQueue,
+ this::handleMessageSent,
+ "mqttBusSend");
+
+ recvQueue = new ArrayBlockingQueue<>(recvQueueSize);
+ recvService = ProcessorHelper.createProcessors(
+ recvPoolSize,
+ recvQueue,
+ this::handleMessageReceived,
+ "mqttBusRecv");
+
+ broker = customSettings.get(TAG_MQTT_BROKER);
+ if (broker == null || broker.isEmpty()) {
+ LOGGER.error("Broker url should be configured in option bus.{}", TAG_MQTT_BROKER);
+ }
+ topicName = customSettings.getWithDefault(TAG_TOPIC_NAME, DEFAULT_TOPIC_NAME, String.class);
+ qosLevel = customSettings.getInt(TAG_QOS_LEVEL, DEFAULT_QOS_LEVEL);
+ maxInFlight = customSettings.getInt(TAG_MAX_IN_FLIGHT, DEFAULT_MAX_IN_FLIGHT);
+ connect();
+
+ formatter = EntityFormatter.getObjectMapper();
+ parser = new EntityParser(PersistenceManagerFactory.getInstance().create().getIdManager().getIdClass());
+ }
+
+ private synchronized void connect() {
+ if (client == null) {
+ try {
+ client = new MqttClient(broker, clientId, new MemoryPersistence());
+ client.setCallback(this);
+ } catch (MqttException ex) {
+ LOGGER.error("Failed to connect to broker: {}", broker);
+ LOGGER.error("", ex);
+ return;
+ }
+ }
+ if (!client.isConnected()) {
+ try {
+ LOGGER.info("paho-client connecting to broker: {}", broker);
+ MqttConnectOptions connOpts = new MqttConnectOptions();
+ connOpts.setAutomaticReconnect(true);
+ connOpts.setCleanSession(false);
+ connOpts.setKeepAliveInterval(30);
+ connOpts.setConnectionTimeout(30);
+ connOpts.setMaxInflight(maxInFlight);
+ client.connect(connOpts);
+ LOGGER.info("paho-client connected to broker");
+ } catch (MqttException ex) {
+ LOGGER.error("Failed to connect to broker: {}", broker);
+ LOGGER.error("", ex);
+ }
+ }
+
+ }
+
+ private synchronized void disconnect() {
+ if (client == null) {
+ return;
+ }
+ if (client.isConnected()) {
+ try {
+ LOGGER.info("paho-client disconnecting from broker: {}", broker);
+ client.disconnect(1000);
+ } catch (MqttException ex) {
+ LOGGER.error("Exception disconnecting client.", ex);
+ }
+ }
+ try {
+ LOGGER.info("paho-client closing");
+ client.close();
+ } catch (MqttException ex) {
+ LOGGER.error("Exception closing client.", ex);
+ }
+ client = null;
+ }
+
+ private synchronized void startListening() {
+ try {
+ LOGGER.info("paho-client subscribing to topic: {}", topicName);
+ if (!client.isConnected()) {
+ connect();
+ }
+ client.subscribe(topicName, qosLevel);
+ listening = true;
+ } catch (MqttException ex) {
+ LOGGER.error("Failed to start listening.", ex);
+ }
+ }
+
+ private synchronized void stopListening() {
+ if (!listening) {
+ return;
+ }
+ try {
+ LOGGER.info("paho-client unsubscribing from topic: {}", topicName);
+ client.unsubscribe(topicName);
+ listening = false;
+ } catch (MqttException ex) {
+ LOGGER.error("Failed to stop listening.", ex);
+ }
+ }
+
+ @Override
+ public void stop() {
+ LOGGER.info("Message bus shutting down.");
+ stopListening();
+ disconnect();
+ ProcessorHelper.shutdownProcessors(sendService, sendQueue, 10, TimeUnit.SECONDS);
+ ProcessorHelper.shutdownProcessors(recvService, recvQueue, 10, TimeUnit.SECONDS);
+ LOGGER.info("Message bus closed.");
+ }
+
+ @Override
+ public void sendMessage(EntityChangedMessage message) {
+ if (!sendQueue.offer(message)) {
+ LOGGER.error("Failed to add message to send-queue. Increase {} (currently {}) to allow a bigger buffer, or increase {} (currently {}) to empty the buffer quicker.",
+ TAG_SEND_QUEUE_SIZE, sendQueueSize, TAG_SEND_WORKER_COUNT, sendPoolSize);
+ }
+ }
+
+ @Override
+ public synchronized void addMessageListener(MessageListener listener) {
+ listeners.add(listener);
+ if (!listening) {
+ startListening();
+ }
+ }
+
+ @Override
+ public synchronized void removeMessageListener(MessageListener listener) {
+ listeners.remove(listener);
+ if (listeners.isEmpty()) {
+ stopListening();
+ }
+ }
+
+ private void handleMessageSent(EntityChangedMessage message) {
+ try {
+ String serialisedMessage = formatter.writeValueAsString(message);
+ byte[] bytes = serialisedMessage.getBytes(StringHelper.ENCODING);
+ if (!client.isConnected()) {
+ connect();
+ }
+ client.publish(topicName, bytes, qosLevel, false);
+ } catch (MqttException | JsonProcessingException ex) {
+ LOGGER.error("Failed to publish message to bus.", ex);
+ }
+ }
+
+ @Override
+ public void connectionLost(Throwable cause) {
+ LOGGER.warn("Connection to message bus lost.");
+ LOGGER.debug("", cause);
+ }
+
+ @Override
+ public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
+ String serialisedEcMessage = new String(mqttMessage.getPayload(), StringHelper.ENCODING);
+ EntityChangedMessage ecMessage = parser.parseObject(EntityChangedMessage.class, serialisedEcMessage);
+ if (!recvQueue.offer(ecMessage)) {
+ LOGGER.error("Failed to add message to receive-queue. Increase {} (currently {}) to allow a bigger buffer, or increase {} (currently {}) to empty the buffer quicker.",
+ TAG_RECV_QUEUE_SIZE, recvQueueSize, TAG_RECV_WORKER_COUNT, recvPoolSize);
+ }
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ // Nothing to do...
+ }
+
+ private void handleMessageReceived(EntityChangedMessage message) {
+ for (MessageListener listener : listeners) {
+ try {
+ listener.messageReceived(message);
+ } catch (Exception ex) {
+ LOGGER.error("Listener threw exception on message reception.", ex);
+ }
+ }
+ }
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/AbstractDatastream.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/AbstractDatastream.java
new file mode 100644
index 000000000..041cadd3e
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/AbstractDatastream.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.model;
+
+import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
+import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.NamedEntity;
+import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInterval;
+import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
+import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+import de.fraunhofer.iosb.ilt.sta.path.ResourcePathElement;
+import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
+import java.util.Objects;
+import org.geojson.Polygon;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author jab, scf
+ */
+public abstract class AbstractDatastream extends NamedEntity {
+
+ /**
+ * The logger for this class.
+ */
+ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDatastream.class);
+ private String observationType;
+ private Polygon observedArea; // reference to GeoJSON library
+ private TimeInterval phenomenonTime;
+ private TimeInterval resultTime;
+ private Sensor sensor;
+ private Thing thing;
+ private EntitySet observations;
+
+ private boolean setObservationType;
+ private boolean setObservedArea;
+ private boolean setPhenomenonTime;
+ private boolean setResultTime;
+ private boolean setSensor;
+ private boolean setThing;
+
+ public AbstractDatastream() {
+ this(null);
+ }
+
+ public AbstractDatastream(Id id) {
+ super(id);
+ this.observations = new EntitySetImpl<>(EntityType.OBSERVATION);
+ }
+
+ @Override
+ public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException {
+ ResourcePathElement parent = containingSet.getParent();
+ if (parent instanceof EntityPathElement) {
+ EntityPathElement parentEntity = (EntityPathElement) parent;
+ Id parentId = parentEntity.getId();
+ if (parentId != null) {
+ checkParent(parentEntity, parentId);
+ }
+ }
+
+ super.complete(containingSet);
+ }
+
+ protected boolean checkParent(EntityPathElement parentEntity, Id parentId) {
+ switch (parentEntity.getEntityType()) {
+ case SENSOR:
+ setSensor(new Sensor(parentId));
+ LOGGER.debug("Set sensorId to {}.", parentId);
+ return true;
+
+ case THING:
+ setThing(new Thing(parentId));
+ LOGGER.debug("Set thingId to {}.", parentId);
+ return true;
+
+ default:
+ LOGGER.error("Incorrect 'parent' entity type for {}: {}", getEntityType(), parentEntity.getEntityType());
+ return false;
+ }
+ }
+
+ @Override
+ public void setEntityPropertiesSet() {
+ super.setEntityPropertiesSet();
+ setObservationType = true;
+ setObservedArea = true;
+ setPhenomenonTime = true;
+ setResultTime = true;
+ }
+
+ public String getObservationType() {
+ return observationType;
+ }
+
+ /**
+ * Set the observation type without changing the "set" status of it.
+ *
+ * @param observationType The observation type to set.
+ */
+ protected final void setObservationTypeIntern(String observationType) {
+ this.observationType = observationType;
+ }
+
+ public void setObservationType(String observationType) {
+ this.observationType = observationType;
+ setObservationType = observationType != null;
+ }
+
+ /**
+ * Flag indicating the observation type was set by the user.
+ *
+ * @return Flag indicating the observation type was set by the user.
+ */
+ public boolean isSetObservationType() {
+ return setObservationType;
+ }
+
+ public Polygon getObservedArea() {
+ return observedArea;
+ }
+
+ public void setObservedArea(Polygon observedArea) {
+ this.observedArea = observedArea;
+ setObservedArea = true;
+ }
+
+ /**
+ * Flag indicating the observedArea was set by the user.
+ *
+ * @return Flag indicating the observedArea was set by the user.
+ */
+ public boolean isSetObservedArea() {
+ return setObservedArea;
+ }
+
+ public TimeInterval getPhenomenonTime() {
+ return phenomenonTime;
+ }
+
+ public void setPhenomenonTime(TimeInterval phenomenonTime) {
+ this.phenomenonTime = phenomenonTime;
+ setPhenomenonTime = true;
+ }
+
+ /**
+ * Flag indicating the PhenomenonTime was set by the user.
+ *
+ * @return Flag indicating the PhenomenonTime was set by the user.
+ */
+ public boolean isSetPhenomenonTime() {
+ return setPhenomenonTime;
+ }
+
+ public TimeInterval getResultTime() {
+ return resultTime;
+ }
+
+ public void setResultTime(TimeInterval resultTime) {
+ this.resultTime = resultTime;
+ setResultTime = true;
+ }
+
+ /**
+ * Flag indicating the ResultTime was set by the user.
+ *
+ * @return Flag indicating the ResultTime was set by the user.
+ */
+ public boolean isSetResultTime() {
+ return setResultTime;
+ }
+
+ public Sensor getSensor() {
+ return sensor;
+ }
+
+ public void setSensor(Sensor sensor) {
+ this.sensor = sensor;
+ setSensor = sensor != null;
+ }
+
+ /**
+ * Flag indicating the Sensor was set by the user.
+ *
+ * @return Flag indicating the Sensor was set by the user.
+ */
+ public boolean isSetSensor() {
+ return setSensor;
+ }
+
+ public Thing getThing() {
+ return thing;
+ }
+
+ public void setThing(Thing thing) {
+ this.thing = thing;
+ setThing = thing != null;
+ }
+
+ /**
+ * Flag indicating the Thing was set by the user.
+ *
+ * @return Flag indicating the Thing was set by the user.
+ */
+ public boolean isSetThing() {
+ return setThing;
+ }
+
+ public EntitySet getObservations() {
+ return observations;
+ }
+
+ public void setObservations(EntitySet observations) {
+ this.observations = observations;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ super.hashCode(),
+ observationType,
+ observedArea,
+ phenomenonTime,
+ resultTime,
+ sensor,
+ thing,
+ observations);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final AbstractDatastream other = (AbstractDatastream) obj;
+ return super.equals(other)
+ && Objects.equals(observationType, other.observationType)
+ && Objects.equals(observedArea, other.observedArea)
+ && Objects.equals(phenomenonTime, other.phenomenonTime)
+ && Objects.equals(resultTime, other.resultTime)
+ && Objects.equals(sensor, other.sensor)
+ && Objects.equals(thing, other.thing)
+ && Objects.equals(observations, other.observations);
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Datastream.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Datastream.java
index 0b2f1aca4..5a1a298dc 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Datastream.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Datastream.java
@@ -17,304 +17,99 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.builder.ObservedPropertyBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.builder.SensorBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.builder.ThingBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
-import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
-import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInterval;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.model.ext.UnitOfMeasurement;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import de.fraunhofer.iosb.ilt.sta.path.ResourcePathElement;
-import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
-import org.geojson.Polygon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
- * @author jab
+ * @author jab, scf
*/
-public class Datastream extends AbstractEntity {
+public class Datastream extends AbstractDatastream {
/**
* The logger for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(Datastream.class);
- private String name;
- private String description;
- private String observationType;
- private Map properties;
private UnitOfMeasurement unitOfMeasurement;
- private Polygon observedArea; // reference to GeoJSON library
- private TimeInterval phenomenonTime;
- private TimeInterval resultTime;
- private Sensor sensor;
private ObservedProperty observedProperty;
- private Thing thing;
- private EntitySet observations;
- private boolean setName;
- private boolean setDescription;
- private boolean setObservationType;
private boolean setUnitOfMeasurement;
- private boolean setObservedArea;
- private boolean setPhenomenonTime;
- private boolean setResultTime;
- private boolean setSensor;
private boolean setObservedProperty;
- private boolean setThing;
- private boolean setProperties;
public Datastream() {
- this.observations = new EntitySetImpl<>(EntityType.Observation);
- this.unitOfMeasurement = new UnitOfMeasurement();
+ this(true, null);
}
- public Datastream(Id id,
- String selfLink,
- String navigationLink,
- String name,
- String description,
- String observationType,
- Map properties,
- UnitOfMeasurement unitOfMeasurement,
- Polygon observedArea,
- TimeInterval phenomenonTime,
- TimeInterval resultTime,
- Sensor sensor,
- ObservedProperty observedProperty,
- Thing thing,
- EntitySet observations) {
- super(id, selfLink, navigationLink);
- this.name = name;
- this.description = description;
- this.observationType = observationType;
- this.unitOfMeasurement = unitOfMeasurement;
- this.observedArea = observedArea;
- this.phenomenonTime = phenomenonTime;
- this.resultTime = resultTime;
- this.sensor = sensor;
- this.observedProperty = observedProperty;
- this.thing = thing;
- this.observations = observations;
- if (properties != null && !properties.isEmpty()) {
- this.properties = new HashMap<>(properties);
+ public Datastream(Id id) {
+ this(true, id);
+ }
+
+ public Datastream(boolean onlyId, Id id) {
+ super(id);
+ if (!onlyId) {
+ this.unitOfMeasurement = new UnitOfMeasurement();
}
}
@Override
public EntityType getEntityType() {
- return EntityType.Datastream;
+ return EntityType.DATASTREAM;
}
@Override
- public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException {
- ResourcePathElement parent = containingSet.getParent();
- if (parent != null && parent instanceof EntityPathElement) {
- EntityPathElement parentEntity = (EntityPathElement) parent;
- Id parentId = parentEntity.getId();
- if (parentId != null) {
- switch (parentEntity.getEntityType()) {
- case ObservedProperty:
- setObservedProperty(new ObservedPropertyBuilder().setId(parentId).build());
- LOGGER.debug("Set observedPropertyId to {}.", parentId);
- break;
-
- case Sensor:
- setSensor(new SensorBuilder().setId(parentId).build());
- LOGGER.debug("Set sensorId to {}.", parentId);
- break;
-
- case Thing:
- setThing(new ThingBuilder().setId(parentId).build());
- LOGGER.debug("Set thingId to {}.", parentId);
- break;
- }
- }
+ protected boolean checkParent(EntityPathElement parentEntity, Id parentId) {
+ if (parentEntity.getEntityType() == EntityType.OBSERVEDPROPERTY) {
+ setObservedProperty(new ObservedProperty(parentId));
+ LOGGER.debug("Set observedPropertyId to {}.", parentId);
+ return true;
}
- super.complete(containingSet);
+ return super.checkParent(parentEntity, parentId);
}
@Override
public void setEntityPropertiesSet() {
- setDescription = true;
- setObservationType = true;
+ super.setEntityPropertiesSet();
setUnitOfMeasurement = true;
- setProperties = true;
- }
-
- public String getName() {
- return name;
- }
-
- /**
- * @return the description
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * @return the observationType
- */
- public String getObservationType() {
- return observationType;
}
- public Map getProperties() {
- return properties;
- }
-
- /**
- * @return the unitOfMeasurement
- */
public UnitOfMeasurement getUnitOfMeasurement() {
return unitOfMeasurement;
}
- /**
- * @return the observedArea
- */
- public Polygon getObservedArea() {
- return observedArea;
- }
-
- /**
- * @return the phenomenonTime
- */
- public TimeInterval getPhenomenonTime() {
- return phenomenonTime;
- }
-
- /**
- * @return the resultTime
- */
- public TimeInterval getResultTime() {
- return resultTime;
- }
-
- /**
- * @return the sensor
- */
- public Sensor getSensor() {
- return sensor;
- }
-
- /**
- * @param observedArea the observedArea to set
- */
- public void setObservedArea(Polygon observedArea) {
- this.observedArea = observedArea;
- setObservedArea = true;
- }
-
- /**
- * @param phenomenonTime the phenomenonTime to set
- */
- public void setPhenomenonTime(TimeInterval phenomenonTime) {
- this.phenomenonTime = phenomenonTime;
- setPhenomenonTime = true;
+ public void setUnitOfMeasurement(UnitOfMeasurement unitOfMeasurement) {
+ this.unitOfMeasurement = unitOfMeasurement;
+ setUnitOfMeasurement = unitOfMeasurement != null;
}
- /**
- * @param resultTime the resultTime to set
- */
- public void setResultTime(TimeInterval resultTime) {
- this.resultTime = resultTime;
- setResultTime = true;
+ public boolean isSetUnitOfMeasurement() {
+ return setUnitOfMeasurement;
}
- /**
- * @return the observedProperty
- */
public ObservedProperty getObservedProperty() {
return observedProperty;
}
- public void setName(String name) {
- this.name = name;
- setName = true;
- }
-
- /**
- * @param description the description to set
- */
- public void setDescription(String description) {
- this.description = description;
- setDescription = true;
- }
-
- /**
- * @param observationType the observationType to set
- */
- public void setObservationType(String observationType) {
- this.observationType = observationType;
- setObservationType = true;
- }
-
- /**
- * @param unitOfMeasurement the unitOfMeasurement to set
- */
- public void setUnitOfMeasurement(UnitOfMeasurement unitOfMeasurement) {
- this.unitOfMeasurement = unitOfMeasurement;
- setUnitOfMeasurement = true;
- }
-
- /**
- * @param sensor the sensor to set
- */
- public void setSensor(Sensor sensor) {
- this.sensor = sensor;
- setSensor = true;
- }
-
- /**
- * @param observedProperty the observedProperty to set
- */
public void setObservedProperty(ObservedProperty observedProperty) {
this.observedProperty = observedProperty;
- setObservedProperty = true;
+ setObservedProperty = observedProperty != null;
}
/**
- * @return the thing
+ * @return true if the ObservedProperty was explicitly set.
*/
- public Thing getThing() {
- return thing;
- }
-
- /**
- * @param thing the thing to set
- */
- public void setThing(Thing thing) {
- this.thing = thing;
- setThing = true;
+ public boolean isSetObservedProperty() {
+ return setObservedProperty;
}
@Override
public int hashCode() {
- int hash = 5;
- hash = 29 * hash + Objects.hashCode(this.name);
- hash = 29 * hash + Objects.hashCode(this.description);
- hash = 29 * hash + Objects.hashCode(this.observationType);
- hash = 29 * hash + Objects.hashCode(this.unitOfMeasurement);
- hash = 29 * hash + Objects.hashCode(this.observedArea);
- hash = 29 * hash + Objects.hashCode(this.phenomenonTime);
- hash = 29 * hash + Objects.hashCode(this.resultTime);
- hash = 29 * hash + Objects.hashCode(this.sensor);
- hash = 29 * hash + Objects.hashCode(this.observedProperty);
- hash = 29 * hash + Objects.hashCode(this.properties);
- hash = 29 * hash + Objects.hashCode(this.thing);
- return hash;
+ return Objects.hash(super.hashCode(), unitOfMeasurement, observedProperty);
}
@Override
@@ -329,133 +124,9 @@ public boolean equals(Object obj) {
return false;
}
final Datastream other = (Datastream) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.description, other.description)) {
- return false;
- }
- if (!Objects.equals(this.observationType, other.observationType)) {
- return false;
- }
- if (!Objects.equals(this.observedArea, other.observedArea)) {
- return false;
- }
- if (!Objects.equals(this.phenomenonTime, other.phenomenonTime)) {
- return false;
- }
- if (!Objects.equals(this.resultTime, other.resultTime)) {
- return false;
- }
- if (!Objects.equals(this.sensor, other.sensor)) {
- return false;
- }
- if (!Objects.equals(this.observedProperty, other.observedProperty)) {
- return false;
- }
- if (!Objects.equals(this.thing, other.thing)) {
- return false;
- }
- if (!Objects.equals(this.properties, other.properties)) {
- return false;
- }
- return true;
- }
-
- /**
- * @return the observations
- */
- public EntitySet getObservations() {
- return observations;
- }
-
- /**
- * @param observations the observations to set
- */
- public void setObservations(EntitySet observations) {
- this.observations = observations;
- }
-
- public void setProperties(Map properties) {
- if (properties != null && properties.isEmpty()) {
- properties = null;
- }
- this.properties = properties;
- setProperties = true;
- }
-
- public boolean isSetName() {
- return setName;
- }
-
- /**
- * @return the setDescription
- */
- public boolean isSetDescription() {
- return setDescription;
- }
-
- /**
- * @return the setObservationType
- */
- public boolean isSetObservationType() {
- return setObservationType;
- }
-
- /**
- * @return the setObservedArea
- */
- public boolean isSetObservedArea() {
- return setObservedArea;
- }
-
- /**
- * @return the setPhenomenonTime
- */
- public boolean isSetPhenomenonTime() {
- return setPhenomenonTime;
- }
-
- /**
- * @return the setResultTime
- */
- public boolean isSetResultTime() {
- return setResultTime;
- }
-
- /**
- * @return the setSensor
- */
- public boolean isSetSensor() {
- return setSensor;
- }
-
- /**
- * @return the setObservedProperty
- */
- public boolean isSetObservedProperty() {
- return setObservedProperty;
- }
-
- public boolean isSetProperties() {
- return setProperties;
- }
-
- /**
- * @return the setThing
- */
- public boolean isSetThing() {
- return setThing;
- }
-
- /**
- * @return the setUnitOfMeasurement
- */
- public boolean isSetUnitOfMeasurement() {
- return setUnitOfMeasurement;
+ return super.equals(other)
+ && Objects.equals(observedProperty, other.observedProperty)
+ && Objects.equals(unitOfMeasurement, other.unitOfMeasurement);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/FeatureOfInterest.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/FeatureOfInterest.java
index 24e16b8fa..5043d9743 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/FeatureOfInterest.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/FeatureOfInterest.java
@@ -17,158 +17,84 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.NamedEntity;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
/**
*
- * @author jab
+ * @author jab, scf
*/
-public class FeatureOfInterest extends AbstractEntity {
+public class FeatureOfInterest extends NamedEntity {
- private String name;
- private String description;
private String encodingType;
private Object feature;
- private Map properties;
private EntitySet observations;
- private boolean setName;
- private boolean setDescription;
private boolean setEncodingType;
private boolean setFeature;
- private boolean setProperties;
public FeatureOfInterest() {
- this.observations = new EntitySetImpl<>(EntityType.Observation);
+ this(null);
}
- public FeatureOfInterest(
- Id id,
- String selfLink,
- String navigationLink,
- String name,
- String description,
- String encodingType,
- Object feature,
- Map properties,
- EntitySet observations) {
- super(id, selfLink, navigationLink);
- this.name = name;
- this.description = description;
- this.encodingType = encodingType;
- this.feature = feature;
- this.observations = observations;
- if (properties != null && !properties.isEmpty()) {
- this.properties = new HashMap<>(properties);
- }
+ public FeatureOfInterest(Id id) {
+ super(id);
+ this.observations = new EntitySetImpl<>(EntityType.OBSERVATION);
}
@Override
public EntityType getEntityType() {
- return EntityType.FeatureOfInterest;
+ return EntityType.FEATUREOFINTEREST;
}
@Override
public void setEntityPropertiesSet() {
- setDescription = true;
+ super.setEntityPropertiesSet();
setEncodingType = true;
setFeature = true;
- setProperties = true;
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
}
public String getEncodingType() {
return encodingType;
}
- public Object getFeature() {
- return feature;
- }
-
- public Map getProperties() {
- return properties;
- }
-
- public EntitySet getObservations() {
- return observations;
- }
-
- public boolean isSetName() {
- return setName;
- }
-
- public boolean isSetDescription() {
- return setDescription;
+ public void setEncodingType(String encodingType) {
+ this.encodingType = encodingType;
+ setEncodingType = encodingType != null;
}
public boolean isSetEncodingType() {
return setEncodingType;
}
- public boolean isSetFeature() {
- return setFeature;
- }
-
- public boolean isSetProperties() {
- return setProperties;
- }
-
- public void setName(String name) {
- this.name = name;
- setName = true;
+ public Object getFeature() {
+ return feature;
}
- public void setDescription(String description) {
- this.description = description;
- setDescription = true;
+ public void setFeature(Object feature) {
+ setFeature = feature != null;
+ this.feature = feature;
}
- public void setEncodingType(String encodingType) {
- this.encodingType = encodingType;
- setEncodingType = true;
+ public boolean isSetFeature() {
+ return setFeature;
}
- public void setFeature(Object feature) {
- setFeature = true;
- this.feature = feature;
+ public EntitySet getObservations() {
+ return observations;
}
public void setObservations(EntitySet observations) {
this.observations = observations;
}
- public void setProperties(Map properties) {
- if (properties != null && properties.isEmpty()) {
- properties = null;
- }
- this.properties = properties;
- setProperties = true;
- }
-
@Override
public int hashCode() {
- int hash = 7;
- hash = 41 * hash + Objects.hashCode(this.name);
- hash = 41 * hash + Objects.hashCode(this.description);
- hash = 41 * hash + Objects.hashCode(this.encodingType);
- hash = 41 * hash + Objects.hashCode(this.feature);
- hash = 41 * hash + Objects.hashCode(this.observations);
- hash = 41 * hash + Objects.hashCode(this.properties);
- return hash;
+ return Objects.hash(super.hashCode(), encodingType, feature, observations);
}
@Override
@@ -183,28 +109,10 @@ public boolean equals(Object obj) {
return false;
}
final FeatureOfInterest other = (FeatureOfInterest) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.description, other.description)) {
- return false;
- }
- if (!Objects.equals(this.encodingType, other.encodingType)) {
- return false;
- }
- if (!Objects.equals(this.feature, other.feature)) {
- return false;
- }
- if (!Objects.equals(this.observations, other.observations)) {
- return false;
- }
- if (!Objects.equals(this.properties, other.properties)) {
- return false;
- }
- return true;
+ return super.equals(other)
+ && Objects.equals(encodingType, other.encodingType)
+ && Objects.equals(feature, other.feature)
+ && Objects.equals(observations, other.observations);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/HistoricalLocation.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/HistoricalLocation.java
index 99198c606..d05b355ab 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/HistoricalLocation.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/HistoricalLocation.java
@@ -17,12 +17,11 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.builder.ThingBuilder;
import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInstant;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
@@ -34,7 +33,7 @@
/**
*
- * @author jab
+ * @author jab, scf
*/
public class HistoricalLocation extends AbstractEntity {
@@ -50,25 +49,17 @@ public class HistoricalLocation extends AbstractEntity {
private boolean setThing;
public HistoricalLocation() {
- this.locations = new EntitySetImpl<>(EntityType.Location);
+ this(null);
}
- public HistoricalLocation(
- Id id,
- String selfLink,
- String navigationLink,
- TimeInstant time,
- Thing thing,
- EntitySet locations) {
- super(id, selfLink, navigationLink);
- this.time = time;
- this.thing = thing;
- this.locations = locations;
+ public HistoricalLocation(Id id) {
+ super(id);
+ this.locations = new EntitySetImpl<>(EntityType.LOCATION);
}
@Override
public EntityType getEntityType() {
- return EntityType.HistoricalLocation;
+ return EntityType.HISTORICALLOCATION;
}
@Override
@@ -78,15 +69,15 @@ public void complete(EntitySetPathElement containingSet) throws IncompleteEntity
throw new IllegalStateException("Set of type " + type + " can not contain a " + getEntityType());
}
ResourcePathElement parent = containingSet.getParent();
- if (parent != null && parent instanceof EntityPathElement) {
+ if (parent instanceof EntityPathElement) {
EntityPathElement parentEntity = (EntityPathElement) parent;
Id parentId = parentEntity.getId();
if (parentId != null) {
- switch (parentEntity.getEntityType()) {
- case Thing:
- setThing(new ThingBuilder().setId(parentId).build());
- LOGGER.debug("Set thingId to {}.", parentId);
- break;
+ if (parentEntity.getEntityType() == EntityType.THING) {
+ setThing(new Thing(parentId));
+ LOGGER.debug("Set thingId to {}.", parentId);
+ } else {
+ LOGGER.error("Incorrect 'parent' entity type for {}: {}", getEntityType(), parentEntity.getEntityType());
}
}
}
@@ -105,30 +96,30 @@ public TimeInstant getTime() {
return time;
}
- public Thing getThing() {
- return thing;
- }
-
- public EntitySet getLocations() {
- return locations;
+ public void setTime(TimeInstant time) {
+ this.time = time;
+ setTime = time != null;
}
public boolean isSetTime() {
return setTime;
}
- public boolean isSetThing() {
- return setThing;
- }
-
- public void setTime(TimeInstant time) {
- this.time = time;
- setTime = true;
+ public Thing getThing() {
+ return thing;
}
public void setThing(Thing thing) {
this.thing = thing;
- setThing = true;
+ setThing = thing != null;
+ }
+
+ public boolean isSetThing() {
+ return setThing;
+ }
+
+ public EntitySet getLocations() {
+ return locations;
}
public void setLocations(EntitySet locations) {
@@ -137,11 +128,7 @@ public void setLocations(EntitySet locations) {
@Override
public int hashCode() {
- int hash = 5;
- hash = 97 * hash + Objects.hashCode(this.time);
- hash = 97 * hash + Objects.hashCode(this.thing);
- hash = 97 * hash + Objects.hashCode(this.locations);
- return hash;
+ return Objects.hash(time, thing, locations);
}
@Override
@@ -156,18 +143,10 @@ public boolean equals(Object obj) {
return false;
}
final HistoricalLocation other = (HistoricalLocation) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.time, other.time)) {
- return false;
- }
- if (!Objects.equals(this.thing, other.thing)) {
- return false;
- }
- if (!Objects.equals(this.locations, other.locations)) {
- return false;
- }
- return true;
+ return super.equals(other)
+ && Objects.equals(this.time, other.time)
+ && Objects.equals(this.thing, other.thing)
+ && Objects.equals(this.locations, other.locations);
}
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Location.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Location.java
index 421f05a2b..83e1485a5 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Location.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Location.java
@@ -17,91 +17,64 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.builder.ThingBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.NamedEntity;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePathElement;
import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
- * @author jab
+ * @author jab, scf
*/
-public class Location extends AbstractEntity {
+public class Location extends NamedEntity {
/**
* The logger for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(Location.class);
- private String name;
- private String description;
private String encodingType;
private Object location;
- private Map properties;
private EntitySet historicalLocations; // 0..*
private EntitySet things;
- private boolean setName;
- private boolean setDescription;
private boolean setEncodingType;
private boolean setLocation;
- private boolean setProperties;
public Location() {
- this.things = new EntitySetImpl<>(EntityType.Thing);
- this.historicalLocations = new EntitySetImpl<>(EntityType.HistoricalLocation);
- }
-
- public Location(
- Id id,
- String selfLink,
- String navigationLink,
- String name,
- String description,
- String encodingType,
- Object location,
- Map properties,
- EntitySet historicalLocations,
- EntitySet things) {
- super(id, selfLink, navigationLink);
- this.name = name;
- this.description = description;
- this.encodingType = encodingType;
- this.location = location;
- this.historicalLocations = historicalLocations;
- this.things = things;
- if (properties != null && !properties.isEmpty()) {
- this.properties = new HashMap<>(properties);
- }
+ this(null);
+ }
+
+ public Location(Id id) {
+ super(id);
+ this.things = new EntitySetImpl<>(EntityType.THING);
+ this.historicalLocations = new EntitySetImpl<>(EntityType.HISTORICALLOCATION);
}
@Override
public EntityType getEntityType() {
- return EntityType.Location;
+ return EntityType.LOCATION;
}
@Override
public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException {
ResourcePathElement parent = containingSet.getParent();
- if (parent != null && parent instanceof EntityPathElement) {
+ if (parent instanceof EntityPathElement) {
EntityPathElement parentEntity = (EntityPathElement) parent;
Id parentId = parentEntity.getId();
if (parentId != null) {
- switch (parentEntity.getEntityType()) {
- case Thing:
- getThings().add(new ThingBuilder().setId(parentId).build());
- LOGGER.debug("Added thingId to {}.", parentId);
- break;
+ if (parentEntity.getEntityType() == EntityType.THING) {
+ getThings().add(new Thing(parentId));
+ LOGGER.debug("Added thingId to {}.", parentId);
+ } else {
+ LOGGER.error("Incorrect 'parent' entity type for {}: {}", getEntityType(), parentEntity.getEntityType());
}
}
}
@@ -110,107 +83,56 @@ public void complete(EntitySetPathElement containingSet) throws IncompleteEntity
@Override
public void setEntityPropertiesSet() {
- setDescription = true;
+ super.setEntityPropertiesSet();
setEncodingType = true;
setLocation = true;
- setProperties = true;
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
}
public String getEncodingType() {
return encodingType;
}
- public Object getLocation() {
- return location;
- }
-
- public Map getProperties() {
- return properties;
- }
-
- public EntitySet getHistoricalLocations() {
- return historicalLocations;
- }
-
- public EntitySet getThings() {
- return things;
- }
-
- public boolean isSetName() {
- return setName;
- }
-
- public boolean isSetDescription() {
- return setDescription;
+ public void setEncodingType(String encodingType) {
+ this.encodingType = encodingType;
+ setEncodingType = encodingType != null;
}
public boolean isSetEncodingType() {
return setEncodingType;
}
- public boolean isSetLocation() {
- return setLocation;
- }
-
- public boolean isSetProperties() {
- return setProperties;
- }
-
- public void setName(String name) {
- this.name = name;
- setName = true;
+ public Object getLocation() {
+ return location;
}
- public void setDescription(String description) {
- this.description = description;
- setDescription = true;
+ public void setLocation(Object location) {
+ this.location = location;
+ setLocation = location != null;
}
- public void setEncodingType(String encodingType) {
- this.encodingType = encodingType;
- setEncodingType = true;
+ public boolean isSetLocation() {
+ return setLocation;
}
- public void setLocation(Object location) {
- this.location = location;
- setLocation = true;
+ public EntitySet getHistoricalLocations() {
+ return historicalLocations;
}
public void setHistoricalLocations(EntitySet historicalLocations) {
this.historicalLocations = historicalLocations;
}
- public void setThings(EntitySet things) {
- this.things = things;
+ public EntitySet getThings() {
+ return things;
}
- public void setProperties(Map properties) {
- if (properties != null && properties.isEmpty()) {
- properties = null;
- }
- this.properties = properties;
- setProperties = true;
+ public void setThings(EntitySet things) {
+ this.things = things;
}
@Override
public int hashCode() {
- int hash = 3;
- hash = 53 * hash + Objects.hashCode(this.name);
- hash = 53 * hash + Objects.hashCode(this.description);
- hash = 53 * hash + Objects.hashCode(this.encodingType);
- hash = 53 * hash + Objects.hashCode(this.location);
- hash = 53 * hash + Objects.hashCode(this.historicalLocations);
- hash = 53 * hash + Objects.hashCode(this.properties);
- hash = 53 * hash + Objects.hashCode(this.things);
- return hash;
+ return Objects.hash(super.hashCode(), encodingType, location, historicalLocations, things);
}
@Override
@@ -225,30 +147,11 @@ public boolean equals(Object obj) {
return false;
}
final Location other = (Location) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.description, other.description)) {
- return false;
- }
- if (!Objects.equals(this.encodingType, other.encodingType)) {
- return false;
- }
- if (!Objects.equals(this.location, other.location)) {
- return false;
- }
- if (!Objects.equals(this.historicalLocations, other.historicalLocations)) {
- return false;
- }
- if (!Objects.equals(this.things, other.things)) {
- return false;
- }
- if (!Objects.equals(this.properties, other.properties)) {
- return false;
- }
- return true;
+ return super.equals(other)
+ && Objects.equals(encodingType, other.encodingType)
+ && Objects.equals(location, other.location)
+ && Objects.equals(historicalLocations, other.historicalLocations)
+ && Objects.equals(things, other.things);
}
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/MultiDatastream.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/MultiDatastream.java
index 698f2ac58..53e8890a1 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/MultiDatastream.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/MultiDatastream.java
@@ -17,130 +17,46 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.builder.SensorBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.builder.ThingBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInterval;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.ext.ObservationType;
import de.fraunhofer.iosb.ilt.sta.model.ext.UnitOfMeasurement;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
-import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import de.fraunhofer.iosb.ilt.sta.path.ResourcePathElement;
import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
-import org.geojson.Polygon;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
*
- * @author jab
+ * @author jab, scf
*/
-public class MultiDatastream extends AbstractEntity {
+public class MultiDatastream extends AbstractDatastream {
- /**
- * The logger for this class.
- */
- private static final Logger LOGGER = LoggerFactory.getLogger(MultiDatastream.class);
- private String name;
- private String description;
- private String observationType = "http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_ComplexObservation";
- private Map properties;
private List multiObservationDataTypes;
private List unitOfMeasurements;
- private Polygon observedArea; // reference to GeoJSON library
- private TimeInterval phenomenonTime;
- private TimeInterval resultTime;
- private Sensor sensor;
private EntitySet observedProperties;
- private Thing thing;
- private EntitySet observations;
- private boolean setName;
- private boolean setDescription;
- private boolean setObservationType;
private boolean setMultiObservationDataTypes;
private boolean setUnitOfMeasurements;
- private boolean setObservedArea;
- private boolean setPhenomenonTime;
- private boolean setResultTime;
- private boolean setSensor;
private boolean setObservedProperties;
- private boolean setThing;
- private boolean setProperties;
public MultiDatastream() {
- this.observations = new EntitySetImpl<>(EntityType.Observation);
- this.observedProperties = new EntitySetImpl<>(EntityType.ObservedProperty);
- this.unitOfMeasurements = new ArrayList<>();
- this.multiObservationDataTypes = new ArrayList<>();
+ this(null);
}
- public MultiDatastream(Id id,
- String selfLink,
- String navigationLink,
- String name,
- String description,
- Map properties,
- List multiObservationDataTypes,
- List unitOfMeasurements,
- Polygon observedArea,
- TimeInterval phenomenonTime,
- TimeInterval resultTime,
- Sensor sensor,
- EntitySet observedProperties,
- Thing thing,
- EntitySet observations) {
- super(id, selfLink, navigationLink);
- this.name = name;
- this.description = description;
- this.multiObservationDataTypes = multiObservationDataTypes;
- this.unitOfMeasurements = unitOfMeasurements;
- this.observedArea = observedArea;
- this.phenomenonTime = phenomenonTime;
- this.resultTime = resultTime;
- this.sensor = sensor;
- this.observedProperties = observedProperties;
- this.thing = thing;
- this.observations = observations;
- if (properties != null && !properties.isEmpty()) {
- this.properties = new HashMap<>(properties);
- }
+ public MultiDatastream(Id id) {
+ super(id);
+ observedProperties = new EntitySetImpl<>(EntityType.OBSERVEDPROPERTY);
+ unitOfMeasurements = new ArrayList<>();
+ multiObservationDataTypes = new ArrayList<>();
+ setObservationTypeIntern(ObservationType.COMPLEX_OBSERVATION.getCode());
}
@Override
public EntityType getEntityType() {
- return EntityType.MultiDatastream;
- }
-
- @Override
- public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException {
- ResourcePathElement parent = containingSet.getParent();
- if (parent != null && parent instanceof EntityPathElement) {
- EntityPathElement parentEntity = (EntityPathElement) parent;
- Id parentId = parentEntity.getId();
- if (parentId != null) {
- switch (parentEntity.getEntityType()) {
- case Sensor:
- setSensor(new SensorBuilder().setId(parentId).build());
- LOGGER.debug("Set sensorId to {}.", parentId);
- break;
-
- case Thing:
- setThing(new ThingBuilder().setId(parentId).build());
- LOGGER.debug("Set thingId to {}.", parentId);
- break;
- }
- }
- }
- super.complete(containingSet);
+ return EntityType.MULTIDATASTREAM;
}
@Override
@@ -148,11 +64,10 @@ public void complete(boolean entityPropertiesOnly) throws IncompleteEntityExcept
if (unitOfMeasurements.size() != multiObservationDataTypes.size()) {
throw new IllegalStateException("Size of list of unitOfMeasurements (" + unitOfMeasurements.size() + ") is not equal to size of multiObservationDataTypes (" + multiObservationDataTypes.size() + ").");
}
- if (!entityPropertiesOnly) {
- if (observedProperties.size() != multiObservationDataTypes.size()) {
- throw new IllegalStateException("Size of list of observedProperties (" + observedProperties.size() + ") is not equal to size of multiObservationDataTypes (" + multiObservationDataTypes.size() + ").");
- }
+ if (!entityPropertiesOnly && observedProperties.size() != multiObservationDataTypes.size()) {
+ throw new IllegalStateException("Size of list of observedProperties (" + observedProperties.size() + ") is not equal to size of multiObservationDataTypes (" + multiObservationDataTypes.size() + ").");
}
+ String observationType = getObservationType();
if (observationType == null || !observationType.equalsIgnoreCase("http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_ComplexObservation")) {
throw new IllegalStateException("ObservationType must be http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_ComplexObservation.");
}
@@ -161,32 +76,8 @@ public void complete(boolean entityPropertiesOnly) throws IncompleteEntityExcept
@Override
public void setEntityPropertiesSet() {
- setDescription = true;
- setObservationType = true;
+ super.setEntityPropertiesSet();
setUnitOfMeasurements = true;
- setProperties = true;
- }
-
- public String getName() {
- return name;
- }
-
- /**
- * @return the description
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * @return the observationType
- */
- public String getObservationType() {
- return observationType;
- }
-
- public Map getProperties() {
- return properties;
}
public List getMultiObservationDataTypes() {
@@ -194,62 +85,40 @@ public List getMultiObservationDataTypes() {
}
/**
- * @return the unitOfMeasurement
- */
- public List getUnitOfMeasurements() {
- return unitOfMeasurements;
- }
-
- /**
- * @return the observedArea
- */
- public Polygon getObservedArea() {
- return observedArea;
- }
-
- /**
- * @return the phenomenonTime
- */
- public TimeInterval getPhenomenonTime() {
- return phenomenonTime;
- }
-
- /**
- * @return the resultTime
+ * @param observationTypes the observationTypes to set
*/
- public TimeInterval getResultTime() {
- return resultTime;
+ public void setMultiObservationDataTypes(List observationTypes) {
+ this.multiObservationDataTypes = observationTypes;
+ setMultiObservationDataTypes = multiObservationDataTypes != null;
}
/**
- * @return the sensor
+ * @return the setMultiObservationDataTypes
*/
- public Sensor getSensor() {
- return sensor;
+ public boolean isSetMultiObservationDataTypes() {
+ return setMultiObservationDataTypes;
}
/**
- * @param observedArea the observedArea to set
+ * @return the unitOfMeasurements
*/
- public void setObservedArea(Polygon observedArea) {
- this.observedArea = observedArea;
- setObservedArea = true;
+ public List getUnitOfMeasurements() {
+ return unitOfMeasurements;
}
/**
- * @param phenomenonTime the phenomenonTime to set
+ * @param unitsOfMeasurement the unitsOfMeasurement to set
*/
- public void setPhenomenonTime(TimeInterval phenomenonTime) {
- this.phenomenonTime = phenomenonTime;
- setPhenomenonTime = true;
+ public void setUnitOfMeasurements(List unitsOfMeasurement) {
+ this.unitOfMeasurements = unitsOfMeasurement;
+ setUnitOfMeasurements = unitOfMeasurements != null;
}
/**
- * @param resultTime the resultTime to set
+ * @return the setUnitOfMeasurements
*/
- public void setResultTime(TimeInterval resultTime) {
- this.resultTime = resultTime;
- setResultTime = true;
+ public boolean isSetUnitOfMeasurements() {
+ return setUnitOfMeasurements;
}
/**
@@ -259,90 +128,24 @@ public EntitySet getObservedProperties() {
return observedProperties;
}
- public void setName(String name) {
- this.name = name;
- setName = true;
- }
-
- /**
- * @param description the description to set
- */
- public void setDescription(String description) {
- this.description = description;
- setDescription = true;
- }
-
- /**
- * @param observationType the observationType to set
- */
- public void setObservationType(String observationType) {
- this.observationType = observationType;
- setObservationType = true;
- }
-
- /**
- * @param observationTypes the observationTypes to set
- */
- public void setMultiObservationDataTypes(List observationTypes) {
- this.multiObservationDataTypes = observationTypes;
- setMultiObservationDataTypes = true;
- }
-
- /**
- * @param unitsOfMeasurement the unitsOfMeasurement to set
- */
- public void setUnitOfMeasurements(List unitsOfMeasurement) {
- this.unitOfMeasurements = unitsOfMeasurement;
- setUnitOfMeasurements = true;
- }
-
- /**
- * @param sensor the sensor to set
- */
- public void setSensor(Sensor sensor) {
- this.sensor = sensor;
- setSensor = true;
- }
-
/**
* @param observedProperties the observedProperty to set
*/
public void setObservedProperties(EntitySet observedProperties) {
this.observedProperties = observedProperties;
- setObservedProperties = true;
- }
-
- /**
- * @return the thing
- */
- public Thing getThing() {
- return thing;
+ setObservedProperties = observedProperties != null;
}
/**
- * @param thing the thing to set
+ * @return the setObservedProperty
*/
- public void setThing(Thing thing) {
- this.thing = thing;
- setThing = true;
+ public boolean isSetObservedProperties() {
+ return setObservedProperties;
}
@Override
public int hashCode() {
- int hash = 5;
- hash = 29 * hash + Objects.hashCode(this.name);
- hash = 29 * hash + Objects.hashCode(this.description);
- hash = 29 * hash + Objects.hashCode(this.observationType);
- hash = 29 * hash + Objects.hashCode(this.multiObservationDataTypes);
- hash = 29 * hash + Objects.hashCode(this.unitOfMeasurements);
- hash = 29 * hash + Objects.hashCode(this.observedArea);
- hash = 29 * hash + Objects.hashCode(this.phenomenonTime);
- hash = 29 * hash + Objects.hashCode(this.resultTime);
- hash = 29 * hash + Objects.hashCode(this.sensor);
- hash = 29 * hash + Objects.hashCode(this.observedProperties);
- hash = 29 * hash + Objects.hashCode(this.thing);
- hash = 29 * hash + Objects.hashCode(this.properties);
- return hash;
+ return Objects.hash(super.hashCode(), multiObservationDataTypes, unitOfMeasurements, observedProperties);
}
@Override
@@ -357,140 +160,10 @@ public boolean equals(Object obj) {
return false;
}
final MultiDatastream other = (MultiDatastream) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.description, other.description)) {
- return false;
- }
- if (!Objects.equals(this.observationType, other.observationType)) {
- return false;
- }
- if (!Objects.equals(this.observedArea, other.observedArea)) {
- return false;
- }
- if (!Objects.equals(this.phenomenonTime, other.phenomenonTime)) {
- return false;
- }
- if (!Objects.equals(this.resultTime, other.resultTime)) {
- return false;
- }
- if (!Objects.equals(this.sensor, other.sensor)) {
- return false;
- }
- if (!Objects.equals(this.observedProperties, other.observedProperties)) {
- return false;
- }
- if (!Objects.equals(this.thing, other.thing)) {
- return false;
- }
- if (!Objects.equals(this.properties, other.properties)) {
- return false;
- }
- return true;
- }
-
- /**
- * @return the observations
- */
- public EntitySet getObservations() {
- return observations;
- }
-
- /**
- * @param observations the observations to set
- */
- public void setObservations(EntitySet observations) {
- this.observations = observations;
- }
-
- public void setProperties(Map properties) {
- if (properties != null && properties.isEmpty()) {
- properties = null;
- }
- this.properties = properties;
- setProperties = true;
- }
-
- public boolean isSetName() {
- return setName;
- }
-
- /**
- * @return the setDescription
- */
- public boolean isSetDescription() {
- return setDescription;
- }
-
- /**
- * @return the setObservationType
- */
- public boolean isSetObservationType() {
- return setObservationType;
- }
-
- /**
- * @return the setMultiObservationDataTypes
- */
- public boolean isSetMultiObservationDataTypes() {
- return setMultiObservationDataTypes;
- }
-
- /**
- * @return the setObservedArea
- */
- public boolean isSetObservedArea() {
- return setObservedArea;
- }
-
- /**
- * @return the setPhenomenonTime
- */
- public boolean isSetPhenomenonTime() {
- return setPhenomenonTime;
- }
-
- /**
- * @return the setResultTime
- */
- public boolean isSetResultTime() {
- return setResultTime;
- }
-
- /**
- * @return the setSensor
- */
- public boolean isSetSensor() {
- return setSensor;
- }
-
- /**
- * @return the setObservedProperty
- */
- public boolean isSetObservedProperties() {
- return setObservedProperties;
- }
-
- public boolean isSetProperties() {
- return setProperties;
- }
-
- /**
- * @return the setThing
- */
- public boolean isSetThing() {
- return setThing;
- }
-
- /**
- * @return the setUnitOfMeasurements
- */
- public boolean isSetUnitOfMeasurements() {
- return setUnitOfMeasurements;
+ return super.equals(other)
+ && Objects.equals(multiObservationDataTypes, other.multiObservationDataTypes)
+ && Objects.equals(observedProperties, other.observedProperties)
+ && Objects.equals(unitOfMeasurements, other.unitOfMeasurements);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Observation.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Observation.java
index 9f2226660..39a1ce6a9 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Observation.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Observation.java
@@ -17,20 +17,16 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.builder.DatastreamBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.builder.FeatureOfInterestBuilder;
-import de.fraunhofer.iosb.ilt.sta.model.builder.MultiDatastreamBuilder;
import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInstant;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInterval;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeValue;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePathElement;
import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
-import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.slf4j.Logger;
@@ -38,7 +34,7 @@
/**
*
- * @author jab
+ * @author jab, scf
*/
public class Observation extends AbstractEntity {
@@ -67,61 +63,44 @@ public class Observation extends AbstractEntity {
private boolean setFeatureOfInterest;
public Observation() {
+ this(null);
}
- public Observation(Id id,
- String selfLink,
- String navigationLink,
- TimeValue phenomenonTime,
- TimeInstant resultTime,
- Object result,
- Object resultQuality,
- TimeInterval validTime,
- Map parameters,
- Datastream datastream,
- MultiDatastream multiDatastreams,
- FeatureOfInterest featureOfInterest) {
- super(id, selfLink, navigationLink);
- this.phenomenonTime = phenomenonTime;
- this.resultTime = resultTime;
- this.result = result;
- this.resultQuality = resultQuality;
- this.validTime = validTime;
- if (parameters != null && !parameters.isEmpty()) {
- this.parameters = new HashMap<>(parameters);
- }
- this.datastream = datastream;
- this.multiDatastream = multiDatastreams;
- this.featureOfInterest = featureOfInterest;
+ public Observation(Id id) {
+ super(id);
}
@Override
public EntityType getEntityType() {
- return EntityType.Observation;
+ return EntityType.OBSERVATION;
}
@Override
public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException {
ResourcePathElement parent = containingSet.getParent();
- if (parent != null && parent instanceof EntityPathElement) {
+ if (parent instanceof EntityPathElement) {
EntityPathElement parentEntity = (EntityPathElement) parent;
Id parentId = parentEntity.getId();
if (parentId != null) {
switch (parentEntity.getEntityType()) {
- case Datastream:
- setDatastream(new DatastreamBuilder().setId(parentId).build());
+ case DATASTREAM:
+ setDatastream(new Datastream(parentId));
LOGGER.debug("Set datastreamId to {}.", parentId);
break;
- case MultiDatastream:
- setMultiDatastream(new MultiDatastreamBuilder().setId(parentId).build());
+ case MULTIDATASTREAM:
+ setMultiDatastream(new MultiDatastream(parentId));
LOGGER.debug("Set multiDatastreamId to {}.", parentId);
break;
- case FeatureOfInterest:
- setFeatureOfInterest(new FeatureOfInterestBuilder().setId(parentId).build());
+ case FEATUREOFINTEREST:
+ setFeatureOfInterest(new FeatureOfInterest(parentId));
LOGGER.debug("Set featureOfInterestId to {}.", parentId);
break;
+
+ default:
+ LOGGER.error("Incorrect 'parent' entity type for {}: {}", getEntityType(), parentEntity.getEntityType());
+ break;
}
}
}
@@ -157,135 +136,137 @@ public TimeValue getPhenomenonTime() {
return phenomenonTime;
}
- public TimeInstant getResultTime() {
- return resultTime;
- }
-
- public Object getResult() {
- return result;
+ public void setPhenomenonTime(TimeValue phenomenonTime) {
+ this.phenomenonTime = phenomenonTime;
+ setPhenomenonTime = phenomenonTime != null;
}
- public Object getResultQuality() {
- return resultQuality;
+ public boolean isSetPhenomenonTime() {
+ return setPhenomenonTime;
}
- public TimeInterval getValidTime() {
- return validTime;
+ public TimeInstant getResultTime() {
+ return resultTime;
}
- public Map getParameters() {
- return parameters;
+ public void setResultTime(TimeInstant resultTime) {
+ this.resultTime = resultTime;
+ setResultTime = resultTime != null;
}
- public Datastream getDatastream() {
- return datastream;
+ public boolean isSetResultTime() {
+ return setResultTime;
}
- public MultiDatastream getMultiDatastream() {
- return multiDatastream;
+ public Object getResult() {
+ return result;
}
- public FeatureOfInterest getFeatureOfInterest() {
- return featureOfInterest;
+ public void setResult(Object result) {
+ this.result = result;
+ setResult = true;
}
- public boolean isSetPhenomenonTime() {
- return setPhenomenonTime;
+ public boolean isSetResult() {
+ return setResult;
}
- public boolean isSetResultTime() {
- return setResultTime;
+ public Object getResultQuality() {
+ return resultQuality;
}
- public boolean isSetResult() {
- return setResult;
+ public void setResultQuality(Object resultQuality) {
+ this.resultQuality = resultQuality;
+ setResultQuality = resultQuality != null;
}
public boolean isSetResultQuality() {
return setResultQuality;
}
- public boolean isSetValidTime() {
- return setValidTime;
+ public TimeInterval getValidTime() {
+ return validTime;
}
- public boolean isSetParameters() {
- return setParameters;
+ public void setValidTime(TimeInterval validTime) {
+ this.validTime = validTime;
+ setValidTime = validTime != null;
}
- public boolean isSetDatastream() {
- return setDatastream;
+ public boolean isSetValidTime() {
+ return setValidTime;
}
- public boolean isSetMultiDatastream() {
- return setMultiDatastream;
+ public Map getParameters() {
+ return parameters;
}
- public boolean isSetFeatureOfInterest() {
- return setFeatureOfInterest;
+ public void setParameters(Map parameters) {
+ if (parameters != null && parameters.isEmpty()) {
+ this.parameters = null;
+ } else {
+ this.parameters = parameters;
+ }
+ setParameters = true;
}
- public void setPhenomenonTime(TimeValue phenomenonTime) {
- this.phenomenonTime = phenomenonTime;
- setPhenomenonTime = true;
+ public boolean isSetParameters() {
+ return setParameters;
}
- public void setResultTime(TimeInstant resultTime) {
- this.resultTime = resultTime;
- setResultTime = true;
+ public Datastream getDatastream() {
+ return datastream;
}
- public void setResult(Object result) {
- this.result = result;
- setResult = true;
+ public void setDatastream(Datastream datastream) {
+ this.datastream = datastream;
+ setDatastream = datastream != null;
}
- public void setResultQuality(Object resultQuality) {
- this.resultQuality = resultQuality;
- setResultQuality = true;
+ public boolean isSetDatastream() {
+ return setDatastream;
}
- public void setValidTime(TimeInterval validTime) {
- this.validTime = validTime;
- setValidTime = true;
+ public MultiDatastream getMultiDatastream() {
+ return multiDatastream;
}
- public void setParameters(Map parameters) {
- if (parameters != null && parameters.isEmpty()) {
- parameters = null;
- }
- this.parameters = parameters;
- setParameters = true;
+ public void setMultiDatastream(MultiDatastream multiDatastream) {
+ this.multiDatastream = multiDatastream;
+ setMultiDatastream = multiDatastream != null;
}
- public void setDatastream(Datastream datastream) {
- this.datastream = datastream;
- setDatastream = true;
+ public boolean isSetMultiDatastream() {
+ return setMultiDatastream;
}
- public void setMultiDatastream(MultiDatastream multiDatastream) {
- this.multiDatastream = multiDatastream;
- setMultiDatastream = true;
+ public FeatureOfInterest getFeatureOfInterest() {
+ return featureOfInterest;
}
public void setFeatureOfInterest(FeatureOfInterest featureOfInterest) {
this.featureOfInterest = featureOfInterest;
- setFeatureOfInterest = true;
+ setFeatureOfInterest = featureOfInterest != null;
+ }
+
+ public boolean isSetFeatureOfInterest() {
+ return setFeatureOfInterest;
}
@Override
public int hashCode() {
- int hash = 7;
- hash = 59 * hash + Objects.hashCode(this.phenomenonTime);
- hash = 59 * hash + Objects.hashCode(this.resultTime);
- hash = 59 * hash + Objects.hashCode(this.result);
- hash = 59 * hash + Objects.hashCode(this.resultQuality);
- hash = 59 * hash + Objects.hashCode(this.validTime);
- hash = 59 * hash + Objects.hashCode(this.parameters);
- hash = 59 * hash + Objects.hashCode(this.datastream);
- hash = 59 * hash + Objects.hashCode(this.multiDatastream);
- hash = 59 * hash + Objects.hashCode(this.featureOfInterest);
- return hash;
+ return Objects.hash(
+ super.hashCode(),
+ phenomenonTime,
+ resultTime,
+ result,
+ resultQuality,
+ validTime,
+ parameters,
+ datastream,
+ multiDatastream,
+ featureOfInterest
+ );
}
@Override
@@ -300,37 +281,16 @@ public boolean equals(Object obj) {
return false;
}
final Observation other = (Observation) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.phenomenonTime, other.phenomenonTime)) {
- return false;
- }
- if (!Objects.equals(this.resultTime, other.resultTime)) {
- return false;
- }
- if (!Objects.equals(this.result, other.result)) {
- return false;
- }
- if (!Objects.equals(this.resultQuality, other.resultQuality)) {
- return false;
- }
- if (!Objects.equals(this.validTime, other.validTime)) {
- return false;
- }
- if (!Objects.equals(this.parameters, other.parameters)) {
- return false;
- }
- if (!Objects.equals(this.datastream, other.datastream)) {
- return false;
- }
- if (!Objects.equals(this.multiDatastream, other.multiDatastream)) {
- return false;
- }
- if (!Objects.equals(this.featureOfInterest, other.featureOfInterest)) {
- return false;
- }
- return true;
+ return super.equals(other)
+ && Objects.equals(phenomenonTime, other.phenomenonTime)
+ && Objects.equals(resultTime, other.resultTime)
+ && Objects.equals(result, other.result)
+ && Objects.equals(resultQuality, other.resultQuality)
+ && Objects.equals(validTime, other.validTime)
+ && Objects.equals(parameters, other.parameters)
+ && Objects.equals(datastream, other.datastream)
+ && Objects.equals(multiDatastream, other.multiDatastream)
+ && Objects.equals(featureOfInterest, other.featureOfInterest);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ObservedProperty.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ObservedProperty.java
index d86d1ab8b..3bfb87ab0 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ObservedProperty.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ObservedProperty.java
@@ -17,189 +17,71 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
-import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
-import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.NamedDsHoldingEntity;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
/**
*
- * @author jab
+ * @author jab, scf
*/
-public class ObservedProperty extends AbstractEntity {
+public class ObservedProperty extends NamedDsHoldingEntity {
- private String name;
private String definition;
- private String description;
- private Map properties;
- private EntitySet datastreams;
- private EntitySet multiDatastreams;
- private boolean setName;
private boolean setDefinition;
- private boolean setDescription;
- private boolean setProperties;
public ObservedProperty() {
- this.datastreams = new EntitySetImpl<>(EntityType.Datastream);
- this.multiDatastreams = new EntitySetImpl<>(EntityType.MultiDatastream);
}
- public ObservedProperty(
- Id id,
- String selfLink,
- String navigationLink,
- String name,
- String definition,
- String description,
- Map properties,
- EntitySet datastreams,
- EntitySet multiDatastreams) {
- super(id, selfLink, navigationLink);
- this.name = name;
- this.definition = definition;
- this.description = description;
- this.datastreams = datastreams;
- this.multiDatastreams = multiDatastreams;
- if (properties != null && !properties.isEmpty()) {
- this.properties = new HashMap<>(properties);
- }
- }
-
- @Override
- public int hashCode() {
- int hash = 7;
- hash = 29 * hash + Objects.hashCode(this.name);
- hash = 29 * hash + Objects.hashCode(this.definition);
- hash = 29 * hash + Objects.hashCode(this.description);
- hash = 29 * hash + Objects.hashCode(this.datastreams);
- hash = 29 * hash + Objects.hashCode(this.multiDatastreams);
- hash = 29 * hash + Objects.hashCode(this.properties);
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final ObservedProperty other = (ObservedProperty) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.definition, other.definition)) {
- return false;
- }
- if (!Objects.equals(this.description, other.description)) {
- return false;
- }
- if (!Objects.equals(this.datastreams, other.datastreams)) {
- return false;
- }
- if (!Objects.equals(this.multiDatastreams, other.multiDatastreams)) {
- return false;
- }
- if (!Objects.equals(this.properties, other.properties)) {
- return false;
- }
- return true;
+ public ObservedProperty(Id id) {
+ super(id);
}
@Override
public EntityType getEntityType() {
- return EntityType.ObservedProperty;
+ return EntityType.OBSERVEDPROPERTY;
}
@Override
public void setEntityPropertiesSet() {
- setName = true;
+ super.setEntityPropertiesSet();
setDefinition = true;
- setDescription = true;
- setProperties = true;
- }
-
- public String getName() {
- return name;
}
public String getDefinition() {
return definition;
}
- public String getDescription() {
- return description;
- }
-
- public Map getProperties() {
- return properties;
- }
-
- public EntitySet getDatastreams() {
- return datastreams;
- }
-
- public EntitySet getMultiDatastreams() {
- return multiDatastreams;
- }
-
- public boolean isSetName() {
- return setName;
+ public void setDefinition(String definition) {
+ this.definition = definition;
+ setDefinition = definition != null;
}
public boolean isSetDefinition() {
return setDefinition;
}
- public boolean isSetDescription() {
- return setDescription;
- }
-
- public boolean isSetProperties() {
- return setProperties;
- }
-
- public void setName(String name) {
- this.name = name;
- setName = true;
- }
-
- public void setDefinition(String definition) {
- this.definition = definition;
- setDefinition = true;
- }
-
- public void setDescription(String description) {
- this.description = description;
- setDescription = true;
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), definition);
}
- public void setProperties(Map properties) {
- if (properties != null && properties.isEmpty()) {
- properties = null;
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
}
- this.properties = properties;
- setProperties = true;
- }
-
- public void setDatastreams(EntitySet datastreams) {
- this.datastreams = datastreams;
- }
-
- public void setMultiDatastreams(EntitySet multiDatastreams) {
- this.multiDatastreams = multiDatastreams;
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ObservedProperty other = (ObservedProperty) obj;
+ return super.equals(other)
+ && Objects.equals(definition, other.definition);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Sensor.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Sensor.java
index f3d693f12..ec61dbb4b 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Sensor.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Sensor.java
@@ -17,210 +17,88 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
-import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
-import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.NamedDsHoldingEntity;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
/**
*
- * @author jab
+ * @author jab, scf
*/
-public class Sensor extends AbstractEntity {
+public class Sensor extends NamedDsHoldingEntity {
- private String name;
- private String description;
private String encodingType;
private Object metadata;
- private Map properties;
- private EntitySet datastreams;
- private EntitySet multiDatastreams;
- private boolean setName;
- private boolean setDescription;
private boolean setEncodingType;
private boolean setMetadata;
- private boolean setProperties;
public Sensor() {
- this.datastreams = new EntitySetImpl<>(EntityType.Datastream);
- this.multiDatastreams = new EntitySetImpl<>(EntityType.MultiDatastream);
}
- public Sensor(
- Id id,
- String selfLink,
- String navigationLink,
- String name,
- String description,
- String encodingType,
- Object metadata,
- Map properties,
- EntitySet datastreams,
- EntitySet multiDatastreams) {
- super(id, selfLink, navigationLink);
- this.name = name;
- this.description = description;
- this.encodingType = encodingType;
- this.metadata = metadata;
- this.datastreams = datastreams;
- this.multiDatastreams = multiDatastreams;
- if (properties != null && !properties.isEmpty()) {
- this.properties = new HashMap<>(properties);
- }
- }
-
- @Override
- public int hashCode() {
- int hash = 5;
- hash = 97 * hash + Objects.hashCode(this.name);
- hash = 97 * hash + Objects.hashCode(this.description);
- hash = 97 * hash + Objects.hashCode(this.encodingType);
- hash = 97 * hash + Objects.hashCode(this.metadata);
- hash = 97 * hash + Objects.hashCode(this.datastreams);
- hash = 97 * hash + Objects.hashCode(this.multiDatastreams);
- hash = 97 * hash + Objects.hashCode(this.properties);
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final Sensor other = (Sensor) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.description, other.description)) {
- return false;
- }
- if (!Objects.equals(this.encodingType, other.encodingType)) {
- return false;
- }
- if (!Objects.equals(this.metadata, other.metadata)) {
- return false;
- }
- if (!Objects.equals(this.datastreams, other.datastreams)) {
- return false;
- }
- if (!Objects.equals(this.multiDatastreams, other.multiDatastreams)) {
- return false;
- }
- if (!Objects.equals(this.properties, other.properties)) {
- return false;
- }
- return true;
+ public Sensor(Id id) {
+ super(id);
}
@Override
public EntityType getEntityType() {
- return EntityType.Sensor;
+ return EntityType.SENSOR;
}
@Override
public void setEntityPropertiesSet() {
- setDescription = true;
+ super.setEntityPropertiesSet();
setEncodingType = true;
setMetadata = true;
- setProperties = true;
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
}
public String getEncodingType() {
return encodingType;
}
- public Object getMetadata() {
- return metadata;
- }
-
- public Map getProperties() {
- return properties;
- }
-
- public EntitySet getDatastreams() {
- return datastreams;
- }
-
- public EntitySet getMultiDatastreams() {
- return multiDatastreams;
- }
-
- public boolean isSetName() {
- return setName;
- }
-
- public boolean isSetDescription() {
- return setDescription;
+ public void setEncodingType(String encodingType) {
+ this.encodingType = encodingType;
+ setEncodingType = encodingType != null;
}
public boolean isSetEncodingType() {
return setEncodingType;
}
- public boolean isSetMetadata() {
- return setMetadata;
- }
-
- public boolean isSetProperties() {
- return setProperties;
- }
-
- public void setName(String name) {
- this.name = name;
- setName = true;
- }
-
- public void setDescription(String description) {
- this.description = description;
- setDescription = true;
- }
-
- public void setEncodingType(String encodingType) {
- this.encodingType = encodingType;
- setEncodingType = true;
+ public Object getMetadata() {
+ return metadata;
}
public void setMetadata(Object metadata) {
this.metadata = metadata;
- setMetadata = true;
+ setMetadata = metadata != null;
}
- public void setProperties(Map properties) {
- if (properties != null && properties.isEmpty()) {
- properties = null;
- }
- this.properties = properties;
- setProperties = true;
+ public boolean isSetMetadata() {
+ return setMetadata;
}
- public void setDatastreams(EntitySet datastreams) {
- this.datastreams = datastreams;
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), encodingType, metadata);
}
- public void setMultiDatastreams(EntitySet multiDatastreams) {
- this.multiDatastreams = multiDatastreams;
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Sensor other = (Sensor) obj;
+ return super.equals(other)
+ && Objects.equals(encodingType, other.encodingType)
+ && Objects.equals(metadata, other.metadata);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Thing.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Thing.java
index 68a618e9c..08f368cc1 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Thing.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/Thing.java
@@ -17,159 +17,56 @@
*/
package de.fraunhofer.iosb.ilt.sta.model;
-import de.fraunhofer.iosb.ilt.sta.model.core.AbstractEntity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.NamedDsHoldingEntity;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
/**
*
- * @author jab
+ * @author jab, scf
*/
-public class Thing extends AbstractEntity {
+public class Thing extends NamedDsHoldingEntity {
- private String name;
- private String description;
- private Map properties;
private EntitySet locations; // 0..*
-
private EntitySet historicalLocations; // 0..*
- private EntitySet datastreams; // 0..*
- private EntitySet multiDatastreams; // 0..*
-
- private boolean setName;
- private boolean setDescription;
- private boolean setProperties;
public Thing() {
- this.locations = new EntitySetImpl<>(EntityType.Location);
- this.historicalLocations = new EntitySetImpl<>(EntityType.HistoricalLocation);
- this.datastreams = new EntitySetImpl<>(EntityType.Datastream);
- this.multiDatastreams = new EntitySetImpl<>(EntityType.MultiDatastream);
+ this(null);
}
- public Thing(Id id,
- String selfLink,
- String navigationLink,
- String name,
- String description,
- Map properties,
- EntitySet locations,
- EntitySet historicalLocations,
- EntitySet datastreams,
- EntitySet multiDatastreams) {
- super(id, selfLink, navigationLink);
- this.name = name;
- this.description = description;
- if (properties != null && !properties.isEmpty()) {
- this.properties = new HashMap<>(properties);
- }
- this.locations = locations;
- this.historicalLocations = historicalLocations;
- this.datastreams = datastreams;
- this.multiDatastreams = multiDatastreams;
+ public Thing(Id id) {
+ super(id);
+ this.locations = new EntitySetImpl<>(EntityType.LOCATION);
+ this.historicalLocations = new EntitySetImpl<>(EntityType.HISTORICALLOCATION);
}
@Override
public EntityType getEntityType() {
- return EntityType.Thing;
- }
-
- @Override
- public void setEntityPropertiesSet() {
- setDescription = true;
- setProperties = true;
- }
-
- public String getName() {
- return name;
- }
-
- public String getDescription() {
- return description;
- }
-
- public Map getProperties() {
- return properties;
+ return EntityType.THING;
}
public EntitySet getLocations() {
return locations;
}
- public EntitySet getHistoricalLocations() {
- return historicalLocations;
- }
-
- public EntitySet getDatastreams() {
- return datastreams;
- }
-
- public EntitySet getMultiDatastreams() {
- return multiDatastreams;
- }
-
- public boolean isSetName() {
- return setName;
- }
-
- public boolean isSetDescription() {
- return setDescription;
- }
-
- public boolean isSetProperties() {
- return setProperties;
- }
-
- public void setName(String name) {
- this.name = name;
- setName = true;
- }
-
- public void setDescription(String description) {
- this.description = description;
- setDescription = true;
- }
-
- public void setProperties(Map properties) {
- if (properties != null && properties.isEmpty()) {
- properties = null;
- }
- this.properties = properties;
- setProperties = true;
- }
-
public void setLocations(EntitySet locations) {
this.locations = locations;
}
- public void setHistoricalLocations(EntitySet historicalLocations) {
- this.historicalLocations = historicalLocations;
- }
-
- public void setDatastreams(EntitySet datastreams) {
- this.datastreams = datastreams;
+ public EntitySet getHistoricalLocations() {
+ return historicalLocations;
}
- public void setMultiDatastreams(EntitySet multiDatastreams) {
- this.multiDatastreams = multiDatastreams;
+ public void setHistoricalLocations(EntitySet historicalLocations) {
+ this.historicalLocations = historicalLocations;
}
@Override
public int hashCode() {
- int hash = 7;
- hash = 71 * hash + Objects.hashCode(this.name);
- hash = 71 * hash + Objects.hashCode(this.description);
- hash = 71 * hash + Objects.hashCode(this.properties);
- hash = 71 * hash + Objects.hashCode(this.locations);
- hash = 71 * hash + Objects.hashCode(this.historicalLocations);
- hash = 71 * hash + Objects.hashCode(this.datastreams);
- hash = 71 * hash + Objects.hashCode(this.multiDatastreams);
- return hash;
+ return Objects.hash(super.hashCode(), locations, historicalLocations);
}
@Override
@@ -184,30 +81,8 @@ public boolean equals(Object obj) {
return false;
}
final Thing other = (Thing) obj;
- if (!super.equals(other)) {
- return false;
- }
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.description, other.description)) {
- return false;
- }
- if (!Objects.equals(this.properties, other.properties)) {
- return false;
- }
- if (!Objects.equals(this.locations, other.locations)) {
- return false;
- }
- if (!Objects.equals(this.historicalLocations, other.historicalLocations)) {
- return false;
- }
- if (!Objects.equals(this.datastreams, other.datastreams)) {
- return false;
- }
- if (!Objects.equals(this.multiDatastreams, other.multiDatastreams)) {
- return false;
- }
- return true;
+ return super.equals(other)
+ && Objects.equals(locations, other.locations)
+ && Objects.equals(historicalLocations, other.historicalLocations);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/AbstractEntityBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/AbstractEntityBuilder.java
index fee6cfecc..8a8896158 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/AbstractEntityBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/AbstractEntityBuilder.java
@@ -17,7 +17,7 @@
*/
package de.fraunhofer.iosb.ilt.sta.model.builder;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
/**
* Abstract base class for implementing an EntityBuilder
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/DatastreamBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/DatastreamBuilder.java
index 63f3edd7b..63038fae7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/DatastreamBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/DatastreamBuilder.java
@@ -53,12 +53,11 @@ public class DatastreamBuilder extends AbstractEntityBuilder();
- observations = new EntitySetImpl<>(EntityType.Observation);
+ observations = new EntitySetImpl<>(EntityType.OBSERVATION);
}
public DatastreamBuilder setObservations(EntitySet observations) {
this.observations = observations;
- this.unitOfMeasurement = new UnitOfMeasurement();
return this;
}
@@ -134,22 +133,21 @@ protected DatastreamBuilder getThis() {
@Override
public Datastream build() {
- Datastream ds = new Datastream(
- id,
- selfLink,
- navigationLink,
- name,
- description,
- observationType,
- properties,
- unitOfMeasurement,
- observedArea,
- phenomenonTime,
- resultTime,
- sensor,
- observedProperty,
- thing,
- observations);
+ Datastream ds = new Datastream(id);
+ ds.setSelfLink(selfLink);
+ ds.setNavigationLink(navigationLink);
+ ds.setName(name);
+ ds.setDescription(description);
+ ds.setObservationType(observationType);
+ ds.setProperties(properties);
+ ds.setUnitOfMeasurement(unitOfMeasurement);
+ ds.setObservedArea(observedArea);
+ ds.setPhenomenonTime(phenomenonTime);
+ ds.setResultTime(resultTime);
+ ds.setSensor(sensor);
+ ds.setObservedProperty(observedProperty);
+ ds.setThing(thing);
+ ds.setObservations(observations);
ds.setExportObject(isExportObject());
return ds;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/FeatureOfInterestBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/FeatureOfInterestBuilder.java
index dbac81111..9fc8d0297 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/FeatureOfInterestBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/FeatureOfInterestBuilder.java
@@ -41,7 +41,7 @@ public class FeatureOfInterestBuilder extends AbstractEntityBuilder();
- observations = new EntitySetImpl<>(EntityType.Observation);
+ observations = new EntitySetImpl<>(EntityType.OBSERVATION);
}
public FeatureOfInterestBuilder setName(String name) {
@@ -91,16 +91,15 @@ protected FeatureOfInterestBuilder getThis() {
@Override
public FeatureOfInterest build() {
- FeatureOfInterest foi = new FeatureOfInterest(
- id,
- selfLink,
- navigationLink,
- name,
- description,
- encodingType,
- feature,
- properties,
- observations);
+ FeatureOfInterest foi = new FeatureOfInterest(id);
+ foi.setSelfLink(selfLink);
+ foi.setNavigationLink(navigationLink);
+ foi.setName(name);
+ foi.setDescription(description);
+ foi.setEncodingType(encodingType);
+ foi.setFeature(feature);
+ foi.setProperties(properties);
+ foi.setObservations(observations);
foi.setExportObject(isExportObject());
return foi;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/HistoricalLocationBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/HistoricalLocationBuilder.java
index 31f203ea3..8a1ec2260 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/HistoricalLocationBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/HistoricalLocationBuilder.java
@@ -37,7 +37,7 @@ public class HistoricalLocationBuilder extends AbstractEntityBuilder locations;
public HistoricalLocationBuilder() {
- locations = new EntitySetImpl<>(EntityType.Location);
+ locations = new EntitySetImpl<>(EntityType.LOCATION);
}
public HistoricalLocationBuilder setTime(TimeInstant time) {
@@ -67,7 +67,12 @@ protected HistoricalLocationBuilder getThis() {
@Override
public HistoricalLocation build() {
- HistoricalLocation hl = new HistoricalLocation(id, selfLink, navigationLink, time, thing, locations);
+ HistoricalLocation hl = new HistoricalLocation(id);
+ hl.setSelfLink(selfLink);
+ hl.setNavigationLink(navigationLink);
+ hl.setTime(time);
+ hl.setThing(thing);
+ hl.setLocations(locations);
hl.setExportObject(isExportObject());
return hl;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/LocationBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/LocationBuilder.java
index 47833eb27..6c607f6e8 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/LocationBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/LocationBuilder.java
@@ -43,8 +43,8 @@ public class LocationBuilder extends AbstractEntityBuilder();
- things = new EntitySetImpl<>(EntityType.Thing);
- historicalLocations = new EntitySetImpl<>(EntityType.HistoricalLocation);
+ things = new EntitySetImpl<>(EntityType.THING);
+ historicalLocations = new EntitySetImpl<>(EntityType.HISTORICALLOCATION);
}
public LocationBuilder setName(String name) {
@@ -104,17 +104,16 @@ protected LocationBuilder getThis() {
@Override
public Location build() {
- Location l = new Location(
- id,
- selfLink,
- navigationLink,
- name,
- description,
- encodingType,
- location,
- properties,
- historicalLocations,
- things);
+ Location l = new Location(id);
+ l.setSelfLink(selfLink);
+ l.setNavigationLink(navigationLink);
+ l.setName(name);
+ l.setDescription(description);
+ l.setEncodingType(encodingType);
+ l.setLocation(location);
+ l.setProperties(properties);
+ l.setHistoricalLocations(historicalLocations);
+ l.setThings(things);
l.setExportObject(isExportObject());
return l;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/MultiDatastreamBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/MultiDatastreamBuilder.java
index cc5637811..ba5c4dfcb 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/MultiDatastreamBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/MultiDatastreamBuilder.java
@@ -42,6 +42,7 @@ public class MultiDatastreamBuilder extends AbstractEntityBuilder multiObservationDataTypes;
private List unitOfMeasurements;
private Polygon observedArea;
@@ -55,8 +56,8 @@ public class MultiDatastreamBuilder extends AbstractEntityBuilder();
- observations = new EntitySetImpl<>(EntityType.Observation);
- observedProperties = new EntitySetImpl<>(EntityType.ObservedProperty);
+ observations = new EntitySetImpl<>(EntityType.OBSERVATION);
+ observedProperties = new EntitySetImpl<>(EntityType.OBSERVEDPROPERTY);
unitOfMeasurements = new ArrayList<>();
multiObservationDataTypes = new ArrayList<>();
}
@@ -91,6 +92,10 @@ public MultiDatastreamBuilder setDescription(String description) {
return this;
}
+ public void setObservationType(String observationType) {
+ this.observationType = observationType;
+ }
+
public MultiDatastreamBuilder setMultiObservationDataTypes(List multiObservationDataTypes) {
this.multiObservationDataTypes = multiObservationDataTypes;
return this;
@@ -153,22 +158,24 @@ protected MultiDatastreamBuilder getThis() {
@Override
public MultiDatastream build() {
- MultiDatastream mds = new MultiDatastream(
- id,
- selfLink,
- navigationLink,
- name,
- description,
- properties,
- multiObservationDataTypes,
- unitOfMeasurements,
- observedArea,
- phenomenonTime,
- resultTime,
- sensor,
- observedProperties,
- thing,
- observations);
+ MultiDatastream mds = new MultiDatastream(id);
+ mds.setSelfLink(selfLink);
+ mds.setNavigationLink(navigationLink);
+ mds.setName(name);
+ mds.setDescription(description);
+ mds.setProperties(properties);
+ if (observationType != null) {
+ mds.setObservationType(observationType);
+ }
+ mds.setMultiObservationDataTypes(multiObservationDataTypes);
+ mds.setUnitOfMeasurements(unitOfMeasurements);
+ mds.setObservedArea(observedArea);
+ mds.setPhenomenonTime(phenomenonTime);
+ mds.setResultTime(resultTime);
+ mds.setSensor(sensor);
+ mds.setObservedProperties(observedProperties);
+ mds.setThing(thing);
+ mds.setObservations(observations);
mds.setExportObject(isExportObject());
return mds;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservationBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservationBuilder.java
index 5c9ef00f5..6030f23dd 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservationBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservationBuilder.java
@@ -105,19 +105,18 @@ protected ObservationBuilder getThis() {
@Override
public Observation build() {
- Observation o = new Observation(
- id,
- selfLink,
- navigationLink,
- phenomenonTime,
- resultTime,
- result,
- resultQuality,
- validTime,
- parameters,
- datastream,
- multiDatastream,
- featureOfInterest);
+ Observation o = new Observation(id);
+ o.setSelfLink(selfLink);
+ o.setNavigationLink(navigationLink);
+ o.setPhenomenonTime(phenomenonTime);
+ o.setResultTime(resultTime);
+ o.setResult(result);
+ o.setResultQuality(resultQuality);
+ o.setValidTime(validTime);
+ o.setParameters(parameters);
+ o.setDatastream(datastream);
+ o.setMultiDatastream(multiDatastream);
+ o.setFeatureOfInterest(featureOfInterest);
o.setExportObject(isExportObject());
return o;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservedPropertyBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservedPropertyBuilder.java
index 2a77c3195..e16261d75 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservedPropertyBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ObservedPropertyBuilder.java
@@ -42,8 +42,8 @@ public class ObservedPropertyBuilder extends AbstractEntityBuilder();
- datastreams = new EntitySetImpl<>(EntityType.Datastream);
- multiDatastreams = new EntitySetImpl<>(EntityType.MultiDatastream);
+ datastreams = new EntitySetImpl<>(EntityType.DATASTREAM);
+ multiDatastreams = new EntitySetImpl<>(EntityType.MULTIDATASTREAM);
}
public ObservedPropertyBuilder setName(String name) {
@@ -102,16 +102,15 @@ public ObservedPropertyBuilder addMultiDatastream(MultiDatastream multiDatastrea
@Override
public ObservedProperty build() {
- ObservedProperty op = new ObservedProperty(
- id,
- selfLink,
- navigationLink,
- name,
- definition,
- description,
- properties,
- datastreams,
- multiDatastreams);
+ ObservedProperty op = new ObservedProperty(id);
+ op.setSelfLink(selfLink);
+ op.setNavigationLink(navigationLink);
+ op.setName(name);
+ op.setDefinition(definition);
+ op.setDescription(description);
+ op.setProperties(properties);
+ op.setDatastreams(datastreams);
+ op.setMultiDatastreams(multiDatastreams);
op.setExportObject(isExportObject());
return op;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/SensorBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/SensorBuilder.java
index f0414cf8f..9ebb6423b 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/SensorBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/SensorBuilder.java
@@ -43,8 +43,8 @@ public class SensorBuilder extends AbstractEntityBuilder
public SensorBuilder() {
properties = new HashMap<>();
- datastreams = new EntitySetImpl<>(EntityType.Datastream);
- multiDatastreams = new EntitySetImpl<>(EntityType.MultiDatastream);
+ datastreams = new EntitySetImpl<>(EntityType.DATASTREAM);
+ multiDatastreams = new EntitySetImpl<>(EntityType.MULTIDATASTREAM);
}
public SensorBuilder setName(String name) {
@@ -104,17 +104,16 @@ protected SensorBuilder getThis() {
@Override
public Sensor build() {
- Sensor sensor = new Sensor(
- id,
- selfLink,
- navigationLink,
- name,
- description,
- encodingType,
- metadata,
- properties,
- datastreams,
- multiDatastreams);
+ Sensor sensor = new Sensor(id);
+ sensor.setSelfLink(selfLink);
+ sensor.setNavigationLink(navigationLink);
+ sensor.setName(name);
+ sensor.setDescription(description);
+ sensor.setEncodingType(encodingType);
+ sensor.setMetadata(metadata);
+ sensor.setProperties(properties);
+ sensor.setDatastreams(datastreams);
+ sensor.setMultiDatastreams(multiDatastreams);
sensor.setExportObject(isExportObject());
return sensor;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ThingBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ThingBuilder.java
index f032233e4..cd6393bdc 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ThingBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/ThingBuilder.java
@@ -45,10 +45,10 @@ public class ThingBuilder extends AbstractEntityBuilder {
public ThingBuilder() {
properties = new HashMap<>();
- locations = new EntitySetImpl<>(EntityType.Location);
- historicalLocations = new EntitySetImpl<>(EntityType.HistoricalLocation);
- datastreams = new EntitySetImpl<>(EntityType.Datastream);
- multiDatastreams = new EntitySetImpl<>(EntityType.MultiDatastream);
+ locations = new EntitySetImpl<>(EntityType.LOCATION);
+ historicalLocations = new EntitySetImpl<>(EntityType.HISTORICALLOCATION);
+ datastreams = new EntitySetImpl<>(EntityType.DATASTREAM);
+ multiDatastreams = new EntitySetImpl<>(EntityType.MULTIDATASTREAM);
}
public ThingBuilder setName(String name) {
@@ -118,17 +118,16 @@ protected ThingBuilder getThis() {
@Override
public Thing build() {
- Thing thing = new Thing(
- id,
- selfLink,
- navigationLink,
- name,
- description,
- properties,
- locations,
- historicalLocations,
- datastreams,
- multiDatastreams);
+ Thing thing = new Thing(id);
+ thing.setSelfLink(selfLink);
+ thing.setNavigationLink(navigationLink);
+ thing.setName(name);
+ thing.setDescription(description);
+ thing.setProperties(properties);
+ thing.setLocations(locations);
+ thing.setHistoricalLocations(historicalLocations);
+ thing.setDatastreams(datastreams);
+ thing.setMultiDatastreams(multiDatastreams);
thing.setExportObject(isExportObject());
return thing;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/UnitOfMeasurementBuilder.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/UnitOfMeasurementBuilder.java
index 87144a929..75dc23b06 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/UnitOfMeasurementBuilder.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/builder/UnitOfMeasurementBuilder.java
@@ -30,9 +30,6 @@ public class UnitOfMeasurementBuilder {
private String symbol;
private String definition;
- public UnitOfMeasurementBuilder() {
- }
-
public UnitOfMeasurementBuilder setName(String name) {
this.name = name;
return this;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/AbstractEntity.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/AbstractEntity.java
index 859bfceeb..a27d82585 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/AbstractEntity.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/AbstractEntity.java
@@ -19,14 +19,15 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.LoggerFactory;
/**
@@ -41,42 +42,62 @@ public abstract class AbstractEntity implements Entity {
*/
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AbstractEntity.class);
- public AbstractEntity() {
- }
-
- public AbstractEntity(Id id, String selfLink, String navigationLink) {
- this.id = id;
- this.selfLink = selfLink;
- this.navigationLink = navigationLink;
- }
@JsonProperty("@iot.id")
- protected Id id;
+ private Id id;
@JsonProperty("@iot.selfLink")
- protected String selfLink;
+ private String selfLink;
@JsonIgnore
- protected String navigationLink;
+ private String navigationLink;
@JsonIgnore
private boolean exportObject = true;
+ @JsonIgnore
+ private Set selectedProperties;
+
+ /**
+ * Flag indicating the Id was set by the user.
+ */
+ @JsonIgnore
+ private boolean setId;
+ /**
+ * Flag indicating the selfLink was set by the user.
+ */
+ @JsonIgnore
+ private boolean setSelfLink;
+
+ public AbstractEntity(Id id) {
+ setId(id);
+ }
+
@Override
public Id getId() {
return id;
}
+ /**
+ * @param id the id to set
+ */
@Override
- public String getSelfLink() {
- return selfLink;
+ public final void setId(Id id) {
+ this.id = id;
+ setId = true;
}
/**
- * @param id the id to set
+ * Flag indicating the Id was set by the user.
+ *
+ * @return Flag indicating the Id was set by the user.
*/
+ public boolean isSetId() {
+ return setId;
+ }
+
@Override
- public void setId(Id id) {
- this.id = id;
+ public String getSelfLink() {
+ return selfLink;
}
/**
@@ -85,39 +106,16 @@ public void setId(Id id) {
@Override
public void setSelfLink(String selfLink) {
this.selfLink = selfLink;
+ setSelfLink = true;
}
- @Override
- public int hashCode() {
- int hash = 5;
- hash = 89 * hash + Objects.hashCode(this.id);
- hash = 89 * hash + Objects.hashCode(this.selfLink);
- hash = 89 * hash + Objects.hashCode(this.navigationLink);
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final AbstractEntity other = (AbstractEntity) obj;
- if (!Objects.equals(this.id, other.id)) {
- return false;
- }
- if (!Objects.equals(this.selfLink, other.selfLink)) {
- return false;
- }
- if (!Objects.equals(this.navigationLink, other.navigationLink)) {
- return false;
- }
- return true;
+ /**
+ * Flag indicating the selfLink was set by the user.
+ *
+ * @return Flag indicating the selfLink was set by the user.
+ */
+ public boolean isSetSelfLink() {
+ return setSelfLink;
}
/**
@@ -136,14 +134,33 @@ public void setNavigationLink(String navigationLink) {
this.navigationLink = navigationLink;
}
+ @Override
+ public Set getSelectedPropertyNames() {
+ return selectedProperties;
+ }
+
+ @Override
+ public void setSelectedPropertyNames(Set selectedProperties) {
+ this.selectedProperties = selectedProperties;
+ }
+
+ @Override
+ public void setSelectedProperties(Set selectedProperties) {
+ setSelectedPropertyNames(
+ selectedProperties
+ .stream()
+ .map(Property::getJsonName)
+ .collect(Collectors.toSet())
+ );
+ }
+
@Override
public Object getProperty(Property property) {
String methodName = property.getGetterName();
try {
- Method getMethod = this.getClass().getMethod(methodName, null);
- return getMethod.invoke(this, null);
+ return MethodUtils.invokeExactMethod(this, methodName);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
- LOGGER.error("Failed to find or execute method " + methodName, ex);
+ LOGGER.error("Failed to find or execute getter method " + methodName, ex);
return null;
}
}
@@ -152,21 +169,33 @@ public Object getProperty(Property property) {
public void setProperty(Property property, Object value) {
String methodName = property.getSetterName();
try {
- for (Method m : this.getClass().getMethods()) {
- if (m.getParameterCount() == 1 && methodName.equals(m.getName())) {
- try {
- m.invoke(this, value);
- return;
- } catch (SecurityException | IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
- LOGGER.trace("Wrong setter method.");
- }
- }
- }
- } catch (SecurityException ex) {
+ MethodUtils.invokeMethod(this, methodName, value);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ LOGGER.error("Failed to find or execute setter method " + methodName, ex);
+ }
+ }
+
+ @Override
+ public void unsetProperty(Property property) {
+ String methodName = property.getSetterName();
+ try {
+ MethodUtils.invokeMethod(this, methodName, (Object) null);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
LOGGER.error("Failed to find or execute method " + methodName, ex);
}
}
+ @Override
+ public boolean isSetProperty(Property property) {
+ String isSetMethodName = property.getIsSetName();
+ try {
+ return (boolean) MethodUtils.invokeMethod(this, isSetMethodName);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ LOGGER.error("Failed to find or execute 'isSet' method " + isSetMethodName, ex);
+ }
+ return false;
+ }
+
@Override
public boolean isExportObject() {
return exportObject;
@@ -177,23 +206,6 @@ public void setExportObject(boolean exportObject) {
this.exportObject = exportObject;
}
- @Override
- public void unsetProperty(Property property) {
- String methodName = property.getSetterName();
- try {
- Method[] methods = this.getClass().getMethods();
- for (Method method : methods) {
- if (method.getName().equalsIgnoreCase(methodName) && method.getParameterCount() == 1) {
- method.invoke(this, new Object[]{null});
- return;
- }
- }
- LOGGER.error("Failed to find method {}.", methodName);
- } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
- LOGGER.error("Failed to find or execute method " + methodName, ex);
- }
- }
-
@Override
public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException {
EntityType type = containingSet.getEntityType();
@@ -202,4 +214,27 @@ public void complete(EntitySetPathElement containingSet) throws IncompleteEntity
}
complete();
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, selfLink, navigationLink);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final AbstractEntity other = (AbstractEntity) obj;
+ return Objects.equals(this.id, other.id)
+ && Objects.equals(this.selfLink, other.selfLink)
+ && Objects.equals(this.navigationLink, other.navigationLink);
+ }
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/Entity.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/Entity.java
index fcb376859..5e8822054 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/Entity.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/Entity.java
@@ -18,7 +18,6 @@
package de.fraunhofer.iosb.ilt.sta.model.core;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
@@ -26,6 +25,7 @@
import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
+import java.util.Set;
/**
* Interface defining basic methods of an Entity.
@@ -48,6 +48,38 @@ public interface Entity extends NavigableElement {
@JsonIgnore
public EntityType getEntityType();
+ /**
+ * Get the list of names of properties that should be serialised.
+ *
+ * @return The list of property names that should be serialised when
+ * converting this Entity to JSON.
+ */
+ public Set getSelectedPropertyNames();
+
+ /**
+ * Set the names of the properties that should be serialised.
+ *
+ * @param selectedProperties the names of the properties that should be
+ * serialised.
+ */
+ public void setSelectedPropertyNames(Set selectedProperties);
+
+ /**
+ * Set the properties that should be serialised.
+ *
+ * @param selectedProperties the properties that should be serialised.
+ */
+ public void setSelectedProperties(Set selectedProperties);
+
+ /**
+ * Returns true if the property is explicitly set to a value, even if this
+ * value is null.
+ *
+ * @param property the property to check.
+ * @return true if the property is explicitly set.
+ */
+ public boolean isSetProperty(Property property);
+
public Object getProperty(Property property);
public void setProperty(Property property, Object value);
@@ -70,7 +102,7 @@ public interface Entity extends NavigableElement {
* @throws IllegalStateException If the containing set is not of the type
* that can contain this entity.
*/
- public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException, IllegalStateException;
+ public void complete(EntitySetPathElement containingSet) throws IncompleteEntityException;
/**
* Checks if all required properties are non-null.
@@ -80,7 +112,7 @@ public interface Entity extends NavigableElement {
* @throws IllegalStateException If any of the required properties are
* incorrect (i.e. Observation with both a Datastream and a MultiDatastream.
*/
- public default void complete() throws IncompleteEntityException, IllegalStateException {
+ public default void complete() throws IncompleteEntityException {
complete(false);
}
@@ -94,17 +126,14 @@ public default void complete() throws IncompleteEntityException, IllegalStateExc
* @throws IllegalStateException If any of the required properties are
* incorrect (i.e. Observation with both a Datastream and a MultiDatastream.
*/
- public default void complete(boolean entityPropertiesOnly) throws IncompleteEntityException, IllegalStateException {
+ public default void complete(boolean entityPropertiesOnly) throws IncompleteEntityException {
EntityType type = getEntityType();
for (Property property : type.getPropertySet()) {
if (entityPropertiesOnly && !(property instanceof EntityProperty)) {
continue;
}
- if (type.isRequired(property)) {
- Object value = getProperty(property);
- if (value == null) {
- throw new IncompleteEntityException("Missing required property '" + property + "'");
- }
+ if (type.isRequired(property) && !isSetProperty(property)) {
+ throw new IncompleteEntityException("Missing required property '" + property.getJsonName() + "'");
}
}
}
@@ -120,8 +149,7 @@ public default ResourcePath getPath() {
epe.setEntityType(type);
epe.setId(getId());
ResourcePath resourcePath = new ResourcePath();
- resourcePath.getPathElements().add(epe);
- resourcePath.setMainElement(epe);
+ resourcePath.addPathElement(epe, true, false);
return resourcePath;
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/EntitySetImpl.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/EntitySetImpl.java
index ce0d7fffa..8d4dca9b7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/EntitySetImpl.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/EntitySetImpl.java
@@ -149,10 +149,7 @@ public void clear() {
@Override
public int hashCode() {
- int hash = 7;
- hash = 79 * hash + Objects.hashCode(this.data);
- hash = 79 * hash + Objects.hashCode(this.navigationLink);
- return hash;
+ return Objects.hash(data, navigationLink);
}
@Override
@@ -170,10 +167,7 @@ public boolean equals(Object obj) {
if (!Objects.equals(this.navigationLink, other.navigationLink)) {
return false;
}
- if (!Objects.equals(this.data, other.data)) {
- return false;
- }
- return true;
+ return Objects.equals(this.data, other.data);
}
@Override
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/Id.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/Id.java
similarity index 92%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/Id.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/Id.java
index b36d07b12..ca5724943 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/Id.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/Id.java
@@ -15,11 +15,10 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.model.id;
+package de.fraunhofer.iosb.ilt.sta.model.core;
import com.fasterxml.jackson.annotation.JsonValue;
import de.fraunhofer.iosb.ilt.sta.persistence.BasicPersistenceType;
-//import de.fraunhofer.iosb.ilt.sta.dao.BasicPersistenceType;
/**
*
@@ -42,4 +41,5 @@ public interface Id {
public Object asBasicPersistenceType();
public void fromBasicPersitenceType(Object data);
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/LongId.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/IdLong.java
similarity index 75%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/LongId.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/IdLong.java
index 37d1dc852..bfcccb5a7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/LongId.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/IdLong.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.model.id;
+package de.fraunhofer.iosb.ilt.sta.model.core;
import de.fraunhofer.iosb.ilt.sta.persistence.BasicPersistenceType;
import java.util.Objects;
@@ -24,21 +24,21 @@
*
* @author jab
*/
-public class LongId implements Id {
+public class IdLong implements Id {
private Long value;
- public LongId(Long value) {
+ public IdLong(Long value) {
this.value = value;
}
- public LongId(int value) {
+ public IdLong(int value) {
this.value = Long.valueOf(value);
}
@Override
public BasicPersistenceType getBasicPersistenceType() {
- return BasicPersistenceType.Integer;
+ return BasicPersistenceType.INTEGER;
}
@Override
@@ -52,10 +52,13 @@ public void fromBasicPersitenceType(Object data) {
}
@Override
- public int hashCode() {
- int hash = 3;
- hash = 53 * hash + Objects.hashCode(this.value);
- return hash;
+ public Long getValue() {
+ return value;
+ }
+
+ @Override
+ public String getUrl() {
+ return toString();
}
@Override
@@ -69,29 +72,18 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass()) {
return false;
}
- final LongId other = (LongId) obj;
- if (!Objects.equals(this.value, other.value)) {
- return false;
- }
- return true;
+ final IdLong other = (IdLong) obj;
+ return Objects.equals(this.value, other.value);
}
@Override
- public Object getValue() {
- return value;
- }
-
- @Override
- public String getUrl() {
- return toString();
+ public int hashCode() {
+ return Objects.hash(value);
}
@Override
public String toString() {
- if (value == null) {
- return "null";
- }
- return value.toString();
+ return Objects.toString(getValue());
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/StringId.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/IdString.java
similarity index 74%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/StringId.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/IdString.java
index 552dd2a31..6f2b6a006 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/id/StringId.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/IdString.java
@@ -15,26 +15,27 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.model.id;
+package de.fraunhofer.iosb.ilt.sta.model.core;
import de.fraunhofer.iosb.ilt.sta.persistence.BasicPersistenceType;
+import de.fraunhofer.iosb.ilt.sta.util.UrlHelper;
import java.util.Objects;
/**
*
* @author jab
*/
-public class StringId implements Id {
+public class IdString implements Id {
private String value;
- public StringId(String value) {
+ public IdString(String value) {
this.value = value;
}
@Override
public BasicPersistenceType getBasicPersistenceType() {
- return BasicPersistenceType.String;
+ return BasicPersistenceType.STRING;
}
@Override
@@ -48,10 +49,15 @@ public void fromBasicPersitenceType(Object data) {
}
@Override
- public int hashCode() {
- int hash = 3;
- hash = 53 * hash + Objects.hashCode(this.value);
- return hash;
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String getUrl() {
+ return "'"
+ + UrlHelper.urlEncode(UrlHelper.escapeForStringConstant(value), true)
+ + "'";
}
@Override
@@ -65,29 +71,18 @@ public boolean equals(Object obj) {
if (getClass() != obj.getClass()) {
return false;
}
- final StringId other = (StringId) obj;
- if (!Objects.equals(this.value, other.value)) {
- return false;
- }
- return true;
+ final IdString other = (IdString) obj;
+ return Objects.equals(this.value, other.value);
}
@Override
- public Object getValue() {
- return value;
- }
-
- @Override
- public String getUrl() {
- return "'" + value + "'";
+ public int hashCode() {
+ return Objects.hash(value);
}
@Override
public String toString() {
- if (value == null) {
- return "null";
- }
- return value;
+ return Objects.toString(getValue());
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/NamedDsHoldingEntity.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/NamedDsHoldingEntity.java
new file mode 100644
index 000000000..ab6f9a91c
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/NamedDsHoldingEntity.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.model.core;
+
+import de.fraunhofer.iosb.ilt.sta.model.*;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+import java.util.Objects;
+
+/**
+ * A named entity that also a list of Datastreams and a list of
+ * MultiDatastreams.
+ *
+ * @author jab, scf
+ */
+public abstract class NamedDsHoldingEntity extends NamedEntity {
+
+ private EntitySet datastreams; // 0..*
+ private EntitySet multiDatastreams; // 0..*
+
+ public NamedDsHoldingEntity() {
+ this(null);
+ }
+
+ public NamedDsHoldingEntity(Id id) {
+ super(id);
+ this.datastreams = new EntitySetImpl<>(EntityType.DATASTREAM);
+ this.multiDatastreams = new EntitySetImpl<>(EntityType.MULTIDATASTREAM);
+ }
+
+ @Override
+ public EntityType getEntityType() {
+ return EntityType.THING;
+ }
+
+ public EntitySet getDatastreams() {
+ return datastreams;
+ }
+
+ public void setDatastreams(EntitySet datastreams) {
+ this.datastreams = datastreams;
+ }
+
+ public EntitySet getMultiDatastreams() {
+ return multiDatastreams;
+ }
+
+ public void setMultiDatastreams(EntitySet multiDatastreams) {
+ this.multiDatastreams = multiDatastreams;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), datastreams, multiDatastreams);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final NamedDsHoldingEntity other = (NamedDsHoldingEntity) obj;
+ return super.equals(other)
+ && Objects.equals(datastreams, other.datastreams)
+ && Objects.equals(multiDatastreams, other.multiDatastreams);
+ }
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/NamedEntity.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/NamedEntity.java
new file mode 100644
index 000000000..2c94415fd
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/core/NamedEntity.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.model.core;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * An abstract entity with: name, description and properties.
+ *
+ * @author jab, scf
+ */
+public abstract class NamedEntity extends AbstractEntity {
+
+ private String name;
+ private String description;
+ private Map properties;
+
+ private boolean setName;
+ private boolean setDescription;
+ private boolean setProperties;
+
+ public NamedEntity(Id id) {
+ super(id);
+ }
+
+ @Override
+ public void setEntityPropertiesSet() {
+ setName = true;
+ setDescription = true;
+ setProperties = true;
+ }
+
+ /**
+ * @return the Name of the entity.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the Name of the entity.
+ *
+ * @param name The Name to set.
+ */
+ public void setName(String name) {
+ this.name = name;
+ setName = name != null;
+ }
+
+ /**
+ * @return Flag indicating the Name was set by the user.
+ */
+ public boolean isSetName() {
+ return setName;
+ }
+
+ /**
+ * @return the Description of the entity.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Set the Description of the entity.
+ *
+ * @param description The Description to set.
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ setDescription = description != null;
+ }
+
+ /**
+ * @return Flag indicating the Description was set by the user.
+ */
+ public boolean isSetDescription() {
+ return setDescription;
+ }
+
+ /**
+ * @return the Properties map of the entity.
+ */
+ public Map getProperties() {
+ return properties;
+ }
+
+ /**
+ * Set the Properties map of the entity.
+ *
+ * @param properties The Properties to set. Setting this to an empty map
+ * will set the properties to null.
+ */
+ public void setProperties(Map properties) {
+ if (properties != null && properties.isEmpty()) {
+ properties = null;
+ }
+ this.properties = properties;
+ setProperties = true;
+ }
+
+ /**
+ * @return Flag indicating Properties was set by the user.
+ */
+ public boolean isSetProperties() {
+ return setProperties;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, description, properties);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final NamedEntity other = (NamedEntity) obj;
+ return super.equals(other)
+ && Objects.equals(this.name, other.name)
+ && Objects.equals(this.description, other.description)
+ && Objects.equals(this.properties, other.properties);
+ }
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/ObservationType.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/ObservationType.java
new file mode 100644
index 000000000..df278a7aa
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/ObservationType.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.model.ext;
+
+/**
+ *
+ * @author scf
+ */
+public enum ObservationType {
+ COMPLEX_OBSERVATION("http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_ComplexObservation");
+
+ public final String code;
+
+ private ObservationType(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInstant.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInstant.java
index c6b88594c..bcd2013f8 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInstant.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInstant.java
@@ -18,7 +18,7 @@
package de.fraunhofer.iosb.ilt.sta.model.ext;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import de.fraunhofer.iosb.ilt.sta.deserialize.TimeInstantDeserializer;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.TimeInstantDeserializer;
import java.util.Objects;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
@@ -52,9 +52,7 @@ public static TimeInstant now(DateTimeZone timeZone) {
@Override
public int hashCode() {
- int hash = 7;
- hash = 37 * hash + Objects.hashCode(this.dateTime);
- return hash;
+ return Objects.hash(dateTime);
}
@Override
@@ -72,13 +70,10 @@ public boolean equals(Object obj) {
if (this.dateTime == null && other.dateTime == null) {
return true;
}
- if (this.dateTime == null | other.dateTime == null) {
+ if (this.dateTime == null || other.dateTime == null) {
return false;
}
- if (!this.dateTime.isEqual(other.dateTime)) {
- return false;
- }
- return true;
+ return this.dateTime.isEqual(other.dateTime);
}
public static TimeInstant parse(String value) {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInterval.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInterval.java
index 38d35c482..e8363f492 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInterval.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeInterval.java
@@ -18,7 +18,7 @@
package de.fraunhofer.iosb.ilt.sta.model.ext;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import de.fraunhofer.iosb.ilt.sta.deserialize.TimeIntervalDeserializer;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.TimeIntervalDeserializer;
import java.util.Objects;
import org.joda.time.DateTimeZone;
import org.joda.time.Interval;
@@ -45,9 +45,7 @@ private TimeInterval(Interval interval) {
@Override
public int hashCode() {
- int hash = 5;
- hash = 67 * hash + Objects.hashCode(this.interval);
- return hash;
+ return Objects.hash(interval);
}
@Override
@@ -62,10 +60,7 @@ public boolean equals(Object obj) {
return false;
}
final TimeInterval other = (TimeInterval) obj;
- if (!Objects.equals(this.interval, other.interval)) {
- return false;
- }
- return true;
+ return Objects.equals(this.interval, other.interval);
}
public static TimeInterval create(long start, long end) {
@@ -88,11 +83,11 @@ public Interval getInterval() {
public String asISO8601() {
DateTimeFormatter printer = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);
printer = printer.withChronology(interval.getChronology());
- StringBuffer buf = new StringBuffer(48);
- printer.printTo(buf, interval.getStartMillis());
- buf.append('/');
- printer.printTo(buf, interval.getEndMillis());
- return buf.toString();
+ StringBuilder timeString = new StringBuilder(48);
+ printer.printTo(timeString, interval.getStartMillis());
+ timeString.append('/');
+ printer.printTo(timeString, interval.getEndMillis());
+ return timeString.toString();
}
@Override
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeValue.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeValue.java
index 872b0ac07..ace0e16b7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeValue.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/TimeValue.java
@@ -19,8 +19,8 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import de.fraunhofer.iosb.ilt.sta.deserialize.TimeValueDeserializer;
-import de.fraunhofer.iosb.ilt.sta.serialize.TimeValueSerializer;
+import de.fraunhofer.iosb.ilt.sta.json.deserialize.TimeValueDeserializer;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.TimeValueSerializer;
/**
* Common interface for time values. Needed as STA sometimes does not scpecify wether an instant or an interval will be
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/UnitOfMeasurement.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/UnitOfMeasurement.java
index ced8ea377..a4b143008 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/UnitOfMeasurement.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/ext/UnitOfMeasurement.java
@@ -17,11 +17,9 @@
*/
package de.fraunhofer.iosb.ilt.sta.model.ext;
-import de.fraunhofer.iosb.ilt.sta.serialize.EntityFormatter;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntityFormatter;
import java.io.IOException;
import java.util.Objects;
-import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* Model class for UnitOfMeasurement. This is not a first class entity in STA.
@@ -92,7 +90,7 @@ public void setDefinition(String definition) {
@Override
public String toString() {
try {
- return new EntityFormatter().writeObject(this);
+ return EntityFormatter.writeObject(this);
} catch (IOException ex) {
return this.toString();
}
@@ -100,11 +98,7 @@ public String toString() {
@Override
public int hashCode() {
- int hash = 5;
- hash = 83 * hash + Objects.hashCode(this.name);
- hash = 83 * hash + Objects.hashCode(this.symbol);
- hash = 83 * hash + Objects.hashCode(this.definition);
- return hash;
+ return Objects.hash(name,symbol,definition);
}
@Override
@@ -125,9 +119,6 @@ public boolean equals(Object obj) {
if (!Objects.equals(this.symbol, other.symbol)) {
return false;
}
- if (!Objects.equals(this.definition, other.definition)) {
- return false;
- }
- return true;
+ return Objects.equals(this.definition, other.definition);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/AbstractDatastreamMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/AbstractDatastreamMixIn.java
new file mode 100644
index 000000000..8fef1424c
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/AbstractDatastreamMixIn.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.model.mixin;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+
+/**
+ * MixIn to ensure that unitOfMeasurement is always included like stated in the
+ * standard (p28, Table 8-9)
+ *
+ * @author jab
+ */
+public interface AbstractDatastreamMixIn {
+
+ @JsonIgnore
+ public abstract EntityType getEntityType();
+
+ @JsonIgnore
+ public abstract boolean isSetName();
+
+ @JsonIgnore
+ public abstract boolean isSetDescription();
+
+ @JsonIgnore
+ public void setObservationTypeIntern(String observationType);
+
+ @JsonIgnore
+ public abstract boolean isSetObservationType();
+
+ @JsonIgnore
+ public abstract boolean isSetObservedArea();
+
+ @JsonIgnore
+ public abstract boolean isSetPhenomenonTime();
+
+ @JsonIgnore
+ public abstract boolean isSetProperties();
+
+ @JsonIgnore
+ public abstract boolean isSetResultTime();
+
+ @JsonIgnore
+ public abstract boolean isSetSensor();
+
+ @JsonIgnore
+ public abstract boolean isSetThing();
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/DatastreamMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/DatastreamMixIn.java
index 5ff324780..181016c9b 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/DatastreamMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/DatastreamMixIn.java
@@ -18,9 +18,6 @@
package de.fraunhofer.iosb.ilt.sta.model.mixin;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import de.fraunhofer.iosb.ilt.sta.model.ext.UnitOfMeasurement;
-import de.fraunhofer.iosb.ilt.sta.path.EntityType;
/**
* MixIn to ensure that unitOfMeasurement is always included like stated in the
@@ -28,44 +25,11 @@
*
* @author jab
*/
-public abstract class DatastreamMixIn {
-
- @JsonSerialize(include = JsonSerialize.Inclusion.ALWAYS)
- public abstract UnitOfMeasurement getUnitOfMeasurement();
-
- @JsonIgnore
- public abstract EntityType getEntityType();
-
- @JsonIgnore
- public abstract boolean isSetName();
-
- @JsonIgnore
- public abstract boolean isSetDescription();
-
- @JsonIgnore
- public abstract boolean isSetObservationType();
-
- @JsonIgnore
- public abstract boolean isSetObservedArea();
-
- @JsonIgnore
- public abstract boolean isSetPhenomenonTime();
-
- @JsonIgnore
- public abstract boolean isSetProperties();
-
- @JsonIgnore
- public abstract boolean isSetResultTime();
-
- @JsonIgnore
- public abstract boolean isSetSensor();
+public interface DatastreamMixIn extends AbstractDatastreamMixIn {
@JsonIgnore
public abstract boolean isSetObservedProperty();
- @JsonIgnore
- public abstract boolean isSetThing();
-
@JsonIgnore
public abstract boolean isSetUnitOfMeasurement();
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/EntitySetResultMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/EntitySetResultMixIn.java
index c8f133db9..6fbb3c53b 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/EntitySetResultMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/EntitySetResultMixIn.java
@@ -24,7 +24,7 @@
*
* @author jab
*/
-public abstract class EntitySetResultMixIn {
+public interface EntitySetResultMixIn {
@JsonProperty("value")
public abstract EntitySet getValues();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/custom/geojson/FeatureMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/FeatureMixIn.java
similarity index 92%
rename from FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/custom/geojson/FeatureMixIn.java
rename to FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/FeatureMixIn.java
index d1a627b14..2760d5d07 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/custom/geojson/FeatureMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/FeatureMixIn.java
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
-package de.fraunhofer.iosb.ilt.sta.model.custom.geojson;
+package de.fraunhofer.iosb.ilt.sta.model.mixin;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
@@ -27,7 +27,7 @@
*
* @author jab
*/
-public abstract class FeatureMixIn {
+public interface FeatureMixIn {
@JsonInclude(Include.NON_EMPTY)
public abstract Map getProperties();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/FeatureOfInterestMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/FeatureOfInterestMixIn.java
index fcd4cbbbc..69a1a4c60 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/FeatureOfInterestMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/FeatureOfInterestMixIn.java
@@ -18,14 +18,14 @@
package de.fraunhofer.iosb.ilt.sta.model.mixin;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.custom.CustomSerialization;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import de.fraunhofer.iosb.ilt.sta.serialize.custom.CustomSerialization;
/**
*
* @author jab
*/
-public abstract class FeatureOfInterestMixIn {
+public interface FeatureOfInterestMixIn {
@CustomSerialization
public abstract Object getFeature();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/HistoricalLocationMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/HistoricalLocationMixIn.java
index 2dcd27403..e44bb10a0 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/HistoricalLocationMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/HistoricalLocationMixIn.java
@@ -18,14 +18,13 @@
package de.fraunhofer.iosb.ilt.sta.model.mixin;
import com.fasterxml.jackson.annotation.JsonIgnore;
-
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
/**
*
* @author jab
*/
-public abstract class HistoricalLocationMixIn {
+public interface HistoricalLocationMixIn {
@JsonIgnore
public abstract EntityType getEntityType();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/LocationMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/LocationMixIn.java
index 499894e05..c00ca99bd 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/LocationMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/LocationMixIn.java
@@ -18,14 +18,14 @@
package de.fraunhofer.iosb.ilt.sta.model.mixin;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.custom.CustomSerialization;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import de.fraunhofer.iosb.ilt.sta.serialize.custom.CustomSerialization;
/**
*
* @author jab
*/
-public abstract class LocationMixIn {
+public interface LocationMixIn {
@JsonIgnore
public abstract EntityType getEntityType();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/MixinUtils.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/MixinUtils.java
new file mode 100644
index 000000000..6c57b18d7
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/MixinUtils.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.model.mixin;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import de.fraunhofer.iosb.ilt.sta.model.Datastream;
+import de.fraunhofer.iosb.ilt.sta.model.FeatureOfInterest;
+import de.fraunhofer.iosb.ilt.sta.model.HistoricalLocation;
+import de.fraunhofer.iosb.ilt.sta.model.Location;
+import de.fraunhofer.iosb.ilt.sta.model.MultiDatastream;
+import de.fraunhofer.iosb.ilt.sta.model.Observation;
+import de.fraunhofer.iosb.ilt.sta.model.ObservedProperty;
+import de.fraunhofer.iosb.ilt.sta.model.Sensor;
+import de.fraunhofer.iosb.ilt.sta.model.Thing;
+import de.fraunhofer.iosb.ilt.sta.model.ext.EntitySetResult;
+import de.fraunhofer.iosb.ilt.sta.model.ext.UnitOfMeasurement;
+
+/**
+ *
+ * @author scf
+ */
+public class MixinUtils {
+
+ private MixinUtils() {
+ // Utility class, not to be instantiated.
+ }
+
+ public static void addMixins(ObjectMapper mapper) {
+ mapper.addMixIn(Datastream.class, DatastreamMixIn.class);
+ mapper.addMixIn(MultiDatastream.class, MultiDatastreamMixIn.class);
+ mapper.addMixIn(FeatureOfInterest.class, FeatureOfInterestMixIn.class);
+ mapper.addMixIn(HistoricalLocation.class, HistoricalLocationMixIn.class);
+ mapper.addMixIn(Location.class, LocationMixIn.class);
+ mapper.addMixIn(Observation.class, ObservationMixIn.class);
+ mapper.addMixIn(ObservedProperty.class, ObservedPropertyMixIn.class);
+ mapper.addMixIn(Sensor.class, SensorMixIn.class);
+ mapper.addMixIn(Thing.class, ThingMixIn.class);
+ mapper.addMixIn(UnitOfMeasurement.class, UnitOfMeasurementMixIn.class);
+ mapper.addMixIn(EntitySetResult.class, EntitySetResultMixIn.class);
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/MultiDatastreamMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/MultiDatastreamMixIn.java
index 1d523d7bb..82e6b6f14 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/MultiDatastreamMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/MultiDatastreamMixIn.java
@@ -18,7 +18,6 @@
package de.fraunhofer.iosb.ilt.sta.model.mixin;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import de.fraunhofer.iosb.ilt.sta.path.EntityType;
/**
* MixIn to ensure that unitOfMeasurement is always included like stated in the
@@ -26,44 +25,14 @@
*
* @author jab
*/
-public abstract class MultiDatastreamMixIn {
-
- @JsonIgnore
- public abstract EntityType getEntityType();
-
- @JsonIgnore
- public abstract boolean isSetName();
-
- @JsonIgnore
- public abstract boolean isSetDescription();
-
- @JsonIgnore
- public abstract boolean isSetObservationType();
+public interface MultiDatastreamMixIn extends AbstractDatastreamMixIn {
@JsonIgnore
public abstract boolean isSetMultiObservationDataTypes();
- @JsonIgnore
- public abstract boolean isSetObservedArea();
-
- @JsonIgnore
- public abstract boolean isSetPhenomenonTime();
-
- @JsonIgnore
- public abstract boolean isSetProperties();
-
- @JsonIgnore
- public abstract boolean isSetResultTime();
-
- @JsonIgnore
- public abstract boolean isSetSensor();
-
@JsonIgnore
public abstract boolean isSetObservedProperties();
- @JsonIgnore
- public abstract boolean isSetThing();
-
@JsonIgnore
public abstract boolean isSetUnitOfMeasurements();
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservationMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservationMixIn.java
index d91b3059b..e4b30ea06 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservationMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservationMixIn.java
@@ -18,13 +18,17 @@
package de.fraunhofer.iosb.ilt.sta.model.mixin;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
/**
*
* @author jab
*/
-public abstract class ObservationMixIn {
+public interface ObservationMixIn {
+
+ @JsonInclude(value = JsonInclude.Include.ALWAYS)
+ public abstract Object getResult();
@JsonIgnore
public abstract EntityType getEntityType();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservedPropertyMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservedPropertyMixIn.java
index 2fbe78aff..249acedc4 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservedPropertyMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ObservedPropertyMixIn.java
@@ -24,7 +24,7 @@
*
* @author jab
*/
-public abstract class ObservedPropertyMixIn {
+public interface ObservedPropertyMixIn {
@JsonIgnore
public abstract EntityType getEntityType();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/SensorMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/SensorMixIn.java
index f87e0e871..49a3ad9e5 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/SensorMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/SensorMixIn.java
@@ -24,7 +24,7 @@
*
* @author jab
*/
-public abstract class SensorMixIn {
+public interface SensorMixIn {
@JsonIgnore
public abstract EntityType getEntityType();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ThingMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ThingMixIn.java
index b1978f243..9c71094be 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ThingMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/ThingMixIn.java
@@ -24,7 +24,7 @@
*
* @author jab
*/
-public abstract class ThingMixIn {
+public interface ThingMixIn {
@JsonIgnore
public abstract EntityType getEntityType();
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/UnitOfMeasurementMixIn.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/UnitOfMeasurementMixIn.java
index 48644055e..eb8dbf4e2 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/UnitOfMeasurementMixIn.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/model/mixin/UnitOfMeasurementMixIn.java
@@ -17,14 +17,15 @@
*/
package de.fraunhofer.iosb.ilt.sta.model.mixin;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.annotation.JsonInclude;
/**
- * MixIn to ensure that unitOfMeasurement is always included like stated in the standard (p28, Table 8-9)
+ * MixIn to ensure that fields of the unitOfMeasurement is always included, even
+ * if null, as stated in the standard. (p28, Table 8-9)
*
* @author jab
*/
-@JsonSerialize(include = JsonSerialize.Inclusion.ALWAYS)
-public abstract class UnitOfMeasurementMixIn {
+@JsonInclude(JsonInclude.Include.ALWAYS)
+public interface UnitOfMeasurementMixIn {
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttManager.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttManager.java
index a44d189db..177c87069 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttManager.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttManager.java
@@ -1,21 +1,24 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt;
+import de.fraunhofer.iosb.ilt.sta.messagebus.EntityChangedMessage;
+import de.fraunhofer.iosb.ilt.sta.messagebus.MessageListener;
import de.fraunhofer.iosb.ilt.sta.model.Observation;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
import de.fraunhofer.iosb.ilt.sta.mqtt.create.EntityCreateListener;
@@ -25,8 +28,7 @@
import de.fraunhofer.iosb.ilt.sta.mqtt.subscription.SubscriptionFactory;
import de.fraunhofer.iosb.ilt.sta.mqtt.subscription.SubscriptionListener;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import de.fraunhofer.iosb.ilt.sta.persistence.EntityChangeListener;
-import de.fraunhofer.iosb.ilt.sta.persistence.EntityChangedEvent;
+import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManager;
import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManagerFactory;
import de.fraunhofer.iosb.ilt.sta.service.RequestType;
@@ -36,10 +38,11 @@
import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
import de.fraunhofer.iosb.ilt.sta.settings.MqttSettings;
import de.fraunhofer.iosb.ilt.sta.util.ProcessorHelper;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
import java.io.IOException;
-import java.nio.charset.Charset;
import java.util.EnumMap;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
@@ -53,10 +56,9 @@
*
* @author jab
*/
-public class MqttManager implements SubscriptionListener, EntityChangeListener, EntityCreateListener {
+public class MqttManager implements SubscriptionListener, MessageListener, EntityCreateListener {
private static MqttManager instance;
- private static final Charset ENCODING = Charset.forName("UTF-8");
private static final Logger LOGGER = LoggerFactory.getLogger(MqttManager.class);
public static synchronized void init(CoreSettings settings) {
@@ -81,7 +83,7 @@ public static MqttManager getInstance() {
private final Map> subscriptions = new EnumMap<>(EntityType.class);
private final CoreSettings settings;
private MqttServer server;
- private BlockingQueue entityChangedEventQueue;
+ private BlockingQueue entityChangedEventQueue;
private ExecutorService entityChangedExecutorService;
private BlockingQueue observationCreateEventQueue;
private ExecutorService observationCreateExecutorService;
@@ -101,6 +103,7 @@ private MqttManager(CoreSettings settings) {
private void init() {
MqttSettings mqttSettings = settings.getMqttSettings();
+ SubscriptionFactory.init(settings);
if (mqttSettings.isEnableMqtt()) {
enabledMqtt = true;
shutdown = false;
@@ -109,14 +112,14 @@ private void init() {
entityChangedExecutorService = ProcessorHelper.createProcessors(
mqttSettings.getSubscribeThreadPoolSize(),
entityChangedEventQueue,
- x -> handleEntityChangedEvent(x),
+ this::handleEntityChangedEvent,
"MqttManager EntityChangedEventProcessor");
// start watching for ObservationCreateEvents
observationCreateEventQueue = new ArrayBlockingQueue<>(mqttSettings.getCreateMessageQueueSize());
observationCreateExecutorService = ProcessorHelper.createProcessors(
mqttSettings.getCreateThreadPoolSize(),
observationCreateEventQueue,
- x -> handleObservationCreateEvent(x),
+ this::handleObservationCreateEvent,
"MqttManager ObservationCreateEventProcessor");
// start MQTT server
server = MqttServerFactory.getInstance().get(settings);
@@ -132,8 +135,6 @@ private void init() {
observationCreateEventQueue = new ArrayBlockingQueue<>(1);
server = null;
}
-
- SubscriptionFactory.init(settings);
}
private void doShutdown() {
@@ -145,23 +146,25 @@ private void doShutdown() {
}
}
- private void handleEntityChangedEvent(EntityChangedEvent e) {
+ private void handleEntityChangedEvent(EntityChangedMessage message) {
+ if (message.getEventType() == EntityChangedMessage.Type.DELETE) {
+ // v1.0 does not do delete notification.
+ return;
+ }
// check if there is any subscription, if not do not publish at all
- if (!subscriptions.containsKey(e.getNewEntity().getEntityType())) {
+ EntityType entityType = message.getEntityType();
+ if (!subscriptions.containsKey(entityType)) {
return;
}
PersistenceManager persistenceManager = PersistenceManagerFactory.getInstance().create();
+ // Send a complete entity through the bus, or just an entity-id?
+ Entity entity = message.getEntity();
+ Set fields = message.getFields();
try {
// for each subscription on EntityType check match
- for (Subscription subscription : subscriptions.get(e.getNewEntity().getEntityType()).keySet()) {
- if (subscription.matches(persistenceManager, e.getOldEntity(), e.getNewEntity())) {
- Entity realEntity = persistenceManager.getEntityById(settings.getServiceRootUrl(), e.getNewEntity().getEntityType(), e.getNewEntity().getId());
- try {
- String payload = subscription.formatMessage(realEntity);
- server.publish(subscription.getTopic(), payload.getBytes(ENCODING), settings.getMqttSettings().getQosLevel());
- } catch (IOException ex) {
- LOGGER.error("publishing to MQTT on topic '" + subscription.getTopic() + "' failed", ex);
- }
+ for (Subscription subscription : subscriptions.get(entityType).keySet()) {
+ if (subscription.matches(persistenceManager, entity, fields)) {
+ notifySubscription(subscription, entity);
}
}
} catch (Exception ex) {
@@ -169,41 +172,54 @@ private void handleEntityChangedEvent(EntityChangedEvent e) {
} finally {
persistenceManager.close();
}
- return;
+ }
+
+ private void notifySubscription(Subscription subscription, Entity entity) {
+ try {
+ String payload = subscription.formatMessage(entity);
+ server.publish(subscription.getTopic(), payload.getBytes(StringHelper.ENCODING), settings.getMqttSettings().getQosLevel());
+ } catch (IOException ex) {
+ LOGGER.error("publishing to MQTT on topic '" + subscription.getTopic() + "' failed", ex);
+ }
}
private void handleObservationCreateEvent(ObservationCreateEvent e) {
// check path?
- if (!e.getTopic().endsWith("Observations")) {
- LOGGER.info("received message on topic '{}' which is no valid topic to create an observation.");
+ String topic = e.getTopic();
+ if (!topic.endsWith("Observations")) {
+ LOGGER.info("received message on topic '{}' which is no valid topic to create an observation.", topic);
return;
}
- String url = e.getTopic().replaceFirst(settings.getApiVersion(), "");
+ String url = topic.replaceFirst(settings.getApiVersion(), "");
ServiceResponse response = new Service(settings).execute(new ServiceRequestBuilder()
- .withRequestType(RequestType.Create)
+ .withRequestType(RequestType.CREATE)
.withContent(e.getPayload())
.withUrlPath(url)
.build());
if (response.isSuccessful()) {
- LOGGER.info("Observation (ID {}) created via MQTT", response.getResult().getId().getValue());
+ LOGGER.debug("Observation (ID {}) created via MQTT", response.getResult().getId().getValue());
} else {
LOGGER.error("Creating observation via MQTT failed (topic: {}, payload: {}, code: {}, message: {})",
- e.getTopic(), e.getPayload(), response.getCode(), response.getMessage());
+ topic, e.getPayload(), response.getCode(), response.getMessage());
}
}
- private void entityChanged(EntityChangedEvent e) {
+ private void entityChanged(EntityChangedMessage e) {
if (shutdown || !enabledMqtt) {
return;
}
if (!entityChangedEventQueue.offer(e)) {
- LOGGER.warn("EntityChangedevent discarded because message queue is full {}! Increase mqtt.CreateMessageQueueSize and/or mqtt.CreateThreadPoolSize.", entityChangedEventQueue.size());
+ LOGGER.warn("EntityChangedevent discarded because message queue is full {}! Increase mqtt.SubscribeMessageQueueSize and/or mqtt.SubscribeThreadPoolSize.", entityChangedEventQueue.size());
}
}
@Override
public void onSubscribe(SubscriptionEvent e) {
Subscription subscription = SubscriptionFactory.getInstance().get(e.getTopic());
+ if (subscription == null) {
+ // Not a valid topic.
+ return;
+ }
Map subscriptionsMap = subscriptions.get(subscription.getEntityType());
synchronized (subscriptionsMap) {
@@ -222,6 +238,10 @@ public void onSubscribe(SubscriptionEvent e) {
@Override
public void onUnsubscribe(SubscriptionEvent e) {
Subscription subscription = SubscriptionFactory.getInstance().get(e.getTopic());
+ if (subscription == null) {
+ // Not a valid topic.
+ return;
+ }
final Map subscriptionsMap = subscriptions.get(subscription.getEntityType());
synchronized (subscriptionsMap) {
AtomicInteger clientCount = subscriptionsMap.get(subscription);
@@ -230,25 +250,15 @@ public void onUnsubscribe(SubscriptionEvent e) {
LOGGER.debug("Now {} subscriptions for topic {}.", newCount, subscription.getTopic());
if (newCount <= 0) {
subscriptionsMap.remove(subscription);
- LOGGER.debug("Removed subscription for topic {}.", newCount, subscription.getTopic());
+ LOGGER.debug("Removed last subscription for topic {}.", subscription.getTopic());
}
}
}
}
@Override
- public void entityInserted(EntityChangedEvent e) {
- entityChanged(e);
- }
-
- @Override
- public void entityDeleted(EntityChangedEvent e) {
-
- }
-
- @Override
- public void entityUpdated(EntityChangedEvent e) {
- entityChanged(e);
+ public void messageReceived(EntityChangedMessage message) {
+ entityChanged(message);
}
@Override
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServer.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServer.java
index 693f29892..21e4a60a2 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServer.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServer.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServerFactory.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServerFactory.java
index 8898f9c59..a7c113233 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServerFactory.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/MqttServerFactory.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/EntityCreateListener.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/EntityCreateListener.java
index 6e6b96c37..b498a325c 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/EntityCreateListener.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/EntityCreateListener.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.create;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/ObservationCreateEvent.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/ObservationCreateEvent.java
index 43c200bc7..0226854b7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/ObservationCreateEvent.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/create/ObservationCreateEvent.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.create;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/AbstractSubscription.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/AbstractSubscription.java
new file mode 100644
index 000000000..83dc7c39b
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/AbstractSubscription.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
+
+import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
+import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty;
+import de.fraunhofer.iosb.ilt.sta.path.Property;
+import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
+import de.fraunhofer.iosb.ilt.sta.path.ResourcePathElement;
+import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManager;
+import de.fraunhofer.iosb.ilt.sta.query.Query;
+import de.fraunhofer.iosb.ilt.sta.query.expression.Expression;
+import de.fraunhofer.iosb.ilt.sta.query.expression.Path;
+import de.fraunhofer.iosb.ilt.sta.query.expression.constant.IntegerConstant;
+import de.fraunhofer.iosb.ilt.sta.query.expression.constant.StringConstant;
+import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.Equal;
+import de.fraunhofer.iosb.ilt.sta.util.PathHelper;
+import de.fraunhofer.iosb.ilt.sta.util.UrlHelper;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author jab
+ */
+public abstract class AbstractSubscription implements Subscription {
+
+ private static Map> navigationProperties = null;
+
+ protected final String topic;
+ protected EntityType entityType;
+ protected Expression matchExpression = null;
+ private Predicate super Entity> matcher;
+ protected ResourcePath path;
+ protected String serviceRootUrl;
+
+ public AbstractSubscription(String topic, ResourcePath path, String serviceRootUrl) {
+ initNavigationProperties();
+ this.topic = topic;
+ this.path = path;
+ this.serviceRootUrl = serviceRootUrl;
+ }
+
+ private static void initNavigationProperties() {
+ if (navigationProperties == null) {
+ navigationProperties = new EnumMap<>(EntityType.class);
+ for (EntityType type : EntityType.values()) {
+ navigationProperties.put(type,
+ type.getPropertySet().stream()
+ .filter(x -> x instanceof NavigationProperty)
+ .map(x -> (NavigationProperty) x)
+ .collect(Collectors.toList()));
+ }
+ }
+ }
+
+ @Override
+ public boolean matches(PersistenceManager persistenceManager, Entity newEntity, Set fields) {
+ if (!newEntity.getEntityType().equals(entityType)) {
+ return false;
+ }
+ if (matcher != null && !matcher.test(newEntity)) {
+ return false;
+ }
+ if (matchExpression != null) {
+ Query query = new Query();
+ query.setFilter(matchExpression);
+ Object result = persistenceManager.get(newEntity.getPath(), query);
+ return result != null;
+ }
+ return true;
+ }
+
+ protected void generateFilter(int pathElementOffset) {
+ EntityType lastType = getEntityType();
+ List properties = new ArrayList<>();
+ for (int i = path.size() - 1 - pathElementOffset; i >= 0; i--) {
+ ResourcePathElement element = path.get(i);
+ if (!(element instanceof EntityPathElement)) {
+ continue;
+ }
+ final EntityPathElement epe = (EntityPathElement) element;
+ final NavigationProperty navProp = PathHelper.getNavigationProperty(lastType, epe.getEntityType());
+
+ Id id = epe.getId();
+ if (!navProp.isSet && id != null) {
+ createMatcher(navProp, id);
+ assert (i <= 1);
+ return;
+ }
+
+ properties.add(navProp);
+ lastType = epe.getEntityType();
+
+ if (id != null) {
+ createMatchExpression(properties, epe);
+ // there should be at most two PathElements left, the EntitySetPath and the EntityPath now visiting
+ assert (i <= 1);
+ return;
+ }
+ }
+ }
+
+ private void createMatcher(final NavigationProperty navProp, Id id) {
+ // We have a collectionSubscription of type one-to-many.
+ // Create a (cheap) matcher instead of an (expensive) Expression
+ matcher = (Entity t) -> {
+ Entity parent = (Entity) t.getProperty(navProp);
+ if (parent == null) {
+ // can be for Observation->Datastream when Observation is MultiDatastream.
+ return false;
+ }
+ return id.equals(parent.getId());
+ };
+ }
+
+ private void createMatchExpression(List properties, final EntityPathElement epe) {
+ properties.add(EntityProperty.ID);
+ String epeId = epe.getId().getUrl();
+ if (epeId.startsWith("'")) {
+ matchExpression = new Equal(new Path(properties), new StringConstant(epeId.substring(1, epeId.length() - 1)));
+ } else {
+ matchExpression = new Equal(new Path(properties), new IntegerConstant(epeId));
+ }
+ }
+
+ @Override
+ public EntityType getEntityType() {
+ return entityType;
+ }
+
+ @Override
+ public String getTopic() {
+ return topic;
+ }
+
+ @Override
+ public String formatMessage(Entity entity) throws IOException {
+ entity.setSelfLink(UrlHelper.generateSelfLink(path, entity));
+ for (NavigationProperty navigationProperty : navigationProperties.get(entity.getEntityType())) {
+ if (navigationProperty.isSet) {
+ EntitySet property = (EntitySet) entity.getProperty(navigationProperty);
+ property.setNavigationLink(UrlHelper.generateNavLink(path, entity, property, true));
+ } else {
+ Entity property = (Entity) entity.getProperty(navigationProperty);
+ if (property != null) {
+ property.setNavigationLink(UrlHelper.generateNavLink(path, entity, property, true));
+ }
+ }
+ }
+ return doFormatMessage(entity);
+ }
+
+ public abstract String doFormatMessage(Entity entity) throws IOException;
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(topic, entityType);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final AbstractSubscription other = (AbstractSubscription) obj;
+ if (!Objects.equals(this.topic, other.topic)) {
+ return false;
+ }
+ return this.entityType == other.entityType;
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySetSubscription.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySetSubscription.java
index 7d751b017..fc0788a10 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySetSubscription.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySetSubscription.java
@@ -1,35 +1,37 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntityFormatter;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
-import static de.fraunhofer.iosb.ilt.sta.mqtt.subscription.Subscription.ENCODING;
import de.fraunhofer.iosb.ilt.sta.parser.query.QueryParser;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.query.Query;
-import de.fraunhofer.iosb.ilt.sta.serialize.EntityFormatter;
import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,10 +39,10 @@
*
* @author jab
*/
-public class EntitySetSubscription extends Subscription {
+public class EntitySetSubscription extends AbstractSubscription {
private static final Logger LOGGER = LoggerFactory.getLogger(EntitySetSubscription.class);
- private final List selectedProperties = new ArrayList<>();
+ private final Set selectedProperties = new HashSet<>();
public EntitySetSubscription(String topic, ResourcePath path, String serviceRootUrl) {
super(topic, path, serviceRootUrl);
@@ -70,14 +72,14 @@ private void init() {
private Query parseQuery(String topic) {
String queryString = null;
try {
- queryString = URLDecoder.decode(topic, ENCODING.name());
+ queryString = URLDecoder.decode(topic, StringHelper.ENCODING.name());
} catch (UnsupportedEncodingException ex) {
LOGGER.error("Unsupported encoding.", ex);
}
try {
return QueryParser.parseQuery(queryString, new CoreSettings());
} catch (IllegalArgumentException e) {
- LOGGER.error("Invalid query: " + e.getMessage());
+ LOGGER.error("Invalid query: {} ERROR: {}", queryString, e.getMessage());
return null;
}
}
@@ -85,8 +87,23 @@ private Query parseQuery(String topic) {
@Override
public String doFormatMessage(Entity entity) throws IOException {
if (!selectedProperties.isEmpty()) {
- return new EntityFormatter(selectedProperties).writeEntity(entity);
+ entity.setSelectedProperties(selectedProperties);
}
- return new EntityFormatter().writeEntity(entity);
+ return EntityFormatter.writeEntity(entity);
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), selectedProperties);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!super.equals(obj)) {
+ return false;
+ }
+ final EntitySetSubscription other = (EntitySetSubscription) obj;
+ return Objects.equals(this.selectedProperties, other.selectedProperties);
+ }
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySubscription.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySubscription.java
index e3ca89d65..08c3930af 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySubscription.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/EntitySubscription.java
@@ -1,39 +1,41 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntityFormatter;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
+import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManager;
-import de.fraunhofer.iosb.ilt.sta.serialize.EntityFormatter;
import java.io.IOException;
+import java.util.Set;
import java.util.function.Predicate;
-import org.slf4j.LoggerFactory;
/**
*
* @author jab
*/
-public class EntitySubscription extends Subscription {
+public class EntitySubscription extends AbstractSubscription {
- private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(EntitySubscription.class);
private Predicate super Entity> matcher;
public EntitySubscription(String topic, ResourcePath path, String serviceRootUrl) {
@@ -46,26 +48,35 @@ private void init() {
throw new IllegalArgumentException("Invalid subscription to: '" + topic + "': query options not allowed for subscription on an entitiy.");
}
entityType = ((EntityPathElement) path.getLastElement()).getEntityType();
- if (path.getPathElements().size() == 2
- && path.getPathElements().get(path.getPathElements().size() - 2) instanceof EntitySetPathElement) {
- matcher = x -> x.getProperty(EntityProperty.Id).equals(((EntityPathElement) path.getLastElement()).getId());
+ final int size = path.size();
+ if (size == 2 && path.get(0) instanceof EntitySetPathElement) {
+ Id id = ((EntityPathElement) path.getLastElement()).getId();
+ matcher = x -> x.getProperty(EntityProperty.ID).equals(id);
}
generateFilter(1);
}
@Override
- public boolean matches(PersistenceManager persistenceManager, Entity oldEntity, Entity newEntity) {
- if (matcher != null) {
- if (!matcher.test(newEntity)) {
- return false;
- }
+ public boolean matches(PersistenceManager persistenceManager, Entity newEntity, Set fields) {
+ if (matcher != null && !matcher.test(newEntity)) {
+ return false;
}
- return super.matches(persistenceManager, oldEntity, newEntity);
+ return super.matches(persistenceManager, newEntity, fields);
}
@Override
public String doFormatMessage(Entity entity) throws IOException {
- return new EntityFormatter().writeEntity(entity);
+ return EntityFormatter.writeEntity(entity);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode();
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/PropertySubscription.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/PropertySubscription.java
index 1e42210d0..5ed875ffc 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/PropertySubscription.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/PropertySubscription.java
@@ -1,38 +1,42 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
+import de.fraunhofer.iosb.ilt.sta.json.serialize.EntityFormatter;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.path.PropertyPathElement;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManager;
-import de.fraunhofer.iosb.ilt.sta.serialize.EntityFormatter;
import java.io.IOException;
-import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
import java.util.function.Predicate;
/**
*
* @author jab
*/
-public class PropertySubscription extends Subscription {
+public class PropertySubscription extends AbstractSubscription {
private Property property;
private Predicate super Entity> matcher;
@@ -46,38 +50,55 @@ private void init() {
if (!SubscriptionFactory.getQueryFromTopic(topic).isEmpty()) {
throw new IllegalArgumentException("Invalid subscription to: '" + topic + "': query options not allowed for subscription on a property.");
}
- entityType = ((EntityPathElement) path.getPathElements().get(path.getPathElements().size() - 2)).getEntityType();
- property = ((PropertyPathElement) path.getPathElements().get(path.getPathElements().size() - 1)).getProperty();
+ final int size = path.size();
+ entityType = ((EntityPathElement) path.get(size - 2)).getEntityType();
+ property = ((PropertyPathElement) path.get(size - 1)).getProperty();
if (path.getIdentifiedElement() != null) {
- matcher = x -> x.getProperty(EntityProperty.Id).equals(path.getIdentifiedElement().getId());
+ Id id = path.getIdentifiedElement().getId();
+ matcher = x -> x.getProperty(EntityProperty.ID).equals(id);
}
generateFilter(2);
}
@Override
- public boolean matches(PersistenceManager persistenceManager, Entity oldEntity, Entity newEntity) {
- if (matcher != null) {
- if (!matcher.test(newEntity)) {
- return false;
- }
+ public boolean matches(PersistenceManager persistenceManager, Entity newEntity, Set fields) {
+ if (matcher != null && !matcher.test(newEntity)) {
+ return false;
}
- if (oldEntity != null && newEntity != null) {
- if (oldEntity.getProperty(property) == null
- | newEntity.getProperty(property) == null) {
- return false;
- }
- if (oldEntity.getProperty(property) != null
- && newEntity.getProperty(property) != null
- && oldEntity.getProperty(property).equals(newEntity.getProperty(property))) {
- return false;
- }
+ if (fields == null || !fields.contains(property)) {
+ return false;
}
- return super.matches(persistenceManager, oldEntity, newEntity);
+ return super.matches(persistenceManager, newEntity, fields);
}
@Override
public String doFormatMessage(Entity entity) throws IOException {
- return new EntityFormatter(Arrays.asList(property)).writeEntity(entity);
+ HashSet propNames = new HashSet<>(1);
+ propNames.add(property.getJsonName());
+ entity.setSelectedPropertyNames(propNames);
+ return EntityFormatter.writeEntity(entity);
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), property);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final PropertySubscription other = (PropertySubscription) obj;
+ return super.equals(obj)
+ && Objects.equals(this.property, other.property);
+ }
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/Subscription.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/Subscription.java
index 60ccd4fb5..30e90ed2b 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/Subscription.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/Subscription.java
@@ -1,180 +1,66 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
-import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
-import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
-import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty;
import de.fraunhofer.iosb.ilt.sta.path.Property;
-import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManager;
-import de.fraunhofer.iosb.ilt.sta.query.Query;
-import de.fraunhofer.iosb.ilt.sta.query.expression.Expression;
-import de.fraunhofer.iosb.ilt.sta.query.expression.Path;
-import de.fraunhofer.iosb.ilt.sta.query.expression.constant.IntegerConstant;
-import de.fraunhofer.iosb.ilt.sta.query.expression.constant.StringConstant;
-import de.fraunhofer.iosb.ilt.sta.query.expression.function.comparison.Equal;
-import de.fraunhofer.iosb.ilt.sta.util.PathHelper;
-import de.fraunhofer.iosb.ilt.sta.util.UrlHelper;
import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.Set;
/**
*
- * @author jab
+ * @author scf
*/
-public abstract class Subscription {
-
- private static Map> navigationProperties = null;
- private static final Logger LOGGER = LoggerFactory.getLogger(Subscription.class);
- // TODO make encoding global constant
- protected static final Charset ENCODING = Charset.forName("UTF-8");
- protected final String topic;
- protected EntityType entityType;
- protected Expression matchExpression = null;
- protected ResourcePath path;
- protected String serviceRootUrl;
-
- public Subscription(String topic, ResourcePath path, String serviceRootUrl) {
- initNavigationProperties();
- this.topic = topic;
- this.path = path;
- this.serviceRootUrl = serviceRootUrl;
- }
-
- private void initNavigationProperties() {
- if (navigationProperties == null) {
- navigationProperties = new HashMap<>();
- for (EntityType entityType : EntityType.values()) {
- navigationProperties.put(entityType,
- entityType.getPropertySet().stream()
- .filter(x -> x instanceof NavigationProperty)
- .map(x -> (NavigationProperty) x)
- .collect(Collectors.toList()));
- }
- }
- }
-
- public boolean matches(PersistenceManager persistenceManager, Entity oldEntity, Entity newEntity) {
- if (!newEntity.getEntityType().equals(entityType)) {
- return false;
- }
- if (matchExpression != null) {
- Query query = new Query();
- query.setFilter(matchExpression);
- Object result = persistenceManager.get(newEntity.getPath(), query);
- return result != null;
- }
- return true;
- }
-
- protected void generateFilter(int pathElementOffset) {
- EntityType lastType = getEntityType();
- List properties = new ArrayList<>();
- for (int i = path.getPathElements().size() - 1 - pathElementOffset; i >= 0; i--) {
-
- if (path.getPathElements().get(i) instanceof EntityPathElement) {
- final EntityPathElement epe = (EntityPathElement) path.getPathElements().get(i);
- final NavigationProperty navProp = PathHelper.getNavigationProperty(lastType, epe.getEntityType());
- properties.add(navProp);
- lastType = epe.getEntityType();
-
- if (epe.getId() != null) {
- properties.add(EntityProperty.Id);
- String epeId = epe.getId().getUrl();
- if (epeId.startsWith("'")) {
- matchExpression = new Equal(new Path(properties), new StringConstant(epeId.substring(1, epeId.length() - 1)));
- } else {
- matchExpression = new Equal(new Path(properties), new IntegerConstant(epeId));
- }
- // there should be at most two PathElements left, the EntitySetPath and the EntityPath now visiting
- assert (i <= 1);
- return;
- }
- }
-
- }
-
- }
-
- public EntityType getEntityType() {
- return entityType;
- }
-
- public String getTopic() {
- return topic;
- }
-
- public String formatMessage(Entity entity) throws IOException {
- entity.setSelfLink(UrlHelper.generateSelfLink(path, entity));
- for (NavigationProperty navigationProperty : navigationProperties.get(entity.getEntityType())) {
- if (navigationProperty.isSet) {
- EntitySet property = (EntitySet) entity.getProperty(navigationProperty);
- property.setNavigationLink(UrlHelper.generateNavLink(path, entity, property, true));
- } else {
- Entity property = (Entity) entity.getProperty(navigationProperty);
- if (property != null) {
- property.setNavigationLink(UrlHelper.generateNavLink(path, entity, property, true));
- }
- }
- }
- return doFormatMessage(entity);
- }
-
- public abstract String doFormatMessage(Entity entity) throws IOException;
-
- @Override
- public int hashCode() {
- int hash = 7;
- hash = 97 * hash + Objects.hashCode(this.topic);
- hash = 97 * hash + Objects.hashCode(this.entityType);
- return hash;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final Subscription other = (Subscription) obj;
- if (!Objects.equals(this.topic, other.topic)) {
- return false;
- }
- if (this.entityType != other.entityType) {
- return false;
- }
- return true;
- }
+public interface Subscription {
+
+ /**
+ * Format the given entity so it fits for the subscription.
+ *
+ * @param entity The entity to format.
+ * @return A message body.
+ * @throws IOException If the formatting failed.
+ */
+ String formatMessage(Entity entity) throws IOException;
+
+ /**
+ * Get the type of entity that is of interest for this Subscription.
+ *
+ * @return the type of entity that is of interest for this Subscription.
+ */
+ EntityType getEntityType();
+
+ /**
+ * Get the topic of the Subscription.
+ *
+ * @return The topic of the Subscription.
+ */
+ String getTopic();
+
+ /**
+ * Check of the given entity is of interest to this Subscription.
+ *
+ * @param persistenceManager The PersistenceManager to use for queries.
+ * @param newEntity The entity to check.
+ * @param fields The fields of the entity that changed.
+ * @return true if the change is of interest for the Subscription.
+ */
+ boolean matches(PersistenceManager persistenceManager, Entity newEntity, Set fields);
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionEvent.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionEvent.java
index e22b75653..e2a28d7cc 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionEvent.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionEvent.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionFactory.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionFactory.java
index 928c26cc9..c4af44e69 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionFactory.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionFactory.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
@@ -24,9 +25,9 @@
import de.fraunhofer.iosb.ilt.sta.persistence.IdManager;
import de.fraunhofer.iosb.ilt.sta.persistence.PersistenceManagerFactory;
import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
-import java.nio.charset.Charset;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,10 +37,10 @@
*/
public class SubscriptionFactory {
+ private static final String URI_PATH_SEP = "/";
private static SubscriptionFactory instance;
- private static final Logger LOGGER = LoggerFactory.getLogger(Subscription.class);
- // TODO make encoding global constant
- private static final Charset ENCODING = Charset.forName("UTF-8");
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(SubscriptionFactory.class);
public static synchronized void init(CoreSettings settings) {
if (instance == null) {
@@ -56,17 +57,17 @@ public static synchronized SubscriptionFactory getInstance() {
private static String getPathFromTopic(String topic) {
String pathString = topic.contains("?")
- ? topic.substring(0, topic.indexOf("?"))
+ ? topic.substring(0, topic.indexOf('?'))
: topic;
- if (!pathString.startsWith("/")) {
- pathString = "/" + pathString;
+ if (!pathString.startsWith(URI_PATH_SEP)) {
+ pathString = URI_PATH_SEP + pathString;
}
return pathString;
}
public static String getQueryFromTopic(String topic) {
return topic.contains("?")
- ? topic.substring(topic.indexOf("?") + 1)
+ ? topic.substring(topic.indexOf('?') + 1)
: "";
}
private final CoreSettings settings;
@@ -82,33 +83,34 @@ public Subscription get(String topic) {
if (topic == null || topic.isEmpty()) {
throw new IllegalArgumentException(errorMsg + "topic must be non-empty.");
}
- if (topic.startsWith("/")) {
- throw new IllegalArgumentException(errorMsg + "topic must not start with '/'.");
+ if (topic.startsWith(URI_PATH_SEP)) {
+ throw new IllegalArgumentException(errorMsg + "topic must not start with '" + URI_PATH_SEP + "'.");
}
String internalTopic = topic;
String topicPrefix = settings.getMqttSettings().getTopicPrefix();
if (topicPrefix != null && !topicPrefix.isEmpty()) {
if (!topic.startsWith(topicPrefix)) {
- // TODO maybe just ignore subscriptio here?
- throw new IllegalArgumentException("Topic '" + topic + " does not start with expected prefix '" + topicPrefix + "'");
+ LOGGER.info("Subscription for invalid topic: {}", topic);
+ return null;
}
internalTopic = topic.substring(topicPrefix.length());
}
ResourcePath path = parsePath(getPathFromTopic(internalTopic));
- if (path == null || path.getPathElements().isEmpty()) {
+ if (path == null || path.isEmpty()) {
throw new IllegalArgumentException(errorMsg + "invalid path.");
}
path.setServiceRootUrl(settings.getServiceRootUrl());
path.compress();
+ final int size = path.size();
if (path.getLastElement() instanceof EntitySetPathElement) {
// SensorThings Standard 14.2.1 - Subscribe to EntitySet
return new EntitySetSubscription(topic, path, settings.getServiceRootUrl());
} else if (path.getLastElement() instanceof EntityPathElement) {
// SensorThings Standard 14.2.2 - Subscribe to Entity
return new EntitySubscription(topic, path, settings.getServiceRootUrl());
- } else if (path.getPathElements().size() >= 2
- && path.getPathElements().get(path.getPathElements().size() - 2) instanceof EntityPathElement
- && path.getPathElements().get(path.getPathElements().size() - 1) instanceof PropertyPathElement) {
+ } else if (size >= 2
+ && path.get(size - 2) instanceof EntityPathElement
+ && path.get(size - 1) instanceof PropertyPathElement) {
// SensorThings Standard 14.2.3 - Subscribe to Property
return new PropertySubscription(topic, path, settings.getServiceRootUrl());
@@ -121,14 +123,14 @@ public Subscription get(String topic) {
private ResourcePath parsePath(String topic) {
ResourcePath result = null;
try {
- String pathString = URLDecoder.decode(topic, ENCODING.name());
+ String pathString = URLDecoder.decode(topic, StringHelper.ENCODING.name());
result = PathParser.parsePath(idManager, "", pathString);
} catch (UnsupportedEncodingException ex) {
LOGGER.error("Encoding not supported.", ex);
} catch (NumberFormatException e) {
LOGGER.error("Not a valid id.");
} catch (IllegalStateException e) {
- LOGGER.error("Not a valid path: " + e.getMessage());
+ LOGGER.error("Not a valid path: {}", e.getMessage());
}
return result;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionListener.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionListener.java
index 5f779a69b..74cde36a3 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionListener.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/mqtt/subscription/SubscriptionListener.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.mqtt.subscription;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/DumpVisitor.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/DumpVisitor.java
deleted file mode 100644
index b8ee80d40..000000000
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/DumpVisitor.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
- * Karlsruhe, Germany.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-package de.fraunhofer.iosb.ilt.sta.parser.path;
-
-import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DumpVisitor implements ParserVisitor {
-
- /**
- * The logger for this class.
- */
- private static final Logger LOGGER = LoggerFactory.getLogger(DumpVisitor.class);
- private int indent = 0;
-
- private String indentString() {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < indent; ++i) {
- sb.append(" ");
- }
- return sb.toString();
- }
-
- public ResourcePath defltAction(SimpleNode node, ResourcePath data) {
- if (node.value == null) {
- LOGGER.info(indentString() + node);
- } else {
- LOGGER.info("{}{} : ({}){}", indentString(), node, node.value.getClass().getSimpleName(), node.value);
- }
- ++indent;
- node.childrenAccept(this, data);
- --indent;
- return data;
- }
-
- @Override
- public ResourcePath visit(SimpleNode node, ResourcePath data) {
- LOGGER.info("{}{}: acceptor not implemented in subclass?", indentString(), node);
- ++indent;
- node.childrenAccept(this, data);
- --indent;
- return data;
- }
-
- @Override
- public ResourcePath visit(ASTStart node, ResourcePath data) {
- LOGGER.info(indentString() + node);
- ++indent;
- node.childrenAccept(this, data);
- --indent;
- return data;
- }
-
- @Override
- public ResourcePath visit(ASTIdentifiedPath node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeDatastream node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcDatastreams node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeMultiDatastream node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcMultiDatastreams node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeFeatureOfInterest node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcFeaturesOfInterest node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeHistLocation node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcHistLocations node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeLocation node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcLocations node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeSensor node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcSensors node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeThing node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcThings node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeObservation node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcObservations node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTeObservedProp node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcObservedProps node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpId node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpSelfLink node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpDescription node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpDefinition node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpEncodingType node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpFeature node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpLocation node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpMetadata node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpName node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpObservationType node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpMultiObservationDataTypes node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpPhenomenonTime node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpProperties node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpResult node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpResultTime node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpTime node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpUnitOfMeasurement node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpUnitOfMeasurements node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTcpRef node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTppValue node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTppSubProperty node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTppArrayIndex node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTLong node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTString node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpObservedArea node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpParameters node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpResultQuality node, ResourcePath data) {
- return defltAction(node, data);
- }
-
- @Override
- public ResourcePath visit(ASTpValidTime node, ResourcePath data) {
- return defltAction(node, data);
- }
-
-}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/DumpVisitorHtml.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/DumpVisitorHtml.java
deleted file mode 100644
index 147683fae..000000000
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/DumpVisitorHtml.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
- * Karlsruhe, Germany.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-package de.fraunhofer.iosb.ilt.sta.parser.path;
-
-import java.io.PrintWriter;
-
-import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
-
-public class DumpVisitorHtml extends DumpVisitor {
-
- private int addOl = 0;
- private final PrintWriter out;
-
- public DumpVisitorHtml(PrintWriter out) {
- this.out = out;
- }
-
- private String prependString() {
- StringBuilder sb = new StringBuilder();
- while (addOl > 0) {
- sb.append("");
- addOl--;
- }
- sb.append("");
- return sb.toString();
- }
-
- private String appendString() {
- StringBuilder sb = new StringBuilder();
- while (addOl < 0) {
- sb.append(" ");
- addOl++;
- }
- sb.append("");
- return sb.toString();
- }
-
- @Override
- public ResourcePath defltAction(SimpleNode node, ResourcePath data) {
- if (node.value == null) {
- out.println(prependString() + node);
- } else {
- out.println(prependString() + node.toString() + " : (" + node.value.getClass().getSimpleName() + ") " + node.value);
- }
- ++addOl;
- node.childrenAccept(this, data);
- --addOl;
- out.println(appendString());
- return data;
- }
-
- @Override
- public ResourcePath visit(ASTStart node, ResourcePath data) {
- out.println("");
- ResourcePath o = defltAction(node, data);
- out.println(" ");
- return o;
- }
-
- @Override
- public ResourcePath visit(SimpleNode node, ResourcePath data) {
- out.println(prependString() + node + ": acceptor not implemented in subclass?{}");
- ++addOl;
- node.childrenAccept(this, data);
- --addOl;
- out.println(appendString());
- return data;
- }
-
-}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/PathParser.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/PathParser.java
index 577ecea47..0428d1415 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/PathParser.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/path/PathParser.java
@@ -26,16 +26,16 @@
import de.fraunhofer.iosb.ilt.sta.path.PropertyPathElement;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.persistence.IdManager;
+import de.fraunhofer.iosb.ilt.sta.persistence.IdManagerlong;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
-import java.util.ArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PathParser implements ParserVisitor {
- private static final Charset ENCODING = Charset.forName("UTF-8");
/**
* The logger for this class.
*/
@@ -43,25 +43,48 @@ public class PathParser implements ParserVisitor {
private final IdManager idmanager;
+ /**
+ * Parse the given path with an IdManagerlong and UTF-8 encoding.
+ *
+ * @param serviceRootUrl The root url to use when parsing.
+ * @param path The path to parse.
+ * @return The parsed ResourcePath.
+ */
public static ResourcePath parsePath(String serviceRootUrl, String path) {
- return parsePath(IdManager.ID_MANAGER_LONG, serviceRootUrl, path, ENCODING);
+ return parsePath(new IdManagerlong(), serviceRootUrl, path, StringHelper.ENCODING);
}
+ /**
+ * Parse the given path, assuming UTF-8 encoding.
+ *
+ * @param idmanager The IdManager to use
+ * @param serviceRootUrl The root url to use when parsing.
+ * @param path The path to parse.
+ * @return The parsed ResourcePath.
+ */
public static ResourcePath parsePath(IdManager idmanager, String serviceRootUrl, String path) {
- return parsePath(idmanager, serviceRootUrl, path, ENCODING);
+ return parsePath(idmanager, serviceRootUrl, path, StringHelper.ENCODING);
}
+ /**
+ * Parse the given path.
+ *
+ * @param idmanager The IdManager to use
+ * @param serviceRootUrl The root url to use when parsing.
+ * @param path The path to parse.
+ * @param encoding The character encoding to use when parsing.
+ * @return The parsed ResourcePath.
+ */
public static ResourcePath parsePath(IdManager idmanager, String serviceRootUrl, String path, Charset encoding) {
ResourcePath resourcePath = new ResourcePath();
resourcePath.setServiceRootUrl(serviceRootUrl);
resourcePath.setPathUrl(path);
- resourcePath.setPathElements(new ArrayList<>());
if (path == null) {
return resourcePath;
}
LOGGER.debug("Parsing: {}", path);
InputStream is = new ByteArrayInputStream(path.getBytes(encoding));
- Parser t = new Parser(is, ENCODING.name());
+ Parser t = new Parser(is, StringHelper.ENCODING.name());
try {
ASTStart start = t.Start();
PathParser v = new PathParser(idmanager);
@@ -80,7 +103,7 @@ public PathParser(IdManager idmanager) {
public ResourcePath defltAction(SimpleNode node, ResourcePath data) {
if (node.value == null) {
- LOGGER.debug(node.toString());
+ LOGGER.debug("{}", node);
} else {
LOGGER.debug("{} : ({}){}", node, node.value.getClass().getSimpleName(), node.value);
}
@@ -96,30 +119,28 @@ private void addAsEntitiy(ResourcePath rp, SimpleNode node, EntityType type) {
rp.setIdentifiedElement(epa);
}
epa.setParent(rp.getLastElement());
- rp.getPathElements().add(epa);
- rp.setMainElement(epa);
+ rp.addPathElement(epa, true, false);
}
private void addAsEntitiySet(ResourcePath rp, EntityType type) {
EntitySetPathElement espa = new EntitySetPathElement();
espa.setEntityType(type);
espa.setParent(rp.getLastElement());
- rp.getPathElements().add(espa);
- rp.setMainElement(espa);
+ rp.addPathElement(espa, true, false);
}
private void addAsEntitiyProperty(ResourcePath rp, EntityProperty type) {
PropertyPathElement ppe = new PropertyPathElement();
ppe.setProperty(type);
ppe.setParent(rp.getLastElement());
- rp.getPathElements().add(ppe);
+ rp.addPathElement(ppe);
}
private void addAsCustomProperty(ResourcePath rp, SimpleNode node) {
CustomPropertyPathElement cppa = new CustomPropertyPathElement();
cppa.setName(node.value.toString());
cppa.setParent(rp.getLastElement());
- rp.getPathElements().add(cppa);
+ rp.addPathElement(cppa);
}
private void addAsArrayIndex(ResourcePath rp, SimpleNode node) {
@@ -133,7 +154,7 @@ private void addAsArrayIndex(ResourcePath rp, SimpleNode node) {
int index = Integer.parseInt(numberString);
cpai.setIndex(index);
cpai.setParent(rp.getLastElement());
- rp.getPathElements().add(cpai);
+ rp.addPathElement(cpai);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Array indices must be integer values. Failed to parse: " + image);
}
@@ -159,217 +180,217 @@ public ResourcePath visit(ASTIdentifiedPath node, ResourcePath data) {
@Override
public ResourcePath visit(ASTeDatastream node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.Datastream);
+ addAsEntitiy(data, node, EntityType.DATASTREAM);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcDatastreams node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.Datastream);
+ addAsEntitiySet(data, EntityType.DATASTREAM);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeMultiDatastream node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.MultiDatastream);
+ addAsEntitiy(data, node, EntityType.MULTIDATASTREAM);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcMultiDatastreams node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.MultiDatastream);
+ addAsEntitiySet(data, EntityType.MULTIDATASTREAM);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeFeatureOfInterest node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.FeatureOfInterest);
+ addAsEntitiy(data, node, EntityType.FEATUREOFINTEREST);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcFeaturesOfInterest node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.FeatureOfInterest);
+ addAsEntitiySet(data, EntityType.FEATUREOFINTEREST);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeHistLocation node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.HistoricalLocation);
+ addAsEntitiy(data, node, EntityType.HISTORICALLOCATION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcHistLocations node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.HistoricalLocation);
+ addAsEntitiySet(data, EntityType.HISTORICALLOCATION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeLocation node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.Location);
+ addAsEntitiy(data, node, EntityType.LOCATION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcLocations node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.Location);
+ addAsEntitiySet(data, EntityType.LOCATION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeSensor node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.Sensor);
+ addAsEntitiy(data, node, EntityType.SENSOR);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcSensors node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.Sensor);
+ addAsEntitiySet(data, EntityType.SENSOR);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeThing node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.Thing);
+ addAsEntitiy(data, node, EntityType.THING);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcThings node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.Thing);
+ addAsEntitiySet(data, EntityType.THING);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeObservation node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.Observation);
+ addAsEntitiy(data, node, EntityType.OBSERVATION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcObservations node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.Observation);
+ addAsEntitiySet(data, EntityType.OBSERVATION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTeObservedProp node, ResourcePath data) {
- addAsEntitiy(data, node, EntityType.ObservedProperty);
+ addAsEntitiy(data, node, EntityType.OBSERVEDPROPERTY);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTcObservedProps node, ResourcePath data) {
- addAsEntitiySet(data, EntityType.ObservedProperty);
+ addAsEntitiySet(data, EntityType.OBSERVEDPROPERTY);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpId node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Id);
+ addAsEntitiyProperty(data, EntityProperty.ID);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpSelfLink node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.SelfLink);
+ addAsEntitiyProperty(data, EntityProperty.SELFLINK);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpDescription node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Description);
+ addAsEntitiyProperty(data, EntityProperty.DESCRIPTION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpDefinition node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Definition);
+ addAsEntitiyProperty(data, EntityProperty.DEFINITION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpEncodingType node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.EncodingType);
+ addAsEntitiyProperty(data, EntityProperty.ENCODINGTYPE);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpFeature node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Feature);
+ addAsEntitiyProperty(data, EntityProperty.FEATURE);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpLocation node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Location);
+ addAsEntitiyProperty(data, EntityProperty.LOCATION);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpMetadata node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Metadata);
+ addAsEntitiyProperty(data, EntityProperty.METADATA);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpName node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Name);
+ addAsEntitiyProperty(data, EntityProperty.NAME);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpObservationType node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.ObservationType);
+ addAsEntitiyProperty(data, EntityProperty.OBSERVATIONTYPE);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpMultiObservationDataTypes node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.MultiObservationDataTypes);
+ addAsEntitiyProperty(data, EntityProperty.MULTIOBSERVATIONDATATYPES);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpPhenomenonTime node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.PhenomenonTime);
+ addAsEntitiyProperty(data, EntityProperty.PHENOMENONTIME);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpProperties node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Properties);
+ addAsEntitiyProperty(data, EntityProperty.PROPERTIES);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpResult node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Result);
+ addAsEntitiyProperty(data, EntityProperty.RESULT);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpResultTime node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.ResultTime);
+ addAsEntitiyProperty(data, EntityProperty.RESULTTIME);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpTime node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Time);
+ addAsEntitiyProperty(data, EntityProperty.TIME);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpUnitOfMeasurement node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.UnitOfMeasurement);
+ addAsEntitiyProperty(data, EntityProperty.UNITOFMEASUREMENT);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpUnitOfMeasurements node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.UnitOfMeasurements);
+ addAsEntitiyProperty(data, EntityProperty.UNITOFMEASUREMENTS);
return defltAction(node, data);
}
@@ -409,25 +430,25 @@ public ResourcePath visit(ASTString node, ResourcePath data) {
@Override
public ResourcePath visit(ASTpObservedArea node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.ObservedArea);
+ addAsEntitiyProperty(data, EntityProperty.OBSERVEDAREA);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpParameters node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.Parameters);
+ addAsEntitiyProperty(data, EntityProperty.PARAMETERS);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpResultQuality node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.ResultQuality);
+ addAsEntitiyProperty(data, EntityProperty.RESULTQUALITY);
return defltAction(node, data);
}
@Override
public ResourcePath visit(ASTpValidTime node, ResourcePath data) {
- addAsEntitiyProperty(data, EntityProperty.ValidTime);
+ addAsEntitiyProperty(data, EntityProperty.VALIDTIME);
return defltAction(node, data);
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/DumpVisitor.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/DumpVisitor.java
deleted file mode 100644
index 610be81e6..000000000
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/DumpVisitor.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
- * Karlsruhe, Germany.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-package de.fraunhofer.iosb.ilt.sta.parser.query;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DumpVisitor implements ParserVisitor {
-
- /**
- * The logger for this class.
- */
- private static final Logger LOGGER = LoggerFactory.getLogger(DumpVisitor.class);
- private int indent = 0;
-
- private String indentString() {
- StringBuilder sb = new StringBuilder();
- boolean line = true;
- for (int i = 0; i < indent; ++i) {
- if (line) {
- sb.append("| ");
- } else {
- sb.append(" ");
- }
- line = !line;
- }
- return sb.toString();
- }
-
- public Object defltAction(SimpleNode node, Object data) {
- if (node.value == null) {
- LOGGER.info(indentString() + node);
- } else {
- LOGGER.info(indentString() + node + " : (" + node.value.getClass().getName() + ") " + node.value);
- }
- ++indent;
- node.childrenAccept(this, data);
- --indent;
- return data;
- }
-
- @Override
- public Object visit(SimpleNode node, Object data) {
- LOGGER.info("{}{}: acceptor not implemented in subclass?", indentString(), node);
- ++indent;
- node.childrenAccept(this, data);
- --indent;
- return data;
- }
-
- @Override
- public Object visit(ASTStart node, Object data) {
- LOGGER.info(indentString() + node);
- ++indent;
- node.childrenAccept(this, data);
- --indent;
- return data;
- }
-
- @Override
- public Object visit(ASTOptions node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTOption node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTOrderBys node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTOrderBy node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTIdentifiers node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTPlainPaths node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTPlainPath node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTPathElement node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTFilteredPaths node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTFilteredPath node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTIdentifiedPaths node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTIdentifiedPath node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTFilter node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTFormat node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTLogicalOr node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTLogicalAnd node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTNot node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTBooleanFunction node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTComparison node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTPlusMin node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTOperator node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTMulDiv node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTValueNode node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTBool node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTFunction node, Object data) {
- return defltAction(node, data);
- }
-
- @Override
- public Object visit(ASTGeoStringLit node, Object data) {
- return defltAction(node, data);
- }
-
-}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/DumpVisitorHtml.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/DumpVisitorHtml.java
deleted file mode 100644
index 185dd1a75..000000000
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/DumpVisitorHtml.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
- * Karlsruhe, Germany.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-package de.fraunhofer.iosb.ilt.sta.parser.query;
-
-import java.io.PrintWriter;
-
-import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
-
-public class DumpVisitorHtml extends DumpVisitor {
-
- private int addOl = 0;
- private final PrintWriter out;
-
- public DumpVisitorHtml(PrintWriter out) {
- this.out = out;
- }
-
- private String prependString() {
- StringBuilder sb = new StringBuilder();
- while (addOl > 0) {
- sb.append("");
- addOl--;
- }
- sb.append("");
- return sb.toString();
- }
-
- private String appendString() {
- StringBuilder sb = new StringBuilder();
- while (addOl < 0) {
- sb.append(" ");
- addOl++;
- }
- sb.append("");
- return sb.toString();
- }
-
- @Override
- public Object defltAction(SimpleNode node, Object data) {
- out.println(prependString() + node);
- ++addOl;
- node.childrenAccept(this, data);
- --addOl;
- out.println(appendString());
- return data;
- }
-
- @Override
- public Object visit(ASTStart node, Object data) {
- out.println("");
- Object o = defltAction(node, data);
- out.println(" ");
- return o;
- }
-
- @Override
- public Object visit(SimpleNode node, Object data) {
- out.println(prependString() + node + ": acceptor not implemented in subclass?{}");
- ++addOl;
- node.childrenAccept(this, data);
- --addOl;
- out.println(appendString());
- return data;
- }
-
-}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/ExpressionParser.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/ExpressionParser.java
index 47143cc3d..b0f667eb3 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/ExpressionParser.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/ExpressionParser.java
@@ -59,15 +59,15 @@
import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Time;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.TotalOffsetMinutes;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Year;
-import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoDistance;
-import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoIntersects;
-import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoLength;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.And;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.Not;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.Or;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.math.Ceiling;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.math.Floor;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.math.Round;
+import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.GeoDistance;
+import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.GeoIntersects;
+import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.GeoLength;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STContains;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STCrosses;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.STDisjoint;
@@ -95,7 +95,9 @@
import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.Overlaps;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.temporal.Starts;
import de.fraunhofer.iosb.ilt.sta.util.ParserHelper;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -104,6 +106,7 @@
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import org.joda.time.Period;
+import org.slf4j.LoggerFactory;
/**
*
@@ -111,65 +114,112 @@
*/
public class ExpressionParser extends AbstractParserVisitor {
- private static final String OP_NOT = "not";
- private static final String OP_AND = "and";
- private static final String OP_OR = "or";
- private static final String OP_ADD = "+";
- private static final String OP_SUB = "-";
- private static final String OP_MUL = "mul";
- private static final String OP_DIV = "div";
- private static final String OP_MOD = "mod";
- private static final String OP_EQUAL = "eq";
- private static final String OP_NOT_EQUAL = "ne";
- private static final String OP_GREATER_THAN = "gt";
- private static final String OP_GREATER_EQUAL = "ge";
- private static final String OP_LESS_THAN = "lt";
- private static final String OP_LESS_EQUAL = "le";
- private static final String OP_SUBSTRING_OF = "substringof";
- private static final String OP_ENDS_WITH = "endswith";
- private static final String OP_STARTS_WITH = "startswith";
- private static final String OP_LENGTH = "length";
- private static final String OP_INDEX_OF = "indexof";
- private static final String OP_SUBSTRING = "substring";
- private static final String OP_TO_LOWER = "tolower";
- private static final String OP_TO_UPPER = "toupper";
- private static final String OP_TRIM = "trim";
- private static final String OP_CONCAT = "concat";
- private static final String OP_YEAR = "year";
- private static final String OP_MONTH = "month";
- private static final String OP_DAY = "day";
- private static final String OP_HOUR = "hour";
- private static final String OP_MINUTE = "minute";
- private static final String OP_SECOND = "second";
- private static final String OP_FRACTIONAL_SECONDS = "fractionalseconds";
- private static final String OP_DATE = "date";
- private static final String OP_TIME = "time";
- private static final String OP_TOTAL_OFFSET_MINUTES = "totaloffsetminutes";
- private static final String OP_NOW = "now";
- private static final String OP_MIN_DATETIME = "mindatetime";
- private static final String OP_MAX_DATETIME = "maxdatetime";
- private static final String OP_BEFORE = "before";
- private static final String OP_AFTER = "after";
- private static final String OP_MEETS = "meets";
- private static final String OP_DURING = "during";
- private static final String OP_OVERLAPS = "overlaps";
- private static final String OP_STARTS = "starts";
- private static final String OP_FINISHES = "finishes";
- private static final String OP_ROUND = "round";
- private static final String OP_FLOOR = "floor";
- private static final String OP_CEILING = "ceiling";
- private static final String OP_GEO_DISTANCE = "geo.distance";
- private static final String OP_GEO_LENGTH = "geo.length";
- private static final String OP_GEO_INTERSECTS = "geo.intersects";
- private static final String OP_ST_EQUALS = "st_equals";
- private static final String OP_ST_DISJOINT = "st_disjoint";
- private static final String OP_ST_TOUCHES = "st_touches";
- private static final String OP_ST_WITHIN = "st_within";
- private static final String OP_ST_OVERLAPS = "st_overlaps";
- private static final String OP_ST_CROSSES = "st_crosses";
- private static final String OP_ST_INTERSECTS = "st_intersects";
- private static final String OP_ST_CONTAINS = "st_contains";
- private static final String OP_ST_RELATE = "st_relate";
+ /**
+ * The logger for this class.
+ */
+ private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ExpressionParser.class);
+
+ public enum Operator {
+ // Logical
+ OP_NOT("not", Not.class),
+ OP_AND("and", And.class),
+ OP_OR("or", Or.class),
+ // Math
+ OP_ADD("+", Add.class),
+ OP_SUB("-", Subtract.class),
+ OP_MUL("mul", Multiply.class),
+ OP_DIV("div", Divide.class),
+ OP_MOD("mod", Modulo.class),
+ // Comparison
+ OP_EQUAL("eq", Equal.class),
+ OP_NOT_EQUAL("ne", NotEqual.class),
+ OP_GREATER_THAN("gt", GreaterThan.class),
+ OP_GREATER_EQUAL("ge", GreaterEqual.class),
+ OP_LESS_THAN("lt", LessThan.class),
+ OP_LESS_EQUAL("le", LessEqual.class),
+ // String
+ OP_SUBSTRING_OF("substringof", SubstringOf.class),
+ OP_ENDS_WITH("endswith", EndsWith.class),
+ OP_STARTS_WITH("startswith", StartsWith.class),
+ OP_LENGTH("length", Length.class),
+ OP_INDEX_OF("indexof", IndexOf.class),
+ OP_SUBSTRING("substring", Substring.class),
+ OP_TO_LOWER("tolower", ToLower.class),
+ OP_TO_UPPER("toupper", ToUpper.class),
+ OP_TRIM("trim", Trim.class),
+ OP_CONCAT("concat", Concat.class),
+ // DateTime
+ OP_YEAR("year", Year.class),
+ OP_MONTH("month", Month.class),
+ OP_DAY("day", Day.class),
+ OP_HOUR("hour", Hour.class),
+ OP_MINUTE("minute", Minute.class),
+ OP_SECOND("second", Second.class),
+ OP_FRACTIONAL_SECONDS("fractionalseconds", FractionalSeconds.class),
+ OP_DATE("date", Date.class),
+ OP_TIME("time", Time.class),
+ OP_TOTAL_OFFSET_MINUTES("totaloffsetminutes", TotalOffsetMinutes.class),
+ OP_NOW("now", Now.class),
+ OP_MIN_DATETIME("mindatetime", MinDateTime.class),
+ OP_MAX_DATETIME("maxdatetime", MaxDateTime.class),
+ // Allen's interval algebra
+ OP_BEFORE("before", Before.class),
+ OP_AFTER("after", After.class),
+ OP_MEETS("meets", Meets.class),
+ OP_DURING("during", During.class),
+ OP_OVERLAPS("overlaps", Overlaps.class),
+ OP_STARTS("starts", Starts.class),
+ OP_FINISHES("finishes", Finishes.class),
+ // Math
+ OP_ROUND("round", Round.class),
+ OP_FLOOR("floor", Floor.class),
+ OP_CEILING("ceiling", Ceiling.class),
+ // Geo
+ OP_GEO_DISTANCE("geo.distance", GeoDistance.class),
+ OP_GEO_LENGTH("geo.length", GeoLength.class),
+ OP_GEO_INTERSECTS("geo.intersects", GeoIntersects.class),
+ OP_ST_EQUALS("st_equals", STEquals.class),
+ OP_ST_DISJOINT("st_disjoint", STDisjoint.class),
+ OP_ST_TOUCHES("st_touches", STTouches.class),
+ OP_ST_WITHIN("st_within", STWithin.class),
+ OP_ST_OVERLAPS("st_overlaps", STOverlaps.class),
+ OP_ST_CROSSES("st_crosses", STCrosses.class),
+ OP_ST_INTERSECTS("st_intersects", STIntersects.class),
+ OP_ST_CONTAINS("st_contains", STContains.class),
+ OP_ST_RELATE("st_relate", STRelate.class);
+
+ private static final Map byKey = new HashMap<>();
+
+ static {
+ for (Operator o : Operator.values()) {
+ byKey.put(o.urlKey, o);
+ }
+ }
+ public final String urlKey;
+ public final Class extends Function> implementingClass;
+
+ private Operator(String urlKey, Class extends Function> implementingClass) {
+ this.urlKey = urlKey;
+ this.implementingClass = implementingClass;
+ }
+
+ public Function instantiate() {
+ try {
+ return implementingClass.newInstance();
+ } catch (InstantiationException | IllegalAccessException ex) {
+ LOGGER.error("Failed to instantiate function {}: {}", this, ex.getMessage());
+ throw new IllegalStateException("problem executing '" + this + "'", ex);
+ }
+ }
+
+ public static Operator fromKey(String key) {
+ Operator operator = byKey.get(key);
+ if (operator == null) {
+ throw new IllegalArgumentException("Unknown operator: '" + key + "'.");
+ }
+ return operator;
+ }
+ }
public static Expression parseExpression(Node node) {
return new ExpressionParser().visit(node, null);
@@ -201,12 +251,11 @@ public Path visit(ASTPlainPath node, Object data) {
@Override
public Property visit(ASTPathElement node, Object data) {
- // TODO only name or also ID allowed???
if (node.getIdentifier() != null && !node.getIdentifier().isEmpty()) {
throw new IllegalArgumentException("no identified paths are allowed inside expressions");
}
Property previous = null;
- if (data != null && data instanceof Property) {
+ if (data instanceof Property) {
previous = (Property) data;
}
return ParserHelper.parseProperty(node.getName(), previous);
@@ -222,35 +271,22 @@ public Expression visit(ASTFilter node, Object data) {
@Override
public Or visit(ASTLogicalOr node, Object data) {
- return (Or) visitLogicalFunction(OP_OR, node, data);
+ return (Or) visitLogicalFunction(Operator.OP_OR, node, data);
}
@Override
public And visit(ASTLogicalAnd node, Object data) {
- return (And) visitLogicalFunction(OP_AND, node, data);
- }
-
- private Function getLogicalFunction(String operator) {
- switch (operator) {
- case OP_AND: {
- return new And();
- }
- case OP_OR: {
- return new Or();
- }
- default:
- throw new IllegalArgumentException("unknown operator '" + operator + "'");
- }
+ return (And) visitLogicalFunction(Operator.OP_AND, node, data);
}
- private Function visitLogicalFunction(String operator, Node node, Object data) {
+ private Function visitLogicalFunction(Operator operator, Node node, Object data) {
if (node.jjtGetNumChildren() < 2) {
throw new IllegalArgumentException("'" + operator + "' must have at least two parameters");
}
- Function function = getLogicalFunction(operator);
+ Function function = operator.instantiate();
Expression result = visitChildWithType(function, node.jjtGetChild(node.jjtGetNumChildren() - 1), data, 1);
for (int i = node.jjtGetNumChildren() - 2; i >= 0; i--) {
- function = getLogicalFunction(operator);
+ function = operator.instantiate();
Expression lhs = visitChildWithType(function, node.jjtGetChild(i), data, 0);
function.setParameters(lhs, result);
result = function;
@@ -284,28 +320,6 @@ private Expression visit(Node node, Object data) {
return (Expression) node.jjtAccept(this, data);
}
- private Function getArithmeticFunction(String operator) {
- switch (operator) {
- case OP_ADD: {
- return new Add();
- }
- case OP_SUB: {
- return new Subtract();
- }
- case OP_MUL: {
- return new Multiply();
- }
- case OP_DIV: {
- return new Divide();
- }
- case OP_MOD: {
- return new Modulo();
- }
- default:
- throw new IllegalArgumentException("unknown operator '" + operator + "'");
- }
- }
-
private Function visitArithmeticFunction(SimpleNode node, Object data) {
int childCount = node.jjtGetNumChildren();
if (childCount < 3 || childCount % 2 == 0) {
@@ -316,25 +330,26 @@ private Function visitArithmeticFunction(SimpleNode node, Object data) {
Expression rhs;
Expression lhs;
Function result = null;
- for (int i = 0; i < childCount; i++) {
- assert (i < childCount - 1);
- int operatorIndex = result == null ? i + 1 : i;
+ int idx = 0;
+ while (idx < childCount) {
+ int operatorIndex = result == null ? idx + 1 : idx;
if (!(node.jjtGetChild(operatorIndex) instanceof ASTOperator)) {
- throw new IllegalArgumentException("operator expected but '" + node.jjtGetChild(i).getClass().getName() + "' found");
+ throw new IllegalArgumentException("operator expected but '" + node.jjtGetChild(idx).getClass().getName() + "' found");
}
- String operator = ((ASTOperator) node.jjtGetChild(operatorIndex)).getName().trim().toLowerCase();
- Function function = getArithmeticFunction(operator);
+ String operatorKey = ((ASTOperator) node.jjtGetChild(operatorIndex)).getName().trim().toLowerCase();
+ Function function = getFunction(operatorKey);
if (result == null) {
- lhs = visitChildWithType(function, node.jjtGetChild(i), data, 1);
- i++;
+ lhs = visitChildWithType(function, node.jjtGetChild(idx), data, 1);
+ idx++;
} else {
lhs = result;
}
- i++;
- rhs = visitChildWithType(function, node.jjtGetChild(i), data, 0);
+ idx++;
+ rhs = visitChildWithType(function, node.jjtGetChild(idx), data, 0);
function.setParameters(lhs, rhs);
result = function;
+ idx++;
}
return result;
}
@@ -350,168 +365,7 @@ public Function visit(ASTMulDiv node, Object data) {
}
private Function getFunction(String operator) {
- switch (operator) {
- /* comparison functions */
- case OP_NOT: {
- return new Not();
- }
- case OP_EQUAL: {
- return new Equal();
- }
- case OP_NOT_EQUAL: {
- return new NotEqual();
- }
- case OP_GREATER_THAN: {
- return new GreaterThan();
- }
- case OP_GREATER_EQUAL: {
- return new GreaterEqual();
- }
- case OP_LESS_THAN: {
- return new LessThan();
- }
- case OP_LESS_EQUAL: {
- return new LessEqual();
- }
- /* string functions */
- case OP_SUBSTRING_OF: {
- return new SubstringOf();
- }
- case OP_ENDS_WITH: {
- return new EndsWith();
- }
- case OP_STARTS_WITH: {
- return new StartsWith();
- }
- case OP_LENGTH: {
- return new Length();
- }
- case OP_INDEX_OF: {
- return new IndexOf();
- }
- case OP_SUBSTRING: {
- return new Substring();
- }
- case OP_TO_LOWER: {
- return new ToLower();
- }
- case OP_TO_UPPER: {
- return new ToUpper();
- }
- case OP_TRIM: {
- return new Trim();
- }
- case OP_CONCAT: {
- return new Concat();
- }
- case OP_YEAR: {
- return new Year();
- }
- case OP_MONTH: {
- return new Month();
- }
- case OP_DAY: {
- return new Day();
- }
- case OP_HOUR: {
- return new Hour();
- }
- case OP_MINUTE: {
- return new Minute();
- }
- case OP_SECOND: {
- return new Second();
- }
- case OP_FRACTIONAL_SECONDS: {
- return new FractionalSeconds();
- }
- case OP_DATE: {
- return new Date();
- }
- case OP_TIME: {
- return new Time();
- }
- case OP_TOTAL_OFFSET_MINUTES: {
- return new TotalOffsetMinutes();
- }
- case OP_NOW: {
- return new Now();
- }
- case OP_MIN_DATETIME: {
- return new MinDateTime();
- }
- case OP_MAX_DATETIME: {
- return new MaxDateTime();
- }
- case OP_BEFORE: {
- return new Before();
- }
- case OP_AFTER: {
- return new After();
- }
- case OP_MEETS: {
- return new Meets();
- }
- case OP_DURING: {
- return new During();
- }
- case OP_OVERLAPS: {
- return new Overlaps();
- }
- case OP_STARTS: {
- return new Starts();
- }
- case OP_FINISHES: {
- return new Finishes();
- }
- case OP_ROUND: {
- return new Round();
- }
- case OP_FLOOR: {
- return new Floor();
- }
- case OP_CEILING: {
- return new Ceiling();
- }
- case OP_GEO_DISTANCE: {
- return new GeoDistance();
- }
- case OP_GEO_LENGTH: {
- return new GeoLength();
- }
- case OP_GEO_INTERSECTS: {
- return new GeoIntersects();
- }
- case OP_ST_EQUALS: {
- return new STEquals();
- }
- case OP_ST_DISJOINT: {
- return new STDisjoint();
- }
- case OP_ST_TOUCHES: {
- return new STTouches();
- }
- case OP_ST_WITHIN: {
- return new STWithin();
- }
- case OP_ST_OVERLAPS: {
- return new STOverlaps();
- }
- case OP_ST_CROSSES: {
- return new STCrosses();
- }
- case OP_ST_INTERSECTS: {
- return new STIntersects();
- }
- case OP_ST_CONTAINS: {
- return new STContains();
- }
- case OP_ST_RELATE: {
- return new STRelate();
- }
- default:
- throw new IllegalArgumentException("unknown function '" + operator + "'");
- }
+ return Operator.fromKey(operator).instantiate();
}
@Override
@@ -525,12 +379,8 @@ public Function visit(ASTFunction node, Object data) {
private Expression[] visitChildsWithType(Function function, Node node, Object data) {
List allowedBindings = function.getAllowedTypeBindings();
if (data != null) {
- try {
- List> allowedReturnTypes = (List>) data;
- allowedBindings = allowedBindings.stream().filter(x -> allowedReturnTypes.contains(x.getReturnType())).collect(Collectors.toList());
- } catch (Exception e) {
-
- }
+ List> allowedReturnTypes = (List>) data;
+ allowedBindings = allowedBindings.stream().filter(x -> allowedReturnTypes.contains(x.getReturnType())).collect(Collectors.toList());
}
Expression[] parameters = new Expression[node.jjtGetNumChildren()];
for (int i = 0; i < parameters.length; i++) {
@@ -542,12 +392,8 @@ private Expression[] visitChildsWithType(Function function, Node node, Object da
private Expression visitChildWithType(Function function, Node child, Object data, int parameterIndex) {
List allowedBindings = function.getAllowedTypeBindings();
if (data != null) {
- try {
- List> allowedReturnTypes = (List>) data;
- allowedBindings = allowedBindings.stream().filter(x -> allowedReturnTypes.contains(x.getReturnType())).collect(Collectors.toList());
- } catch (Exception e) {
-
- }
+ List> allowedReturnTypes = (List>) data;
+ allowedBindings = allowedBindings.stream().filter(x -> allowedReturnTypes.contains(x.getReturnType())).collect(Collectors.toList());
}
return visit(child, allowedBindings.stream().map(x -> x.getParameters().get(parameterIndex)).collect(Collectors.toList()));
}
@@ -562,7 +408,7 @@ public Constant visit(ASTValueNode node, Object data) {
} else if (value instanceof Integer) {
return new IntegerConstant((Integer) value);
} else if (value instanceof Long) {
- return new IntegerConstant(((Long) value).intValue());
+ return new IntegerConstant(((Number) value).intValue());
} else if (value instanceof DateTime) {
return new DateTimeConstant((DateTime) value);
} else if (value instanceof LocalDate) {
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/QueryParser.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/QueryParser.java
index 4589b54fe..e839fa50d 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/QueryParser.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/parser/query/QueryParser.java
@@ -24,6 +24,7 @@
import de.fraunhofer.iosb.ilt.sta.query.Query;
import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
import de.fraunhofer.iosb.ilt.sta.util.ParserHelper;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
@@ -38,7 +39,7 @@ public class QueryParser extends AbstractParserVisitor {
* The logger for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(QueryParser.class);
- private static final Charset ENCODING = Charset.forName("UTF-8");
+
private final CoreSettings settings;
public QueryParser(CoreSettings settings) {
@@ -50,22 +51,22 @@ public static Query parseQuery(String query) {
}
public static Query parseQuery(String query, CoreSettings settings) {
- return parseQuery(query, ENCODING, settings);
+ return parseQuery(query, StringHelper.ENCODING, settings);
}
public static Query parseQuery(String query, Charset encoding, CoreSettings settings) {
if (query == null || query.isEmpty()) {
- Query result = new Query(settings);
- return result;
+ return new Query(settings);
}
- LOGGER.debug("Parsing: {}", query);
+
InputStream is = new ByteArrayInputStream(query.getBytes(encoding));
- Parser t = new Parser(is, ENCODING.name());
+ Parser t = new Parser(is, StringHelper.ENCODING.name());
try {
ASTStart n = t.Start();
QueryParser v = new QueryParser(settings);
return v.visit(n, null);
} catch (ParseException | TokenMgrError | IllegalArgumentException ex) {
+ LOGGER.error("Exception parsing: {}", query);
LOGGER.error("Failed to parse because (Set loglevel to trace for stack): {}", ex.getMessage());
LOGGER.trace("Exception: ", ex);
throw new IllegalArgumentException("Query is not valid: " + ex.getMessage(), ex);
@@ -101,51 +102,50 @@ public Object visit(ASTOption node, Object data) {
Query query = (Query) data;
String operator = node.getType().toLowerCase().trim();
switch (operator) {
- case OP_TOP: {
+ case OP_TOP:
int top = Math.toIntExact((long) ((ASTValueNode) node.jjtGetChild(0)).jjtGetValue());
query.setTop(top);
break;
- }
- case OP_SKIP: {
+
+ case OP_SKIP:
query.setSkip(Math.toIntExact((long) ((ASTValueNode) node.jjtGetChild(0)).jjtGetValue()));
break;
- }
- case OP_COUNT: {
+
+ case OP_COUNT:
query.setCount(((ASTBool) node.jjtGetChild(0)).getValue());
break;
- }
- case OP_SELECT: {
+
+ case OP_SELECT:
if (node.jjtGetNumChildren() != 1 || !(node.jjtGetChild(0) instanceof ASTIdentifiers)) {
throw new IllegalArgumentException("ASTOption(select) must have exactly one child node of type ASTIdentifiers");
}
query.setSelect(visit((ASTIdentifiers) node.jjtGetChild(0), data));
break;
- }
- case OP_EXPAND: {
+
+ case OP_EXPAND:
if (node.jjtGetNumChildren() != 1 || !(node.jjtGetChild(0) instanceof ASTFilteredPaths)) {
throw new IllegalArgumentException("ASTOption(expand) must have exactly one child node of type ASTFilteredPaths");
}
query.setExpand(visit(((ASTFilteredPaths) node.jjtGetChild(0)), data));
break;
- }
- case OP_FILTER: {
+
+ case OP_FILTER:
if (node.jjtGetNumChildren() != 1) {
throw new IllegalArgumentException("ASTOption(filter) must have exactly one child node");
}
query.setFilter(ExpressionParser.parseExpression(node.jjtGetChild(0)));
break;
- }
- case OP_FORMAT: {
+
+ case OP_FORMAT:
query.setFormat(((ASTFormat) node.jjtGetChild(0)).getValue());
break;
- }
- case OP_ORDER_BY: {
+
+ case OP_ORDER_BY:
if (node.jjtGetNumChildren() != 1 || !(node.jjtGetChild(0) instanceof ASTOrderBys)) {
throw new IllegalArgumentException("ASTOption(orderby) must have exactly one child node of type ASTOrderBys");
}
query.setOrderBy(visit((ASTOrderBys) node.jjtGetChild(0), data));
break;
- }
default:
// ignore or throw exception?
@@ -206,7 +206,7 @@ public Property visit(ASTPathElement node, Object data) {
throw new IllegalArgumentException("no identified paths are allowed inside select");
}
Property previous = null;
- if (data != null && data instanceof Property) {
+ if (data instanceof Property) {
previous = (Property) data;
}
return ParserHelper.parseProperty(node.getName(), previous);
@@ -228,6 +228,6 @@ public OrderBy visit(ASTOrderBy node, Object data) {
}
return new OrderBy(
ExpressionParser.parseExpression(node.jjtGetChild(0)),
- node.isAscending() ? OrderBy.OrderType.Ascending : OrderBy.OrderType.Descending);
+ node.isAscending() ? OrderBy.OrderType.ASCENDING : OrderBy.OrderType.DESCENDING);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomProperty.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomProperty.java
index 56a47d318..627820e04 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomProperty.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomProperty.java
@@ -24,6 +24,7 @@
*/
public class CustomProperty implements Property {
+ private static final String UNSUPPORTED = "Not supported on custom properties.";
/**
* The name of this property as used in URLs.
*/
@@ -58,18 +59,28 @@ public String getName() {
return name;
}
+ @Override
+ public String getJsonName() {
+ return name;
+ }
+
public Integer getIndex() {
return index;
}
@Override
public String getGetterName() {
- throw new UnsupportedOperationException("Not supported on custom properties.");
+ throw new UnsupportedOperationException(UNSUPPORTED);
}
@Override
public String getSetterName() {
- throw new UnsupportedOperationException("Not supported on custom properties.");
+ throw new UnsupportedOperationException(UNSUPPORTED);
+ }
+
+ @Override
+ public String getIsSetName() {
+ throw new UnsupportedOperationException(UNSUPPORTED);
}
@Override
@@ -83,10 +94,7 @@ public String toString() {
@Override
public int hashCode() {
- int hash = 5;
- hash = 17 * hash + Objects.hashCode(this.name);
- hash = 17 * hash + Objects.hashCode(this.index);
- return hash;
+ return Objects.hash(name, index);
}
@Override
@@ -101,10 +109,8 @@ public boolean equals(Object obj) {
return false;
}
final CustomProperty other = (CustomProperty) obj;
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- return Objects.equals(this.index, other.index);
+ return Objects.equals(this.name, other.name)
+ && Objects.equals(this.index, other.index);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyArrayIndex.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyArrayIndex.java
index e83d12c4b..10d3eabc2 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyArrayIndex.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyArrayIndex.java
@@ -65,10 +65,7 @@ public String toString() {
@Override
public int hashCode() {
- int hash = 3;
- hash = 31 * hash + Objects.hashCode(this.index);
- hash = 31 * hash + Objects.hashCode(this.parent);
- return hash;
+ return Objects.hash(index, parent);
}
@Override
@@ -80,10 +77,8 @@ public boolean equals(Object obj) {
return false;
}
final CustomPropertyArrayIndex other = (CustomPropertyArrayIndex) obj;
- if (!Objects.equals(this.index, other.index)) {
- return false;
- }
- return Objects.equals(this.parent, other.parent);
+ return Objects.equals(this.index, other.index)
+ && Objects.equals(this.parent, other.parent);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyPathElement.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyPathElement.java
index cd1059800..ff56b75ef 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyPathElement.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/CustomPropertyPathElement.java
@@ -65,10 +65,7 @@ public String toString() {
@Override
public int hashCode() {
- int hash = 3;
- hash = 31 * hash + Objects.hashCode(this.name);
- hash = 31 * hash + Objects.hashCode(this.parent);
- return hash;
+ return Objects.hash(name, parent);
}
@Override
@@ -80,13 +77,8 @@ public boolean equals(Object obj) {
return false;
}
final CustomPropertyPathElement other = (CustomPropertyPathElement) obj;
- if (!Objects.equals(this.name, other.name)) {
- return false;
- }
- if (!Objects.equals(this.parent, other.parent)) {
- return false;
- }
- return true;
+ return Objects.equals(this.name, other.name)
+ && Objects.equals(this.parent, other.parent);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityPathElement.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityPathElement.java
index 21addf92d..274526e77 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityPathElement.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityPathElement.java
@@ -17,7 +17,7 @@
*/
package de.fraunhofer.iosb.ilt.sta.path;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import java.util.Objects;
/**
@@ -71,16 +71,12 @@ public void visit(ResourcePathVisitor visitor) {
@Override
public String toString() {
- return entityType.name;
+ return entityType.entityName;
}
@Override
public int hashCode() {
- int hash = 7;
- hash = 11 * hash + Objects.hashCode(this.id);
- hash = 11 * hash + Objects.hashCode(this.entityType);
- hash = 11 * hash + Objects.hashCode(this.parent);
- return hash;
+ return Objects.hash(id, entityType, parent);
}
@Override
@@ -92,16 +88,9 @@ public boolean equals(Object obj) {
return false;
}
final EntityPathElement other = (EntityPathElement) obj;
- if (!Objects.equals(this.id, other.id)) {
- return false;
- }
- if (this.entityType != other.entityType) {
- return false;
- }
- if (!Objects.equals(this.parent, other.parent)) {
- return false;
- }
- return true;
+ return Objects.equals(this.id, other.id)
+ && this.entityType == other.entityType
+ && Objects.equals(this.parent, other.parent);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityProperty.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityProperty.java
index fc3986e1e..07b92f879 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityProperty.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityProperty.java
@@ -17,6 +17,7 @@
*/
package de.fraunhofer.iosb.ilt.sta.path;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -27,58 +28,66 @@
*/
public enum EntityProperty implements Property {
- Description,
- Definition,
- EncodingType,
- Feature(true),
- Id("id", "@iot.id"),
- Location(true),
- Metadata,
- MultiObservationDataTypes,
- Name,
- ObservationType,
- ObservedArea,
- PhenomenonTime,
- Parameters(true),
- Properties(true),
- Result(true),
- ResultTime,
- ResultQuality,
- SelfLink("@iot.selfLink", "@iot.selfLink"),
- Time,
- UnitOfMeasurement(true),
- UnitOfMeasurements(true),
- ValidTime;
+ DESCRIPTION("Description"),
+ DEFINITION("Definition"),
+ ENCODINGTYPE("EncodingType"),
+ FEATURE("Feature", true),
+ ID("Id", "id", "@iot.id"),
+ LOCATION("Location", true),
+ METADATA("Metadata"),
+ MULTIOBSERVATIONDATATYPES("MultiObservationDataTypes"),
+ NAME("Name"),
+ OBSERVATIONTYPE("ObservationType"),
+ OBSERVEDAREA("ObservedArea"),
+ PHENOMENONTIME("PhenomenonTime"),
+ PARAMETERS("Parameters", true),
+ PROPERTIES("Properties", true),
+ RESULT("Result", true),
+ RESULTTIME("ResultTime"),
+ RESULTQUALITY("ResultQuality"),
+ SELFLINK("SelfLink", "@iot.selfLink", "@iot.selfLink"),
+ TIME("Time"),
+ UNITOFMEASUREMENT("UnitOfMeasurement", true),
+ UNITOFMEASUREMENTS("UnitOfMeasurements", true),
+ VALIDTIME("ValidTime");
/**
- * The name of this property as used in URLs.
+ * The entitiyName of this property as used in URLs.
*/
- public final String name;
+ public final String entitiyName;
+ public final String jsonName;
public final String getterName;
public final String setterName;
+ public final String isSetName;
public final boolean hasCustomProperties;
private final Collection aliases;
- private EntityProperty() {
- this(false);
+ private EntityProperty(String codeName) {
+ this(codeName, false);
}
- private EntityProperty(boolean hasCustomProperties) {
+ private EntityProperty(String codeName, boolean hasCustomProperties) {
this.aliases = new ArrayList<>();
- this.aliases.add(name());
- this.name = name().substring(0, 1).toLowerCase() + name().substring(1);
- this.getterName = "get" + name();
- this.setterName = "set" + name();
+ this.aliases.add(codeName);
+ this.entitiyName = StringHelper.deCapitalize(codeName);
+ this.jsonName = entitiyName;
+ this.getterName = "get" + codeName;
+ this.setterName = "set" + codeName;
+ this.isSetName = "isSet" + codeName;
this.hasCustomProperties = hasCustomProperties;
}
- private EntityProperty(String name, String... aliases) {
+ private EntityProperty(String codeName, String pathName, String jsonName, String... aliases) {
this.aliases = new ArrayList<>();
+ this.entitiyName = pathName;
+ this.jsonName = jsonName;
this.aliases.add(name());
- this.name = name;
+ this.aliases.add(jsonName);
this.aliases.addAll(Arrays.asList(aliases));
- this.getterName = "get" + name();
- this.setterName = "set" + name();
+ String capitalized = StringHelper.capitalize(codeName);
+ this.getterName = "get" + capitalized;
+ this.setterName = "set" + capitalized;
+ this.isSetName = "isSet" + capitalized;
this.hasCustomProperties = false;
}
@@ -95,7 +104,12 @@ public static EntityProperty fromString(String propertyName) {
@Override
public String getName() {
- return name;
+ return entitiyName;
+ }
+
+ @Override
+ public String getJsonName() {
+ return jsonName;
}
@Override
@@ -108,4 +122,9 @@ public String getSetterName() {
return setterName;
}
+ @Override
+ public String getIsSetName() {
+ return isSetName;
+ }
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntitySetPathElement.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntitySetPathElement.java
index 72fc89064..1f05cca7a 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntitySetPathElement.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntitySetPathElement.java
@@ -65,10 +65,7 @@ public String toString() {
@Override
public int hashCode() {
- int hash = 3;
- hash = 53 * hash + Objects.hashCode(this.entityType);
- hash = 53 * hash + Objects.hashCode(this.parent);
- return hash;
+ return Objects.hash(entityType, parent);
}
@Override
@@ -80,13 +77,8 @@ public boolean equals(Object obj) {
return false;
}
final EntitySetPathElement other = (EntitySetPathElement) obj;
- if (this.entityType != other.entityType) {
- return false;
- }
- if (!Objects.equals(this.parent, other.parent)) {
- return false;
- }
- return true;
+ return this.entityType == other.entityType
+ && Objects.equals(this.parent, other.parent);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityType.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityType.java
index ea77eca5a..528efeba9 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityType.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/EntityType.java
@@ -27,7 +27,9 @@
import de.fraunhofer.iosb.ilt.sta.model.Sensor;
import de.fraunhofer.iosb.ilt.sta.model.Thing;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -37,15 +39,15 @@
*/
public enum EntityType {
- Datastream("Datastreams", Datastream.class),
- MultiDatastream("MultiDatastreams", MultiDatastream.class),
- FeatureOfInterest("FeaturesOfInterest", FeatureOfInterest.class),
- HistoricalLocation("HistoricalLocations", HistoricalLocation.class),
- Location("Locations", Location.class),
- Observation("Observations", Observation.class),
- ObservedProperty("ObservedProperties", ObservedProperty.class),
- Sensor("Sensors", Sensor.class),
- Thing("Things", Thing.class);
+ DATASTREAM("Datastream", "Datastreams", Datastream.class),
+ MULTIDATASTREAM("MultiDatastream", "MultiDatastreams", MultiDatastream.class),
+ FEATUREOFINTEREST("FeatureOfInterest", "FeaturesOfInterest", FeatureOfInterest.class),
+ HISTORICALLOCATION("HistoricalLocation", "HistoricalLocations", HistoricalLocation.class),
+ LOCATION("Location", "Locations", Location.class),
+ OBSERVATION("Observation", "Observations", Observation.class),
+ OBSERVEDPROPERTY("ObservedProperty", "ObservedProperties", ObservedProperty.class),
+ SENSOR("Sensor", "Sensors", Sensor.class),
+ THING("Thing", "Things", Thing.class);
public static class PropertyEntry {
@@ -62,141 +64,169 @@ public PropertyEntry(Property property, boolean required) {
}
/**
- * The name of this entity type as used in URLs.
+ * The entitiyName of this entity type as used in URLs.
*/
- public final String name;
+ public final String entityName;
/**
- * The name of collections of this entity type as used in URLs.
+ * The entitiyName of collections of this entity type as used in URLs.
*/
public final String plural;
/**
- * The Set of Properties that Entities of this type have.
+ * The writable version of the properties map, for internal use only.
*/
- private final Map propertyMap = new HashMap<>();
+ private final Map propertyMapRw = new HashMap<>();
+ /**
+ * The Set of PROPERTIES that Entities of this type have, mapped to the flag
+ * indicating if they are required.
+ */
+ private final Map propertyMap = Collections.unmodifiableMap(propertyMapRw);
+ /**
+ * The set of Navigation properties pointing to single entities.
+ */
+ private final Set navigationEntities = new HashSet<>();
+ /**
+ * The set of Navigation properties pointing to entity sets.
+ */
+ private final Set navigationSets = new HashSet<>();
+
private final Class extends Entity> implementingClass;
private static void init() {
- Map propertySet;
- propertySet = Datastream.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Name, true);
- propertySet.put(EntityProperty.Description, true);
- propertySet.put(EntityProperty.ObservationType, true);
- propertySet.put(EntityProperty.UnitOfMeasurement, true);
- propertySet.put(EntityProperty.ObservedArea, false);
- propertySet.put(EntityProperty.PhenomenonTime, false);
- propertySet.put(EntityProperty.Properties, false);
- propertySet.put(EntityProperty.ResultTime, false);
- propertySet.put(NavigationProperty.ObservedProperty, true);
- propertySet.put(NavigationProperty.Sensor, true);
- propertySet.put(NavigationProperty.Thing, true);
- propertySet.put(NavigationProperty.Observations, false);
-
- propertySet = MultiDatastream.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Name, true);
- propertySet.put(EntityProperty.Description, true);
- propertySet.put(EntityProperty.ObservationType, true);
- propertySet.put(EntityProperty.MultiObservationDataTypes, true);
- propertySet.put(EntityProperty.UnitOfMeasurements, true);
- propertySet.put(EntityProperty.ObservedArea, false);
- propertySet.put(EntityProperty.PhenomenonTime, false);
- propertySet.put(EntityProperty.Properties, false);
- propertySet.put(EntityProperty.ResultTime, false);
- propertySet.put(NavigationProperty.ObservedProperties, true);
- propertySet.put(NavigationProperty.Sensor, true);
- propertySet.put(NavigationProperty.Thing, true);
- propertySet.put(NavigationProperty.Observations, false);
-
- propertySet = FeatureOfInterest.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Name, true);
- propertySet.put(EntityProperty.Description, true);
- propertySet.put(EntityProperty.EncodingType, true);
- propertySet.put(EntityProperty.Feature, true);
- propertySet.put(EntityProperty.Properties, false);
- propertySet.put(NavigationProperty.Observations, false);
-
- propertySet = HistoricalLocation.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Time, true);
- propertySet.put(NavigationProperty.Thing, true);
- propertySet.put(NavigationProperty.Locations, false);
-
- propertySet = Location.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Name, true);
- propertySet.put(EntityProperty.Description, true);
- propertySet.put(EntityProperty.EncodingType, true);
- propertySet.put(EntityProperty.Location, true);
- propertySet.put(EntityProperty.Properties, false);
- propertySet.put(NavigationProperty.HistoricalLocations, false);
- propertySet.put(NavigationProperty.Things, false);
-
- propertySet = Observation.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.PhenomenonTime, false);
- propertySet.put(EntityProperty.ResultTime, false);
- propertySet.put(EntityProperty.Result, true);
- propertySet.put(EntityProperty.ResultQuality, false);
- propertySet.put(EntityProperty.ValidTime, false);
- propertySet.put(EntityProperty.Parameters, false);
+ Map propertyMap;
+ propertyMap = DATASTREAM.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.NAME, true);
+ propertyMap.put(EntityProperty.DESCRIPTION, true);
+ propertyMap.put(EntityProperty.OBSERVATIONTYPE, true);
+ propertyMap.put(EntityProperty.UNITOFMEASUREMENT, true);
+ propertyMap.put(EntityProperty.OBSERVEDAREA, false);
+ propertyMap.put(EntityProperty.PHENOMENONTIME, false);
+ propertyMap.put(EntityProperty.PROPERTIES, false);
+ propertyMap.put(EntityProperty.RESULTTIME, false);
+ propertyMap.put(NavigationProperty.OBSERVEDPROPERTY, true);
+ propertyMap.put(NavigationProperty.SENSOR, true);
+ propertyMap.put(NavigationProperty.THING, true);
+ propertyMap.put(NavigationProperty.OBSERVATIONS, false);
+
+ propertyMap = MULTIDATASTREAM.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.NAME, true);
+ propertyMap.put(EntityProperty.DESCRIPTION, true);
+ // OBSERVATIONTYPE is required, but must always be the same, thus we set it ourselves.
+ propertyMap.put(EntityProperty.OBSERVATIONTYPE, false);
+ propertyMap.put(EntityProperty.MULTIOBSERVATIONDATATYPES, true);
+ propertyMap.put(EntityProperty.UNITOFMEASUREMENTS, true);
+ propertyMap.put(EntityProperty.OBSERVEDAREA, false);
+ propertyMap.put(EntityProperty.PHENOMENONTIME, false);
+ propertyMap.put(EntityProperty.PROPERTIES, false);
+ propertyMap.put(EntityProperty.RESULTTIME, false);
+ propertyMap.put(NavigationProperty.OBSERVEDPROPERTIES, true);
+ propertyMap.put(NavigationProperty.SENSOR, true);
+ propertyMap.put(NavigationProperty.THING, true);
+ propertyMap.put(NavigationProperty.OBSERVATIONS, false);
+
+ propertyMap = FEATUREOFINTEREST.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.NAME, true);
+ propertyMap.put(EntityProperty.DESCRIPTION, true);
+ propertyMap.put(EntityProperty.ENCODINGTYPE, true);
+ propertyMap.put(EntityProperty.FEATURE, true);
+ propertyMap.put(EntityProperty.PROPERTIES, false);
+ propertyMap.put(NavigationProperty.OBSERVATIONS, false);
+
+ propertyMap = HISTORICALLOCATION.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.TIME, true);
+ propertyMap.put(NavigationProperty.THING, true);
+ propertyMap.put(NavigationProperty.LOCATIONS, false);
+
+ propertyMap = LOCATION.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.NAME, true);
+ propertyMap.put(EntityProperty.DESCRIPTION, true);
+ propertyMap.put(EntityProperty.ENCODINGTYPE, true);
+ propertyMap.put(EntityProperty.LOCATION, true);
+ propertyMap.put(EntityProperty.PROPERTIES, false);
+ propertyMap.put(NavigationProperty.HISTORICALLOCATIONS, false);
+ propertyMap.put(NavigationProperty.THINGS, false);
+
+ propertyMap = OBSERVATION.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.PHENOMENONTIME, false);
+ propertyMap.put(EntityProperty.RESULTTIME, false);
+ propertyMap.put(EntityProperty.RESULT, true);
+ propertyMap.put(EntityProperty.RESULTQUALITY, false);
+ propertyMap.put(EntityProperty.VALIDTIME, false);
+ propertyMap.put(EntityProperty.PARAMETERS, false);
// One of the following two is mandatory.
- propertySet.put(NavigationProperty.Datastream, false);
- propertySet.put(NavigationProperty.MultiDatastream, false);
- // FeatureOfInterest must be generated on the fly if not present.
- propertySet.put(NavigationProperty.FeatureOfInterest, false);
-
- propertySet = ObservedProperty.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Name, true);
- propertySet.put(EntityProperty.Definition, true);
- propertySet.put(EntityProperty.Description, true);
- propertySet.put(EntityProperty.Properties, false);
- propertySet.put(NavigationProperty.Datastreams, false);
- propertySet.put(NavigationProperty.MultiDatastreams, false);
-
- propertySet = Sensor.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Name, true);
- propertySet.put(EntityProperty.Description, true);
- propertySet.put(EntityProperty.EncodingType, true);
- propertySet.put(EntityProperty.Metadata, true);
- propertySet.put(EntityProperty.Properties, false);
- propertySet.put(NavigationProperty.Datastreams, false);
- propertySet.put(NavigationProperty.MultiDatastreams, false);
-
- propertySet = Thing.propertyMap;
- propertySet.put(EntityProperty.Id, false);
- propertySet.put(EntityProperty.SelfLink, false);
- propertySet.put(EntityProperty.Name, true);
- propertySet.put(EntityProperty.Description, true);
- propertySet.put(EntityProperty.Properties, false);
- propertySet.put(NavigationProperty.Locations, false);
- propertySet.put(NavigationProperty.HistoricalLocations, false);
- propertySet.put(NavigationProperty.Datastreams, false);
- propertySet.put(NavigationProperty.MultiDatastreams, false);
+ propertyMap.put(NavigationProperty.DATASTREAM, false);
+ propertyMap.put(NavigationProperty.MULTIDATASTREAM, false);
+ // FEATUREOFINTEREST must be generated on the fly if not present.
+ propertyMap.put(NavigationProperty.FEATUREOFINTEREST, false);
+
+ propertyMap = OBSERVEDPROPERTY.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.NAME, true);
+ propertyMap.put(EntityProperty.DEFINITION, true);
+ propertyMap.put(EntityProperty.DESCRIPTION, true);
+ propertyMap.put(EntityProperty.PROPERTIES, false);
+ propertyMap.put(NavigationProperty.DATASTREAMS, false);
+ propertyMap.put(NavigationProperty.MULTIDATASTREAMS, false);
+
+ propertyMap = SENSOR.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.NAME, true);
+ propertyMap.put(EntityProperty.DESCRIPTION, true);
+ propertyMap.put(EntityProperty.ENCODINGTYPE, true);
+ propertyMap.put(EntityProperty.METADATA, true);
+ propertyMap.put(EntityProperty.PROPERTIES, false);
+ propertyMap.put(NavigationProperty.DATASTREAMS, false);
+ propertyMap.put(NavigationProperty.MULTIDATASTREAMS, false);
+
+ propertyMap = THING.propertyMapRw;
+ propertyMap.put(EntityProperty.ID, false);
+ propertyMap.put(EntityProperty.SELFLINK, false);
+ propertyMap.put(EntityProperty.NAME, true);
+ propertyMap.put(EntityProperty.DESCRIPTION, true);
+ propertyMap.put(EntityProperty.PROPERTIES, false);
+ propertyMap.put(NavigationProperty.LOCATIONS, false);
+ propertyMap.put(NavigationProperty.HISTORICALLOCATIONS, false);
+ propertyMap.put(NavigationProperty.DATASTREAMS, false);
+ propertyMap.put(NavigationProperty.MULTIDATASTREAMS, false);
+
+ for (EntityType type : EntityType.values()) {
+ for (Property property : type.getPropertySet()) {
+ if (property instanceof NavigationProperty) {
+ NavigationProperty navigationProperty = (NavigationProperty) property;
+ if (navigationProperty.isSet) {
+ type.getNavigationSets().add(navigationProperty);
+ } else {
+ type.getNavigationEntities().add(navigationProperty);
+ }
+ }
+ }
+ }
}
- private EntityType(String plural, Class extends Entity> implementingClass) {
- this.name = name();
+ private EntityType(String singular, String plural, Class extends Entity> implementingClass) {
+ this.entityName = singular;
this.plural = plural;
this.implementingClass = implementingClass;
}
/**
- * The Map of Properties that Entities of this type have, with their
+ * The Map of PROPERTIES that Entities of this type have, with their
* required status.
*
- * @return The Set of Properties that Entities of this type have.
+ * @return The Set of PROPERTIES that Entities of this type have.
*/
public Map getPropertyMap() {
if (propertyMap.isEmpty()) {
@@ -206,9 +236,9 @@ public Map getPropertyMap() {
}
/**
- * The Set of Properties that Entities of this type have.
+ * The Set of PROPERTIES that Entities of this type have.
*
- * @return The Set of Properties that Entities of this type have.
+ * @return The Set of PROPERTIES that Entities of this type have.
*/
public Set getPropertySet() {
if (propertyMap.isEmpty()) {
@@ -217,6 +247,20 @@ public Set getPropertySet() {
return propertyMap.keySet();
}
+ public Set getNavigationEntities() {
+ if (propertyMap.isEmpty()) {
+ init();
+ }
+ return navigationEntities;
+ }
+
+ public Set getNavigationSets() {
+ if (propertyMap.isEmpty()) {
+ init();
+ }
+ return navigationSets;
+ }
+
/**
* @param property The property to check the required state for.
* @return True when the property is required, false otherwise.
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/NavigationProperty.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/NavigationProperty.java
index 252a3cc4b..0453f3900 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/NavigationProperty.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/NavigationProperty.java
@@ -17,8 +17,8 @@
*/
package de.fraunhofer.iosb.ilt.sta.path;
+import de.fraunhofer.iosb.ilt.sta.util.StringHelper;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
/**
@@ -27,42 +27,42 @@
*/
public enum NavigationProperty implements Property {
- Datastream(EntityType.Datastream, false),
- Datastreams(EntityType.Datastream, true),
- MultiDatastream(EntityType.MultiDatastream, false),
- MultiDatastreams(EntityType.MultiDatastream, true),
- FeatureOfInterest(EntityType.FeatureOfInterest, false),
- HistoricalLocations(EntityType.HistoricalLocation, true),
- Location(EntityType.Location, false),
- Locations(EntityType.Location, true),
- Observations(EntityType.Observation, true),
- ObservedProperty(EntityType.ObservedProperty, false),
- ObservedProperties(EntityType.ObservedProperty, true),
- Sensor(EntityType.Sensor, false),
- Thing(EntityType.Thing, false),
- Things(EntityType.Thing, true);
+ DATASTREAM("Datastream", EntityType.DATASTREAM, false),
+ DATASTREAMS("Datastreams", EntityType.DATASTREAM, true),
+ MULTIDATASTREAM("MultiDatastream", EntityType.MULTIDATASTREAM, false),
+ MULTIDATASTREAMS("MultiDatastreams", EntityType.MULTIDATASTREAM, true),
+ FEATUREOFINTEREST("FeatureOfInterest", EntityType.FEATUREOFINTEREST, false),
+ HISTORICALLOCATIONS("HistoricalLocations", EntityType.HISTORICALLOCATION, true),
+ LOCATION("Location", EntityType.LOCATION, false),
+ LOCATIONS("Locations", EntityType.LOCATION, true),
+ OBSERVATIONS("Observations", EntityType.OBSERVATION, true),
+ OBSERVEDPROPERTY("ObservedProperty", EntityType.OBSERVEDPROPERTY, false),
+ OBSERVEDPROPERTIES("ObservedProperties", EntityType.OBSERVEDPROPERTY, true),
+ SENSOR("Sensor", EntityType.SENSOR, false),
+ THING("Thing", EntityType.THING, false),
+ THINGS("Things", EntityType.THING, true);
private final Collection aliases;
/**
* The type of entity that this navigation property points to.
*/
public final EntityType type;
+ public final String propertyName;
public final String getterName;
public final String setterName;
+ public final String isSetName;
public final boolean isSet;
- private NavigationProperty(EntityType type, boolean isSet) {
+ private NavigationProperty(String propertyName, EntityType type, boolean isSet) {
+ this.propertyName = propertyName;
this.aliases = new ArrayList<>();
- this.aliases.add(toString());
+ this.aliases.add(propertyName);
this.type = type;
this.isSet = isSet;
- this.getterName = "get" + name();
- this.setterName = "set" + name();
- }
-
- private NavigationProperty(EntityType type, boolean isSet, String... aliases) {
- this(type, isSet);
- this.aliases.addAll(Arrays.asList(aliases));
+ String capitalized = StringHelper.capitalize(propertyName);
+ this.getterName = "get" + capitalized;
+ this.setterName = "set" + capitalized;
+ this.isSetName = "isSet" + capitalized;
}
public static NavigationProperty fromString(String propertyName) {
@@ -82,7 +82,12 @@ public EntityType getType() {
@Override
public String getName() {
- return name();
+ return propertyName;
+ }
+
+ @Override
+ public String getJsonName() {
+ return propertyName;
}
@Override
@@ -95,4 +100,9 @@ public String getSetterName() {
return setterName;
}
+ @Override
+ public String getIsSetName() {
+ return isSetName;
+ }
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/Property.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/Property.java
index e0f33f12d..edcd77306 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/Property.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/Property.java
@@ -28,6 +28,11 @@ public interface Property {
*/
public String getName();
+ /**
+ * @return The name of this property as used in JSON.
+ */
+ public String getJsonName();
+
/**
* @return The name of the getter method for this property.
*/
@@ -37,4 +42,9 @@ public interface Property {
* @return The name of the setter method for this property.
*/
public String getSetterName();
+
+ /**
+ * @return The name of the method to check if this property is set.
+ */
+ public String getIsSetName();
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/PropertyPathElement.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/PropertyPathElement.java
index e09bd1874..b50820cb6 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/PropertyPathElement.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/PropertyPathElement.java
@@ -60,15 +60,12 @@ public void visit(ResourcePathVisitor visitor) {
@Override
public String toString() {
- return property.name;
+ return property.entitiyName;
}
@Override
public int hashCode() {
- int hash = 3;
- hash = 61 * hash + Objects.hashCode(this.property);
- hash = 61 * hash + Objects.hashCode(this.parent);
- return hash;
+ return Objects.hash(property, parent);
}
@Override
@@ -80,13 +77,8 @@ public boolean equals(Object obj) {
return false;
}
final PropertyPathElement other = (PropertyPathElement) obj;
- if (this.property != other.property) {
- return false;
- }
- if (!Objects.equals(this.parent, other.parent)) {
- return false;
- }
- return true;
+ return this.property == other.property
+ && Objects.equals(this.parent, other.parent);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/ResourcePath.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/ResourcePath.java
index c2d8e0cc0..af42270c7 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/ResourcePath.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/path/ResourcePath.java
@@ -43,6 +43,11 @@ public class ResourcePath {
* Flag indicating there was a $value at the end of the path.
*/
private boolean value;
+ /**
+ * Flag indicating the path points to an entityProperty
+ * (EntitySet(id)/entityProperty).
+ */
+ private boolean entityProperty;
/**
* The elements in this path.
*/
@@ -67,22 +72,92 @@ public ResourcePath(String serviceRootUrl, String pathUrl) {
this.pathUrl = pathUrl;
}
+ /**
+ * Flag indicating there was a $ref at the end of the path.
+ *
+ * @return the ref
+ */
public boolean isRef() {
return ref;
}
+ /**
+ * Flag indicating there was a $ref at the end of the path.
+ *
+ * @param ref the ref to set
+ */
+ public void setRef(boolean ref) {
+ this.ref = ref;
+ }
+
+ /**
+ * Flag indicating there was a $value at the end of the path.
+ *
+ * @return the value
+ */
public boolean isValue() {
return value;
}
- public List getPathElements() {
- return pathElements;
+ /**
+ * Flag indicating there was a $value at the end of the path.
+ *
+ * @param value the value to set
+ */
+ public void setValue(boolean value) {
+ this.value = value;
+ }
+
+ /**
+ * Flag indicating the path points to an entityProperty
+ * (EntitySet(id)/entityProperty).
+ *
+ * @return the entityProperty
+ */
+ public boolean isEntityProperty() {
+ return entityProperty;
+ }
+
+ /**
+ * Returns the number of elements in the path.
+ *
+ * @return The size of the path.
+ */
+ public int size() {
+ return pathElements.size();
+ }
+
+ public boolean isEmpty() {
+ return pathElements.isEmpty();
+ }
+
+ /**
+ * Get the element with the given index, where the first element has index
+ * 0.
+ *
+ * @param index The index of the element to get.
+ * @return The element with the given index.
+ */
+ public ResourcePathElement get(int index) {
+ return pathElements.get(index);
}
public ResourcePathElement getMainElement() {
return mainElement;
}
+ public EntityType getMainElementType() {
+ if (mainElement instanceof EntityPathElement) {
+ EntityPathElement entityPathElement = (EntityPathElement) mainElement;
+ return entityPathElement.getEntityType();
+ }
+ if (mainElement instanceof EntitySetPathElement) {
+ EntitySetPathElement entitySetPathElement = (EntitySetPathElement) mainElement;
+ return entitySetPathElement.getEntityType();
+ }
+ return null;
+ }
+
public ResourcePathElement getLastElement() {
if (pathElements.isEmpty()) {
return null;
@@ -94,18 +169,6 @@ public EntityPathElement getIdentifiedElement() {
return identifiedElement;
}
- public void setRef(boolean ref) {
- this.ref = ref;
- }
-
- public void setValue(boolean value) {
- this.value = value;
- }
-
- public void setPathElements(List pathElements) {
- this.pathElements = pathElements;
- }
-
public void setMainElement(ResourcePathElement mainElementType) {
this.mainElement = mainElementType;
}
@@ -114,16 +177,38 @@ public void setIdentifiedElement(EntityPathElement identifiedElement) {
this.identifiedElement = identifiedElement;
}
+ /**
+ * Add the given element at the given index.
+ *
+ * @param index The position in the path to put the element.
+ * @param pe The element to add.
+ */
+ public void addPathElement(int index, ResourcePathElement pe) {
+ pathElements.add(index, pe);
+ }
+
+ public void addPathElement(ResourcePathElement pe) {
+ addPathElement(pe, false, false);
+ }
+
+ /**
+ * Add the given path element, optionally setting it as the main element, or
+ * as the identifying element.
+ *
+ * @param pe The element to add.
+ * @param isMain Flag indicating it is the main element.
+ * @param isIdentifier Flag indicating it is the identifying element.
+ */
public void addPathElement(ResourcePathElement pe, boolean isMain, boolean isIdentifier) {
- getPathElements().add(pe);
- if (isMain && pe instanceof EntityPathElement) {
- EntityPathElement epe = (EntityPathElement) pe;
- setMainElement(epe);
+ pathElements.add(pe);
+ if (isMain && pe instanceof EntityPathElement || pe instanceof EntitySetPathElement) {
+ setMainElement(pe);
}
if (isIdentifier && pe instanceof EntityPathElement) {
EntityPathElement epe = (EntityPathElement) pe;
setIdentifiedElement(epe);
}
+ this.entityProperty = (pe instanceof PropertyPathElement);
}
public void compress() {
@@ -160,14 +245,7 @@ public void setPathUrl(String pathUrl) {
@Override
public int hashCode() {
- int hash = 7;
- hash = 97 * hash + Objects.hashCode(this.serviceRootUrl);
- hash = 97 * hash + (this.ref ? 1 : 0);
- hash = 97 * hash + (this.value ? 1 : 0);
- hash = 97 * hash + Objects.hashCode(this.pathElements);
- hash = 97 * hash + Objects.hashCode(this.mainElement);
- hash = 97 * hash + Objects.hashCode(this.identifiedElement);
- return hash;
+ return Objects.hash(serviceRootUrl, ref, value, pathElements, mainElement, identifiedElement);
}
@Override
@@ -179,25 +257,12 @@ public boolean equals(Object obj) {
return false;
}
final ResourcePath other = (ResourcePath) obj;
- if (!Objects.equals(this.serviceRootUrl, other.serviceRootUrl)) {
- return false;
- }
- if (this.ref != other.ref) {
- return false;
- }
- if (this.value != other.value) {
- return false;
- }
- if (!Objects.equals(this.pathElements, other.pathElements)) {
- return false;
- }
- if (!Objects.equals(this.mainElement, other.mainElement)) {
- return false;
- }
- if (!Objects.equals(this.identifiedElement, other.identifiedElement)) {
- return false;
- }
- return true;
+ return Objects.equals(this.serviceRootUrl, other.serviceRootUrl)
+ && this.ref == other.ref
+ && this.value == other.value
+ && Objects.equals(this.pathElements, other.pathElements)
+ && Objects.equals(this.mainElement, other.mainElement)
+ && Objects.equals(this.identifiedElement, other.identifiedElement);
}
@Override
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/AbstractPersistenceManager.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/AbstractPersistenceManager.java
index d233e49ba..59442839e 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/AbstractPersistenceManager.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/AbstractPersistenceManager.java
@@ -1,30 +1,37 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.persistence;
+import de.fraunhofer.iosb.ilt.sta.messagebus.EntityChangedMessage;
+import de.fraunhofer.iosb.ilt.sta.messagebus.MessageBus;
+import de.fraunhofer.iosb.ilt.sta.messagebus.MessageBusFactory;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
+import de.fraunhofer.iosb.ilt.sta.path.EntityType;
+import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
+import de.fraunhofer.iosb.ilt.sta.query.Query;
import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
import de.fraunhofer.iosb.ilt.sta.util.NoSuchEntityException;
import java.util.ArrayList;
import java.util.List;
-import javax.swing.event.EventListenerList;
/**
*
@@ -32,59 +39,39 @@
*/
public abstract class AbstractPersistenceManager implements PersistenceManager {
- protected EventListenerList entityChangeListeners = new EventListenerList();
- private final List insertedEntities;
- private final List deletedEntities;
- private final List updatedEntities;
+ /**
+ * The changed entity messages that need to be sent to the bus.
+ */
+ private final List changedEntities;
protected AbstractPersistenceManager() {
- this.insertedEntities = new ArrayList<>();
- this.deletedEntities = new ArrayList<>();
- this.updatedEntities = new ArrayList<>();
+ this.changedEntities = new ArrayList<>();
}
- @Override
- public void addEntityChangeListener(EntityChangeListener listener) {
- entityChangeListeners.add(EntityChangeListener.class, listener);
- }
-
- @Override
- public void removeEntityChangeListener(EntityChangeListener listener) {
- entityChangeListeners.remove(EntityChangeListener.class, listener);
- }
-
- protected void fireEntityInserted(Entity e) {
- Object[] listeners = entityChangeListeners.getListenerList();
- for (int i = 0; i < listeners.length; i = i + 2) {
- if (listeners[i] == EntityChangeListener.class) {
- ((EntityChangeListener) listeners[i + 1]).entityInserted(new EntityChangedEvent(this, null, e));
- }
- }
- }
-
- protected void fireEntityDeleted(Entity e) {
- Object[] listeners = entityChangeListeners.getListenerList();
- for (int i = 0; i < listeners.length; i = i + 2) {
- if (listeners[i] == EntityChangeListener.class) {
- ((EntityChangeListener) listeners[i + 1]).entityDeleted(new EntityChangedEvent(this, null, e));
- }
- }
- }
-
- protected void fireEntityUpdated(Entity oldEntity, Entity newEntity) {
- Object[] listeners = entityChangeListeners.getListenerList();
- for (int i = 0; i < listeners.length; i = i + 2) {
- if (listeners[i] == EntityChangeListener.class) {
- ((EntityChangeListener) listeners[i + 1]).entityUpdated(new EntityChangedEvent(this, oldEntity, newEntity));
+ private Entity fetchEntity(EntityType entityType, Id id) {
+ Entity entity = get(entityType, id);
+ for (NavigationProperty property : entityType.getNavigationEntities()) {
+ Object parentObject = entity.getProperty(property);
+ if (parentObject instanceof Entity) {
+ Entity parentEntity = (Entity) parentObject;
+ parentEntity.setExportObject(true);
}
}
+ return entity;
}
@Override
public boolean insert(Entity entity) throws NoSuchEntityException, IncompleteEntityException {
boolean result = doInsert(entity);
if (result) {
- insertedEntities.add(entity);
+ Entity newEntity = fetchEntity(
+ entity.getEntityType(),
+ entity.getId());
+ changedEntities.add(
+ new EntityChangedMessage()
+ .setEventType(EntityChangedMessage.Type.CREATE)
+ .setEntity(newEntity)
+ );
}
return result;
}
@@ -96,11 +83,20 @@ public boolean delete(EntityPathElement pathElement) throws NoSuchEntityExceptio
Entity entity = getEntityByEntityPath(pathElement);
boolean result = doDelete(pathElement);
if (result) {
- deletedEntities.add(entity);
+ changedEntities.add(
+ new EntityChangedMessage()
+ .setEventType(EntityChangedMessage.Type.DELETE)
+ .setEntity(entity)
+ );
}
return result;
}
+ @Override
+ public void delete(ResourcePath path, Query query) throws NoSuchEntityException {
+ doDelete(path, query);
+ }
+
private Entity getEntityByEntityPath(EntityPathElement pathElement) {
ResourcePath path = new ResourcePath();
path.addPathElement(new EntitySetPathElement(pathElement.getEntityType(), null), false, false);
@@ -111,29 +107,48 @@ private Entity getEntityByEntityPath(EntityPathElement pathElement) {
public abstract boolean doDelete(EntityPathElement pathElement) throws NoSuchEntityException;
+ public abstract void doDelete(ResourcePath path, Query query);
+
@Override
- public boolean update(EntityPathElement pathElement, Entity entity) throws NoSuchEntityException {
- Entity oldEntity = getEntityByEntityPath(pathElement);
- boolean result = doUpdate(pathElement, entity);
- if (result) {
- updatedEntities.add(new EntityUpdateInfo(oldEntity, getEntityByEntityPath(pathElement)));
+ public boolean update(EntityPathElement pathElement, Entity entity) throws NoSuchEntityException, IncompleteEntityException {
+ EntityChangedMessage result = doUpdate(pathElement, entity);
+ if (result != null) {
+ result.setEventType(EntityChangedMessage.Type.UPDATE);
+ Entity newEntity = fetchEntity(
+ entity.getEntityType(),
+ entity.getId());
+ result.setEntity(newEntity);
+ changedEntities.add(result);
}
- return result;
- }
-
- public abstract boolean doUpdate(EntityPathElement pathElement, Entity entity) throws NoSuchEntityException;
-
+ return result != null;
+ }
+
+ /**
+ * Update the given entity and return a message with the fields that were
+ * changed. The entity is added to the message by the
+ * AbstractPersistenceManager.
+ *
+ * @param pathElement The path to the entity to update.
+ * @param entity The updated entity.
+ * @return A message with the fields that were changed. The entity is added
+ * by the AbstractPersistenceManager.
+ * @throws NoSuchEntityException If the entity does not exist.
+ * @throws IncompleteEntityException If the entity does not have all the
+ * required fields.
+ */
+ public abstract EntityChangedMessage doUpdate(EntityPathElement pathElement, Entity entity) throws NoSuchEntityException, IncompleteEntityException;
+
+ /**
+ * If there are changes to send, connect to bus and send them.
+ */
private void fireEntityChangeEvents() {
- insertedEntities.forEach(e -> fireEntityInserted(e));
- deletedEntities.forEach(e -> fireEntityDeleted(e));
- updatedEntities.forEach(e -> fireEntityUpdated(e.oldEntity, e.newEntity));
+ MessageBus messageBus = MessageBusFactory.getMessageBus();
+ changedEntities.forEach(messageBus::sendMessage);
clearEntityChangedEvents();
}
private void clearEntityChangedEvents() {
- insertedEntities.clear();
- deletedEntities.clear();
- updatedEntities.clear();
+ changedEntities.clear();
}
@Override
@@ -162,15 +177,4 @@ public void close() {
}
protected abstract boolean doClose();
-
- private class EntityUpdateInfo {
-
- Entity oldEntity;
- Entity newEntity;
-
- public EntityUpdateInfo(Entity oldEntity, Entity newEntity) {
- this.oldEntity = oldEntity;
- this.newEntity = newEntity;
- }
- }
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/BasicPersistenceType.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/BasicPersistenceType.java
index 8ce938186..0ab3b5d22 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/BasicPersistenceType.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/BasicPersistenceType.java
@@ -22,8 +22,8 @@
* @author jab
*/
public enum BasicPersistenceType {
- Integer,
- Double,
- String,
- ByteArray
+ INTEGER,
+ DOUBLE,
+ STRING,
+ BYTEARRAY
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/EntityChangedEvent.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/EntityChangedEvent.java
deleted file mode 100644
index 8b0062c6c..000000000
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/EntityChangedEvent.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131 Karlsruhe, Germany.
- * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version.
- * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the
- * GNU Lesser General Public License for more details.
- * * You should have received a copy of the GNU Lesser General Public License along with this program. If not, see .
- */
-package de.fraunhofer.iosb.ilt.sta.persistence;
-
-import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
-import java.util.EventObject;
-
-/**
- *
- * @author jab
- */
-public class EntityChangedEvent extends EventObject {
-
- private final Entity oldEntity;
- private final Entity newEntity;
-
- public EntityChangedEvent(PersistenceManager source, Entity oldEntity, Entity newEntity) {
- super(source);
- this.oldEntity = oldEntity;
- this.newEntity = newEntity;
- }
-
- @Override
- public PersistenceManager getSource() {
- return (PersistenceManager) source;
- }
-
- public Entity getOldEntity() {
- return oldEntity;
- }
-
- public Entity getNewEntity() {
- return newEntity;
- }
-
-}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManager.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManager.java
index 7908d4ba4..7cf7a71ad 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManager.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManager.java
@@ -17,46 +17,34 @@
*/
package de.fraunhofer.iosb.ilt.sta.persistence;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
-import de.fraunhofer.iosb.ilt.sta.model.id.LongId;
-import de.fraunhofer.iosb.ilt.sta.model.id.StringId;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
/**
*
* @author scf
*/
-public interface IdManager {
+public interface IdManager {
+ /**
+ * Get the Id implementation used by this IdManager.
+ *
+ * @return The Class that implements Id.
+ */
public Class extends Id> getIdClass();
+ /**
+ * Parse the given input and generate an Id from it.
+ *
+ * @param input The input to parse as Id.
+ * @return The Id.
+ */
public Id parseId(String input);
- public static final IdManager ID_MANAGER_LONG = new IdManager() {
- @Override
- public Class extends Id> getIdClass() {
- return LongId.class;
- }
-
- @Override
- public Id parseId(String input) {
- return new LongId(Long.parseLong(input));
- }
- };
-
- public static final IdManager ID_MANAGER_STRING = new IdManager() {
- @Override
- public Class extends Id> getIdClass() {
- return StringId.class;
- }
-
- @Override
- public Id parseId(String input) {
- if (input.startsWith("'")) {
- return new StringId(input.substring(1, input.length() - 1));
- }
- return new StringId(input);
- }
- };
-;
-
+ /**
+ * Wrap the given id object in an Id.
+ *
+ * @param input The id object to wrap.
+ * @return an Id.
+ */
+ public Id fromObject(T input);
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManagerString.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManagerString.java
new file mode 100644
index 000000000..434d0d8af
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManagerString.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.persistence;
+
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.IdString;
+
+/**
+ *
+ * @author scf
+ */
+public class IdManagerString implements IdManager {
+
+ @Override
+ public Class extends Id> getIdClass() {
+ return IdString.class;
+ }
+
+ @Override
+ public Id parseId(String input) {
+ if (input.startsWith("'")) {
+ String idString = input.substring(1, input.length() - 1);
+ idString = idString.replaceAll("''", "'");
+ return new IdString(idString);
+ }
+ return new IdString(input);
+ }
+
+ @Override
+ public Id fromObject(Object input) {
+ return new IdString(input.toString());
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManagerlong.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManagerlong.java
new file mode 100644
index 000000000..296bce1d6
--- /dev/null
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/IdManagerlong.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+package de.fraunhofer.iosb.ilt.sta.persistence;
+
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
+import de.fraunhofer.iosb.ilt.sta.model.core.IdLong;
+
+/**
+ *
+ * @author scf
+ */
+public class IdManagerlong implements IdManager {
+
+ @Override
+ public Class extends Id> getIdClass() {
+ return IdLong.class;
+ }
+
+ @Override
+ public Id parseId(String input) {
+ return new IdLong(Long.parseLong(input));
+ }
+
+ @Override
+ public Id fromObject(Object input) {
+ if (input instanceof Number) {
+ return new IdLong(((Number) input).longValue());
+ }
+ throw new IllegalArgumentException("Can not use " + input.getClass().getName() + " (" + input + ") as a long Id");
+ }
+
+}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManager.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManager.java
index d5741ed9a..ec20b74a8 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManager.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManager.java
@@ -18,16 +18,17 @@
package de.fraunhofer.iosb.ilt.sta.persistence;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
-import de.fraunhofer.iosb.ilt.sta.model.id.Id;
-import de.fraunhofer.iosb.ilt.sta.model.id.LongId;
+import de.fraunhofer.iosb.ilt.sta.model.core.Id;
import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.path.ResourcePath;
import de.fraunhofer.iosb.ilt.sta.query.Query;
import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
import de.fraunhofer.iosb.ilt.sta.util.IncompleteEntityException;
import de.fraunhofer.iosb.ilt.sta.util.NoSuchEntityException;
+import de.fraunhofer.iosb.ilt.sta.util.UpgradeFailedException;
+import java.io.IOException;
+import java.io.Writer;
/**
*
@@ -56,15 +57,9 @@ public interface PersistenceManager {
*/
public boolean insert(Entity entity) throws NoSuchEntityException, IncompleteEntityException;
- public Object get(ResourcePath path, Query query);
+ public Entity get(EntityType entityType, Id id);
- public default Entity getEntityById(String serviceRootUrl, EntityType entityType, Id id) {
- ResourcePath path = new ResourcePath();
- path.addPathElement(new EntitySetPathElement(entityType, null), false, false);
- path.addPathElement(new EntityPathElement(id, entityType, path.getLastElement()), true, true);
- path.setServiceRootUrl(serviceRootUrl);
- return (Entity) get(path, null);
- }
+ public Object get(ResourcePath path, Query query);
public default T get(ResourcePath path, Query query, Class clazz) {
Object result = get(path, query);
@@ -76,11 +71,27 @@ public default T get(ResourcePath path, Query query, Class clazz) {
public boolean delete(EntityPathElement pathElement) throws NoSuchEntityException;
- public boolean update(EntityPathElement pathElement, Entity entity) throws NoSuchEntityException;
-
- public void addEntityChangeListener(EntityChangeListener listener);
+ /**
+ * Delete all entities in the given path, matching the filter in the given
+ * query.
+ *
+ * @param path The path to an entity set.
+ * @param query The query containing only a filter.
+ * @throws NoSuchEntityException If the path does not lead to an entity set.
+ */
+ public void delete(ResourcePath path, Query query) throws NoSuchEntityException;
- public void removeEntityChangeListener(EntityChangeListener listener);
+ /**
+ * Update the given entity.
+ *
+ * @param pathElement The path to the entity.
+ * @param entity The entity.
+ * @return True if the update was successful.
+ * @throws NoSuchEntityException If the entity does not exist.
+ * @throws IncompleteEntityException If the given entity is missing required
+ * fields.
+ */
+ public boolean update(EntityPathElement pathElement, Entity entity) throws NoSuchEntityException, IncompleteEntityException;
/**
* Initialise using the given settings.
@@ -124,7 +135,12 @@ public default void commitAndClose() {
/**
* Upgrade the storage backend.
*
- * @return a log of what was done.
+ * @param out The Writer to append logging messages to.
+ * @return true if the upgrade was successful, false if upgrade should be
+ * tried again later.
+ * @throws de.fraunhofer.iosb.ilt.sta.util.UpgradeFailedException when
+ * upgrading fails and should not be attempted again at a later stage.
+ * @throws java.io.IOException when the Writer throws this exception.
*/
- public String doUpgrades();
+ public boolean doUpgrades(Writer out) throws UpgradeFailedException, IOException;
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManagerFactory.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManagerFactory.java
index 53d38b694..f9e7aaa2c 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManagerFactory.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/persistence/PersistenceManagerFactory.java
@@ -1,23 +1,27 @@
/*
- * Copyright (C) 2016 Fraunhofer IOSB
+ * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
+ * Karlsruhe, Germany.
*
* This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
+ * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package de.fraunhofer.iosb.ilt.sta.persistence;
import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
-import javax.swing.event.EventListenerList;
+import de.fraunhofer.iosb.ilt.sta.settings.PersistenceSettings;
+import de.fraunhofer.iosb.ilt.sta.util.UpgradeFailedException;
+import java.io.IOException;
+import java.io.StringWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -28,22 +32,19 @@
public class PersistenceManagerFactory {
private static final String ERROR_MSG = "Could not generate PersistenceManager instance: ";
- private static final EventListenerList entityChangeListeners = new EventListenerList();
+
private static final Logger LOGGER = LoggerFactory.getLogger(PersistenceManagerFactory.class);
private static PersistenceManagerFactory instance;
+ private static boolean maybeUpdateDatabase = true;
public static synchronized void init(CoreSettings settings) {
if (instance == null) {
instance = new PersistenceManagerFactory(settings);
+ maybeUpdateDatabase(settings, instance);
+ }
+ if (maybeUpdateDatabase) {
+ maybeUpdateDatabase(settings, instance);
}
- }
-
- public static void addEntityChangeListener(EntityChangeListener listener) {
- entityChangeListeners.add(EntityChangeListener.class, listener);
- }
-
- public static void removeEntityChangeListener(EntityChangeListener listener) {
- entityChangeListeners.remove(EntityChangeListener.class, listener);
}
public static PersistenceManagerFactory getInstance() {
@@ -77,12 +78,36 @@ public PersistenceManager create() {
try {
persistenceManager = (PersistenceManager) persistenceManagerClass.newInstance();
persistenceManager.init(settings);
- for (EntityChangeListener listener : entityChangeListeners.getListeners(EntityChangeListener.class)) {
- persistenceManager.addEntityChangeListener(listener);
- }
} catch (InstantiationException | IllegalAccessException ex) {
LOGGER.error(ERROR_MSG + "Class '" + settings.getPersistenceSettings().getPersistenceManagerImplementationClass() + "' could not be instantiated", ex);
}
return persistenceManager;
}
+
+ private static void maybeUpdateDatabase(CoreSettings coreSettings, PersistenceManagerFactory instance) {
+ PersistenceSettings persistenceSettings = coreSettings.getPersistenceSettings();
+ if (persistenceSettings.isAutoUpdateDatabase()) {
+ StringWriter updateLog = new StringWriter();
+ try {
+ boolean success = instance.create().doUpgrades(updateLog);
+ maybeUpdateDatabase = !success;
+ if (success) {
+ LOGGER.info("Database-update successful.");
+ } else {
+ LOGGER.info("Database-update not successful, trying again later.");
+ }
+ } catch (UpgradeFailedException ex) {
+ LOGGER.error("Database upgrade failed.", ex);
+ maybeUpdateDatabase = false;
+ } catch (IOException ex) {
+ // Should not happen, StringWriter does not throw IOExceptions.
+ LOGGER.error("Database upgrade failed.", ex);
+ }
+ String logString = updateLog.toString();
+ if (!logString.isEmpty()) {
+ LOGGER.info("Database-update-log:\n{}", logString);
+ }
+ }
+ }
+
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Expand.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Expand.java
index 7c4ff4a7d..5404caf88 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Expand.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Expand.java
@@ -18,8 +18,6 @@
package de.fraunhofer.iosb.ilt.sta.query;
import de.fraunhofer.iosb.ilt.sta.path.CustomPropertyPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.path.NavigationProperty;
import de.fraunhofer.iosb.ilt.sta.path.PropertyPathElement;
@@ -75,15 +73,7 @@ public void validate(ResourcePath path) {
if (mainElement instanceof PropertyPathElement || mainElement instanceof CustomPropertyPathElement) {
throw new IllegalArgumentException("No expand allowed on property paths.");
}
- EntityType entityType = null;
- if (mainElement instanceof EntityPathElement) {
- EntityPathElement entityPathElement = (EntityPathElement) mainElement;;
- entityType = entityPathElement.getEntityType();
- }
- if (mainElement instanceof EntitySetPathElement) {
- EntitySetPathElement entitySetPathElement = (EntitySetPathElement) mainElement;
- entityType = entitySetPathElement.getEntityType();
- }
+ EntityType entityType = path.getMainElementType();
if (entityType == null) {
throw new IllegalStateException("Unkown ResourcePathElementType found.");
}
@@ -94,7 +84,7 @@ protected void validate(EntityType entityType) {
EntityType currentEntityType = entityType;
for (NavigationProperty navigationProperty : this.path) {
if (!currentEntityType.getPropertySet().contains(navigationProperty)) {
- throw new IllegalArgumentException("Invalid expand path '" + navigationProperty.getName() + "' on entity type " + currentEntityType.name);
+ throw new IllegalArgumentException("Invalid expand path '" + navigationProperty.getName() + "' on entity type " + currentEntityType.entityName);
}
currentEntityType = navigationProperty.getType();
}
@@ -105,10 +95,7 @@ protected void validate(EntityType entityType) {
@Override
public int hashCode() {
- int hash = 5;
- hash = 83 * hash + Objects.hashCode(this.path);
- hash = 83 * hash + Objects.hashCode(this.subQuery);
- return hash;
+ return Objects.hash(path, subQuery);
}
@Override
@@ -123,13 +110,8 @@ public boolean equals(Object obj) {
return false;
}
final Expand other = (Expand) obj;
- if (!Objects.equals(this.path, other.path)) {
- return false;
- }
- if (!Objects.equals(this.subQuery, other.subQuery)) {
- return false;
- }
- return true;
+ return Objects.equals(this.path, other.path)
+ && Objects.equals(this.subQuery, other.subQuery);
}
@Override
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/OrderBy.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/OrderBy.java
index 139a415d9..8a8d05063 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/OrderBy.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/OrderBy.java
@@ -17,9 +17,8 @@
*/
package de.fraunhofer.iosb.ilt.sta.query;
-import java.util.Objects;
-
import de.fraunhofer.iosb.ilt.sta.query.expression.Expression;
+import java.util.Objects;
/**
*
@@ -27,14 +26,21 @@
*/
public class OrderBy {
- public static enum OrderType {
+ /**
+ * The two directions that can be used for sorting.
+ */
+ public enum OrderType {
+
+ ASCENDING("asc"),
+ DESCENDING("desc");
- Ascending("asc"),
- Descending("desc");
- public final String name;
+ /**
+ * The direction as it appears in the url.
+ */
+ public final String direction;
- private OrderType(String name) {
- this.name = name;
+ private OrderType(String direction) {
+ this.direction = direction;
}
}
@@ -48,7 +54,7 @@ public OrderBy(Expression expression, OrderType type) {
public OrderBy(Expression expression) {
this.expression = expression;
- this.type = OrderType.Ascending;
+ this.type = OrderType.ASCENDING;
}
public Expression getExpression() {
@@ -61,10 +67,7 @@ public OrderType getType() {
@Override
public int hashCode() {
- int hash = 7;
- hash = 97 * hash + Objects.hashCode(this.expression);
- hash = 97 * hash + Objects.hashCode(this.type);
- return hash;
+ return Objects.hash(expression, type);
}
@Override
@@ -79,18 +82,13 @@ public boolean equals(Object obj) {
return false;
}
final OrderBy other = (OrderBy) obj;
- if (!Objects.equals(this.expression, other.expression)) {
- return false;
- }
- if (this.type != other.type) {
- return false;
- }
- return true;
+ return Objects.equals(this.expression, other.expression)
+ && this.type == other.type;
}
@Override
public String toString() {
- return expression.toUrl() + " " + type.name;
+ return expression.toUrl() + " " + type.direction;
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Query.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Query.java
index 7e782b17f..7f542907d 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Query.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/Query.java
@@ -18,8 +18,6 @@
package de.fraunhofer.iosb.ilt.sta.query;
import de.fraunhofer.iosb.ilt.sta.path.CustomPropertyPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntityPathElement;
-import de.fraunhofer.iosb.ilt.sta.path.EntitySetPathElement;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.path.Property;
import de.fraunhofer.iosb.ilt.sta.path.PropertyPathElement;
@@ -28,16 +26,12 @@
import de.fraunhofer.iosb.ilt.sta.query.expression.Expression;
import de.fraunhofer.iosb.ilt.sta.settings.CoreSettings;
import de.fraunhofer.iosb.ilt.sta.util.UrlHelper;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
*
@@ -45,10 +39,6 @@
*/
public class Query {
- /**
- * The logger for this class.
- */
- private static final Logger LOGGER = LoggerFactory.getLogger(Query.class);
private CoreSettings settings;
private Optional top;
private Optional skip;
@@ -78,15 +68,7 @@ public void validate(ResourcePath path) {
if (mainElement instanceof PropertyPathElement || mainElement instanceof CustomPropertyPathElement) {
throw new IllegalArgumentException("No queries allowed for property paths.");
}
- EntityType entityType = null;
- if (mainElement instanceof EntityPathElement) {
- EntityPathElement entityPathElement = (EntityPathElement) mainElement;;
- entityType = entityPathElement.getEntityType();
- }
- if (mainElement instanceof EntitySetPathElement) {
- EntitySetPathElement entitySetPathElement = (EntitySetPathElement) mainElement;
- entityType = entitySetPathElement.getEntityType();
- }
+ EntityType entityType = path.getMainElementType();
if (entityType == null) {
throw new IllegalStateException("Unkown ResourcePathElementType found.");
}
@@ -97,7 +79,7 @@ protected void validate(EntityType entityType) {
Set propertySet = entityType.getPropertySet();
Optional invalidProperty = select.stream().filter(x -> !propertySet.contains(x)).findAny();
if (invalidProperty.isPresent()) {
- throw new IllegalArgumentException("Invalid property '" + invalidProperty.get().getName() + "' found for entity type " + entityType.name);
+ throw new IllegalArgumentException("Invalid property '" + invalidProperty.get().getName() + "' found for entity type " + entityType.entityName);
}
expand.forEach(x -> x.validate(entityType));
}
@@ -206,16 +188,7 @@ public void setOrderBy(List orderBy) {
@Override
public int hashCode() {
- int hash = 7;
- hash = 73 * hash + Objects.hashCode(this.top);
- hash = 73 * hash + Objects.hashCode(this.skip);
- hash = 73 * hash + Objects.hashCode(this.count);
- hash = 73 * hash + Objects.hashCode(this.select);
- hash = 73 * hash + Objects.hashCode(this.filter);
- hash = 73 * hash + Objects.hashCode(this.format);
- hash = 73 * hash + Objects.hashCode(this.expand);
- hash = 73 * hash + Objects.hashCode(this.orderBy);
- return hash;
+ return Objects.hash(top, skip, count, select, filter, format, expand, orderBy);
}
@Override
@@ -230,31 +203,14 @@ public boolean equals(Object obj) {
return false;
}
final Query other = (Query) obj;
- if (!Objects.equals(this.count, other.count)) {
- return false;
- }
- if (!Objects.equals(this.top, other.top)) {
- return false;
- }
- if (!Objects.equals(this.skip, other.skip)) {
- return false;
- }
- if (!Objects.equals(this.select, other.select)) {
- return false;
- }
- if (!Objects.equals(this.filter, other.filter)) {
- return false;
- }
- if (!Objects.equals(this.format, other.format)) {
- return false;
- }
- if (!Objects.equals(this.expand, other.expand)) {
- return false;
- }
- if (!Objects.equals(this.orderBy, other.orderBy)) {
- return false;
- }
- return true;
+ return Objects.equals(this.count, other.count)
+ && Objects.equals(this.top, other.top)
+ && Objects.equals(this.skip, other.skip)
+ && Objects.equals(this.select, other.select)
+ && Objects.equals(this.filter, other.filter)
+ && Objects.equals(this.format, other.format)
+ && Objects.equals(this.expand, other.expand)
+ && Objects.equals(this.orderBy, other.orderBy);
}
@Override
@@ -266,39 +222,73 @@ public String toString(boolean inExpand) {
char separator = inExpand ? ';' : '&';
StringBuilder sb = new StringBuilder();
- if (top.isPresent()) {
- sb.append(separator).append("$top=").append(top.get());
+
+ addTopToUrl(sb, separator);
+
+ addSkipToUrl(sb, separator);
+
+ addSelectToUrl(sb, separator);
+
+ addFilterToUrl(sb, separator, inExpand);
+
+ addFormatToUrl(sb, separator);
+
+ addExpandToUrl(sb, separator, inExpand);
+
+ addOrderbyToUrl(sb, separator, inExpand);
+
+ addCountToUrl(sb, separator);
+
+ if (sb.length() > 0) {
+ return sb.substring(1);
+ }
+ return "";
+ }
+
+ private void addCountToUrl(StringBuilder sb, char separator) {
+ if (count.isPresent()) {
+ sb.append(separator).append("$count=").append(count.get());
+ }
+ }
+
+ private void addFormatToUrl(StringBuilder sb, char separator) {
+ if (format != null) {
+ sb.append(separator).append("$resultFormat=").append(UrlHelper.urlEncode(format));
}
+ }
+
+ private void addSkipToUrl(StringBuilder sb, char separator) {
if (skip.isPresent()) {
sb.append(separator).append("$skip=").append(skip.get());
}
- if (!select.isEmpty()) {
- sb.append(separator).append("$select=");
+ }
+
+ private void addTopToUrl(StringBuilder sb, char separator) {
+ if (top.isPresent()) {
+ sb.append(separator).append("$top=").append(top.get());
+ }
+ }
+
+ private void addOrderbyToUrl(StringBuilder sb, char separator, boolean inExpand) {
+ if (!orderBy.isEmpty()) {
+ sb.append(separator).append("$orderby=");
boolean firstDone = false;
- for (Property property : select) {
+ for (OrderBy ob : orderBy) {
if (firstDone) {
sb.append(",");
} else {
firstDone = true;
}
- try {
- sb.append(URLEncoder.encode(property.getName(), "UTF-8"));
- } catch (UnsupportedEncodingException ex) {
- LOGGER.error("UTF-8 not supported?!", ex);
+ String orderUrl = ob.toString();
+ if (!inExpand) {
+ orderUrl = UrlHelper.urlEncode(orderUrl);
}
+ sb.append(orderUrl);
}
}
- if (filter != null) {
- sb.append(separator).append("$filter=");
- String filterUrl = filter.toUrl();
- if (!inExpand) {
- filterUrl = UrlHelper.urlEncode(filterUrl);
- }
- sb.append(filterUrl);
- }
- if (format != null) {
- sb.append(separator).append("$resultFormat=").append(UrlHelper.urlEncode(format));
- }
+ }
+
+ private void addExpandToUrl(StringBuilder sb, char separator, boolean inExpand) {
if (!expand.isEmpty()) {
sb.append(separator).append("$expand=");
boolean firstDone = false;
@@ -315,29 +305,32 @@ public String toString(boolean inExpand) {
sb.append(expandUrl);
}
}
- if (!orderBy.isEmpty()) {
- sb.append(separator).append("$orderby=");
+ }
+
+ private void addFilterToUrl(StringBuilder sb, char separator, boolean inExpand) {
+ if (filter != null) {
+ sb.append(separator).append("$filter=");
+ String filterUrl = filter.toUrl();
+ if (!inExpand) {
+ filterUrl = UrlHelper.urlEncode(filterUrl);
+ }
+ sb.append(filterUrl);
+ }
+ }
+
+ private void addSelectToUrl(StringBuilder sb, char separator) {
+ if (!select.isEmpty()) {
+ sb.append(separator).append("$select=");
boolean firstDone = false;
- for (OrderBy ob : orderBy) {
+ for (Property property : select) {
if (firstDone) {
sb.append(",");
} else {
firstDone = true;
}
- String orderUrl = ob.toString();
- if (!inExpand) {
- orderUrl = UrlHelper.urlEncode(orderUrl);
- }
- sb.append(orderUrl);
+ sb.append(UrlHelper.urlEncode(property.getName()));
}
}
- if (count.isPresent()) {
- sb.append(separator).append("$count=").append(count.get());
- }
- if (sb.length() > 0) {
- return sb.substring(1);
- }
- return "";
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/ExpressionVisitor.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/ExpressionVisitor.java
index 8b21b7057..a4eab4240 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/ExpressionVisitor.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/ExpressionVisitor.java
@@ -53,9 +53,9 @@
import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Time;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.TotalOffsetMinutes;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.date.Year;
-import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoDistance;
-import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoIntersects;
-import de.fraunhofer.iosb.ilt.sta.query.expression.function.geospatial.GeoLength;
+import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.GeoDistance;
+import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.GeoIntersects;
+import de.fraunhofer.iosb.ilt.sta.query.expression.function.spatialrelation.GeoLength;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.And;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.Not;
import de.fraunhofer.iosb.ilt.sta.query.expression.function.logical.Or;
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/Path.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/Path.java
index 8af01ad87..0da872b95 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/Path.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/Path.java
@@ -49,9 +49,7 @@ public List getElements() {
@Override
public int hashCode() {
- int hash = 5;
- hash = 89 * hash + Objects.hashCode(this.elements);
- return hash;
+ return Objects.hash(elements);
}
@Override
@@ -66,10 +64,7 @@ public boolean equals(Object obj) {
return false;
}
final Path other = (Path) obj;
- if (!Objects.equals(this.elements, other.elements)) {
- return false;
- }
- return true;
+ return Objects.equals(this.elements, other.elements);
}
@Override
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/Constant.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/Constant.java
index b14b6cd42..ec128749c 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/Constant.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/Constant.java
@@ -65,13 +65,6 @@ public T getValue() {
return value;
}
- @Override
- public int hashCode() {
- int hash = 3;
- hash = 83 * hash + Objects.hashCode(this.value);
- return hash;
- }
-
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -84,10 +77,12 @@ public boolean equals(Object obj) {
return false;
}
final Constant> other = (Constant>) obj;
- if (!Objects.equals(this.value, other.value)) {
- return false;
- }
- return true;
+ return Objects.equals(this.value, other.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(value);
}
}
diff --git a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/GeoJsonConstant.java b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/GeoJsonConstant.java
index aa34f9ee7..a4a1e3b19 100644
--- a/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/GeoJsonConstant.java
+++ b/FROST-Server.Core/src/main/java/de/fraunhofer/iosb/ilt/sta/query/expression/constant/GeoJsonConstant.java
@@ -17,11 +17,13 @@
*/
package de.fraunhofer.iosb.ilt.sta.query.expression.constant;
+import java.util.Objects;
import org.geojson.GeoJsonObject;
/**
*
* @author jab
+ * @param