use of org.openremote.model.asset.AssetAttribute in project openremote by openremote.
the class AbstractProtocol method updateLinkedAttribute.
/**
* Update the value of a linked attribute. Call this to publish new sensor values. This will apply any
* {@link MessageFilter}s that have been set for the {@link Attribute} against the {@link AttributeState#value}
* before sending on the sensor queue.
*/
@SuppressWarnings("unchecked")
protected final void updateLinkedAttribute(final AttributeState finalState, long timestamp) {
withLock(getProtocolName() + "::updateLinkedAttribute", () -> {
AttributeState state = finalState;
AssetAttribute attribute = linkedAttributes.get(state.getAttributeRef());
if (attribute == null) {
LOG.severe("Update linked attribute called for un-linked attribute: " + state);
return;
}
if (state.getValue().isPresent()) {
List<MessageFilter> filters;
Value value = state.getValue().get();
filters = linkedAttributeFilters.get(state.getAttributeRef());
if (filters != null) {
LOG.fine("Applying message filters to sensor value...");
for (MessageFilter filter : filters) {
if (filter.getMessageType() != value.getType().getModelType()) {
LOG.fine("Message filter type '" + filter.getMessageType().getName() + "' is not compatible with actual message type '" + value.getType().getModelType().getName() + "': " + filter.getClass().getName());
value = null;
} else {
try {
LOG.finest("Applying message filter: " + filter.getClass().getName());
value = filter.process(value);
} catch (Exception e) {
LOG.log(Level.SEVERE, "Message filter threw and exception during processing of message: " + filter.getClass().getName(), e);
value = null;
}
}
if (value == null) {
break;
}
}
}
// Do basic value conversion
Optional<ValueType> attributeValueType = attribute.getType().map(AttributeType::getValueType);
if (value != null && attributeValueType.isPresent()) {
if (attributeValueType.get() != value.getType()) {
LOG.fine("Converting value: " + value.getType() + " -> " + attributeValueType.get());
Optional<Value> convertedValue = Values.convert(value, attributeValueType.get());
if (!convertedValue.isPresent()) {
LOG.warning("Failed to convert value: " + value.getType() + " -> " + attributeValueType.get());
} else {
value = convertedValue.get();
}
}
}
state = new AttributeState(state.getAttributeRef(), value);
}
AttributeEvent attributeEvent = new AttributeEvent(state, timestamp);
LOG.fine("Sending on sensor queue: " + attributeEvent);
producerTemplate.sendBodyAndHeader(SENSOR_QUEUE, attributeEvent, Protocol.SENSOR_QUEUE_SOURCE_PROTOCOL, getProtocolName());
if (locationLinkedAttributes.contains(state.getAttributeRef())) {
// Check value type is compatible
Point location = state.getValue().map(value -> {
if (value.getType() != ValueType.ARRAY) {
LOG.warning("Location linked attribute type is not an array");
return null;
}
Optional<List<NumberValue>> coordinates = Values.getArrayElements((ArrayValue) value, NumberValue.class, false, false);
if (!coordinates.isPresent() || coordinates.get().size() != 2 || Math.abs(coordinates.get().get(0).getNumber()) > 180 || Math.abs(coordinates.get().get(1).getNumber()) > 90) {
LOG.warning("Location linked attribute value must contain longitude then latitude in a 2 value number array");
return null;
}
try {
return new GeometryFactory().createPoint(new Coordinate(coordinates.get().get(0).getNumber(), coordinates.get().get(1).getNumber()));
} catch (Exception e) {
return null;
}
}).orElse(null);
updateAssetLocation(state.getAttributeRef().getEntityId(), location);
}
});
}
use of org.openremote.model.asset.AssetAttribute in project openremote by openremote.
the class AbstractProtocol method processLinkedAttributeWrite.
protected final void processLinkedAttributeWrite(AttributeEvent event) {
LOG.finest("Processing linked attribute write on " + getProtocolName() + ": " + event);
withLock(getProtocolName() + "::processLinkedAttributeWrite", () -> {
AssetAttribute attribute = linkedAttributes.get(event.getAttributeRef());
if (attribute == null) {
LOG.warning("Attribute doesn't exist on this protocol: " + event.getAttributeRef());
} else {
AssetAttribute protocolConfiguration = getLinkedProtocolConfiguration(attribute);
processLinkedAttributeWrite(event, protocolConfiguration);
}
});
}
use of org.openremote.model.asset.AssetAttribute in project openremote by openremote.
the class AbstractHttpServerProtocol method createDeployment.
protected ResteasyDeployment createDeployment(Application application, AssetAttribute protocolConfiguration) {
ResteasyDeployment resteasyDeployment = new ResteasyDeployment();
resteasyDeployment.setApplication(application);
List<String> allowedOrigins;
if (devMode) {
allowedOrigins = Collections.singletonList("*");
} else {
Optional<MetaItem> allowedOriginsMeta = protocolConfiguration.getMetaItem(META_PROTOCOL_ALLOWED_ORIGINS);
allowedOrigins = allowedOriginsMeta.flatMap(AbstractValueHolder::getValueAsString).map(Collections::singletonList).orElseGet(() -> allowedOriginsMeta.flatMap(AbstractValueHolder::getValueAsArray).flatMap(arrayValue -> Values.getArrayElements(arrayValue, StringValue.class, true, false, StringValue::getString)).orElse(null));
}
if (allowedOrigins != null) {
String allowedMethods = protocolConfiguration.getMetaItem(META_PROTOCOL_ALLOWED_METHODS).flatMap(AbstractValueHolder::getValueAsString).orElse(DEFAULT_ALLOWED_METHODS);
if (TextUtil.isNullOrEmpty(allowedMethods)) {
throw new IllegalArgumentException("Allowed methods meta item must be a non empty string: " + META_PROTOCOL_ALLOWED_METHODS);
}
CorsFilter corsFilter = new CorsFilter();
corsFilter.getAllowedOrigins().addAll(allowedOrigins);
corsFilter.setAllowedMethods(allowedMethods);
resteasyDeployment.getProviders().add(corsFilter);
}
return resteasyDeployment;
}
use of org.openremote.model.asset.AssetAttribute in project openremote by openremote.
the class HttpClientProtocol method doLinkAttribute.
@Override
protected void doLinkAttribute(AssetAttribute attribute, AssetAttribute protocolConfiguration) {
AttributeRef protocolConfigurationRef = protocolConfiguration.getReferenceOrThrow();
Pair<ResteasyWebTarget, List<Integer>> clientAndFailureCodes;
clientAndFailureCodes = clientMap.get(protocolConfigurationRef);
WebTarget client = clientAndFailureCodes != null ? clientAndFailureCodes.key : null;
if (client == null) {
LOG.warning("Attempt to link attribute to non existent protocol configuration: " + attribute.getReferenceOrThrow());
return;
}
String method = Values.getMetaItemValueOrThrow(attribute, META_ATTRIBUTE_METHOD, StringValue.class, false, true).map(StringValue::getString).orElse(DEFAULT_HTTP_METHOD);
String path = Values.getMetaItemValueOrThrow(attribute, META_ATTRIBUTE_PATH, StringValue.class, false, true).map(StringValue::getString).orElse(null);
String contentType = Values.getMetaItemValueOrThrow(attribute, META_ATTRIBUTE_CONTENT_TYPE, StringValue.class, false, true).map(StringValue::getString).orElse(null);
Value body = attribute.getMetaItem(META_ATTRIBUTE_BODY).flatMap(AbstractValueHolder::getValue).orElse(null);
List<Integer> failureCodes = attribute.getMetaItem(META_FAILURE_CODES).flatMap(AbstractValueHolder::getValueAsArray).flatMap(arrayValue -> Values.getArrayElements(arrayValue, NumberValue.class, true, false, number -> Values.getIntegerCoerced(number).orElse(null))).map(fCodes -> {
if (clientAndFailureCodes.value != null) {
fCodes.addAll(clientAndFailureCodes.value);
}
return fCodes;
}).orElseGet(() -> {
if (clientAndFailureCodes.value != null) {
return clientAndFailureCodes.value;
}
return null;
});
MultivaluedMap<String, String> headers = Values.getMetaItemValueOrThrow(attribute, META_HEADERS, ObjectValue.class, false, true).flatMap(objectValue -> getMultivaluedMap(objectValue, true)).orElse(null);
MultivaluedMap<String, String> queryParams = Values.getMetaItemValueOrThrow(attribute, META_QUERY_PARAMETERS, ObjectValue.class, false, true).flatMap(objectValue -> getMultivaluedMap(objectValue, false)).orElse(null);
Optional<Integer> pollingSeconds = Values.getMetaItemValueOrThrow(attribute, META_ATTRIBUTE_POLLING_SECONDS, NumberValue.class, false, true).map(polling -> Values.getIntegerCoerced(polling).map(seconds -> seconds < 1 ? null : seconds).orElseThrow(() -> new IllegalArgumentException("Polling seconds meta item must be an integer >= 1")));
final AttributeRef attributeRef = attribute.getReferenceOrThrow();
boolean updateConnectionStatus = !pollingMap.containsKey(protocolConfigurationRef);
HttpClientRequest clientRequest = buildClientRequest(client, path, method, headers, queryParams, failureCodes, updateConnectionStatus, body, contentType);
LOG.fine("Creating HTTP request for linked attribute '" + clientRequest + "': " + attributeRef);
requestMap.put(attributeRef, clientRequest);
pollingSeconds.ifPresent(seconds -> pollingMap.put(attributeRef, schedulePollingRequest(attributeRef, protocolConfigurationRef, clientRequest, seconds)));
}
use of org.openremote.model.asset.AssetAttribute in project openremote by openremote.
the class HttpClientProtocol method doLinkProtocolConfiguration.
@Override
protected void doLinkProtocolConfiguration(AssetAttribute protocolConfiguration) {
final AttributeRef protocolRef = protocolConfiguration.getReferenceOrThrow();
if (!protocolConfiguration.isEnabled()) {
updateStatus(protocolRef, ConnectionStatus.DISABLED);
return;
}
String baseUri = protocolConfiguration.getMetaItem(META_PROTOCOL_BASE_URI).flatMap(AbstractValueHolder::getValueAsString).orElseThrow(() -> new IllegalArgumentException("Missing or invalid require meta item: " + META_PROTOCOL_BASE_URI));
/* We're going to fail hard and fast if optional meta items are incorrectly configured */
Optional<OAuthGrant> oAuthGrant = getOAuthGrant(protocolConfiguration);
Optional<StringValue> username = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_USERNAME, StringValue.class, false, true);
Optional<StringValue> password = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_PASSWORD, StringValue.class, false, true);
boolean followRedirects = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_FOLLOW_REDIRECTS, BooleanValue.class, false, true).map(BooleanValue::getBoolean).orElse(false);
List<Integer> failureCodes = protocolConfiguration.getMetaItem(META_FAILURE_CODES).flatMap(AbstractValueHolder::getValueAsArray).flatMap(arrayValue -> Values.getArrayElements(arrayValue, NumberValue.class, true, false, number -> Values.getIntegerCoerced(number).orElse(null))).orElse(null);
Optional<MultivaluedMap<String, String>> headers = Values.getMetaItemValueOrThrow(protocolConfiguration, META_HEADERS, ObjectValue.class, false, true).flatMap(objectValue -> getMultivaluedMap(objectValue, true));
Optional<MultivaluedMap<String, String>> queryParams = Values.getMetaItemValueOrThrow(protocolConfiguration, META_QUERY_PARAMETERS, ObjectValue.class, false, true).flatMap(objectValue -> getMultivaluedMap(objectValue, false));
String pingPath = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_PING_PATH, StringValue.class, false, true).map(StringValue::getString).orElse(null);
if ((username.isPresent() && !password.isPresent()) || (!username.isPresent() && password.isPresent())) {
throw new IllegalArgumentException("Both username and password must be set for basic authentication");
}
WebTargetBuilder webTargetBuilder = new WebTargetBuilder(baseUri);
if (oAuthGrant.isPresent()) {
LOG.info("Adding OAuth");
webTargetBuilder.setOAuthAuthentication(oAuthGrant.get());
} else {
// noinspection ConstantConditions
username.ifPresent(stringValue -> {
LOG.info("Adding Basic Authentication");
webTargetBuilder.setBasicAuthentication(stringValue.getString(), password.get().getString());
});
}
headers.ifPresent(webTargetBuilder::setInjectHeaders);
queryParams.ifPresent(webTargetBuilder::setInjectQueryParameters);
webTargetBuilder.followRedirects(followRedirects);
LOG.fine("Creating web target client '" + baseUri + "'");
ResteasyWebTarget client = webTargetBuilder.build();
clientMap.put(protocolRef, new Pair<>(client, failureCodes));
updateStatus(protocolRef, ConnectionStatus.UNKNOWN);
if (pingPath == null) {
return;
}
String pingMethod = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_PING_METHOD, StringValue.class, false, true).map(StringValue::getString).orElse(DEFAULT_HTTP_METHOD);
Value pingBody = protocolConfiguration.getMetaItem(META_PROTOCOL_PING_BODY).flatMap(AbstractValueHolder::getValue).orElse(null);
MultivaluedMap<String, String> pingQueryParams = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_PING_QUERY_PARAMETERS, ObjectValue.class, false, true).flatMap(objectValue -> getMultivaluedMap(objectValue, false)).orElse(null);
Integer pingPollingSeconds = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_PING_SECONDS, NumberValue.class, false, true).map(polling -> Values.getIntegerCoerced(polling).map(seconds -> seconds < 1 ? null : seconds).orElseThrow(() -> new IllegalArgumentException("Ping polling seconds meta item must be an integer >= 1"))).orElse(DEFAULT_PING_SECONDS);
String contentType = Values.getMetaItemValueOrThrow(protocolConfiguration, META_PROTOCOL_PING_CONTENT_TYPE, StringValue.class, false, true).map(StringValue::getString).orElse(null);
HttpClientRequest pingRequest = buildClientRequest(client, pingPath, pingMethod, null, pingQueryParams, null, true, pingBody, contentType);
LOG.info("Creating ping polling request '" + pingRequest + "'");
requestMap.put(protocolRef, pingRequest);
pollingMap.put(protocolRef, schedulePollingRequest(null, protocolRef, pingRequest, pingPollingSeconds));
}
Aggregations