You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2022/08/18 20:33:08 UTC
[incubator-streampipes] 02/15: [STREAMPIPES-577] Improve error handling in StreamPipes Connect
This is an automated email from the ASF dual-hosted git repository.
riemer pushed a commit to branch rel/0.70.0
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
commit 7a1f96bfb31ceb81367c68f0ecae7176afab89eb
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Mon Aug 15 14:48:11 2022 +0200
[STREAMPIPES-577] Improve error handling in StreamPipes Connect
---
.../exceptions/SpConfigurationException.java | 32 +++
.../master/management/GuessManagement.java | 6 +-
.../master/management/WorkerRestClient.java | 23 +-
.../worker/rest/RuntimeResolvableResource.java | 26 +-
.../api/InvocablePipelineElementResource.java | 27 +-
.../api/ResolvesContainerProvidedOptions.java | 3 +-
.../ResolvesContainerProvidedOutputStrategy.java | 4 +-
.../api/RuntimeResolvableRequestHandler.java | 5 +-
.../container/api/SupportsRuntimeConfig.java | 3 +-
.../opcua/MiloOpcUaConfigurationProvider.java | 8 +-
.../connect/iiot/adapters/opcua/OpcUaAdapter.java | 4 +-
.../connect/iiot/adapters/opcua/SpOpcUaClient.java | 8 +-
.../opcua/utils/ExceptionMessageExtractor.java | 34 ++-
.../iiot/adapters/opcua/utils/OpcUaUtil.java | 287 +++++++++++----------
.../org/apache/streampipes/model/MessageLd.java | 117 ---------
.../apache/streampipes/model/NotificationLd.java | 95 -------
.../streampipes/model/StreamPipesErrorMessage.java | 98 +++++++
.../rest/impl/connect/GuessResource.java | 14 +-
.../impl/connect/RuntimeResolvableResource.java | 19 +-
ui/package.json | 4 +-
.../src/lib/model/gen/streampipes-model.ts | 35 ++-
ui/projects/streampipes/shared-ui/package.json | 1 +
.../exception-details-dialog.component.html | 43 +++
.../exception-details-dialog.component.scss} | 39 +--
.../exception-details-dialog.component.ts} | 25 +-
.../sp-exception-message.component.html | 38 +++
.../sp-exception-message.component.scss | 17 +-
.../sp-exception-message.component.ts | 56 ++++
.../shared-ui/src/lib/shared-ui.module.ts | 10 +-
.../streampipes/shared-ui/src/public-api.ts | 2 +
.../new-adapter/new-adapter.component.ts | 1 -
.../error-message/error-message.component.html | 18 +-
.../error-message/error-message.component.ts | 3 +-
.../event-schema/event-schema.component.html | 2 +-
.../event-schema/event-schema.component.ts | 5 +-
ui/src/app/connect/connect.module.ts | 3 +-
...tatic-runtime-resolvable-any-input.component.ts | 3 +
.../base-runtime-resolvable-input.ts | 13 +
...tic-runtime-resolvable-oneof-input.component.ts | 3 +
.../static-tree-input.component.html | 3 +
.../static-tree-input.component.ts | 31 +++
41 files changed, 687 insertions(+), 481 deletions(-)
diff --git a/streampipes-commons/src/main/java/org/apache/streampipes/commons/exceptions/SpConfigurationException.java b/streampipes-commons/src/main/java/org/apache/streampipes/commons/exceptions/SpConfigurationException.java
new file mode 100644
index 000000000..a1436f4f1
--- /dev/null
+++ b/streampipes-commons/src/main/java/org/apache/streampipes/commons/exceptions/SpConfigurationException.java
@@ -0,0 +1,32 @@
+package org.apache.streampipes.commons.exceptions;
+
+public class SpConfigurationException extends Exception {
+
+ /**
+ * Creates a new Exception with the given message and null as the cause.
+ *
+ * @param message The exception message
+ */
+ public SpConfigurationException(String message) {
+ super(message);
+ }
+
+ /**
+ * Creates a new exception with a null message and the given cause.
+ *
+ * @param cause The exception that caused this exception
+ */
+ public SpConfigurationException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Creates a new exception with the given message and cause
+ *
+ * @param message The exception message
+ * @param cause The exception that caused this exception
+ */
+ public SpConfigurationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java
index f5385e317..e54ade7a4 100644
--- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java
+++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/GuessManagement.java
@@ -67,10 +67,10 @@ public class GuessManagement {
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
return mapper.readValue(responseString, GuessSchema.class);
} else {
- ErrorMessage errorMessage = mapper.readValue(responseString, ErrorMessage.class);
+ ErrorMessage errorMessage = mapper.readValue(responseString, ErrorMessage.class);
- LOG.error(errorMessage.getElementName());
- throw new WorkerAdapterException(errorMessage);
+ LOG.error(errorMessage.getElementName());
+ throw new WorkerAdapterException(errorMessage);
}
}
diff --git a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java
index 8c9f1074c..dab1e4bd7 100644
--- a/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java
+++ b/streampipes-connect-container-master/src/main/java/org/apache/streampipes/connect/container/master/management/WorkerRestClient.java
@@ -18,8 +18,11 @@
package org.apache.streampipes.connect.container.master.management;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.IOUtils;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.connect.api.exception.AdapterException;
import org.apache.streampipes.connect.container.master.util.WorkerPaths;
import org.apache.streampipes.model.connect.adapter.AdapterDescription;
@@ -37,6 +40,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.util.List;
/**
@@ -146,19 +150,26 @@ public class WorkerRestClient {
public static RuntimeOptionsResponse getConfiguration(String workerEndpoint,
String appId,
- RuntimeOptionsRequest runtimeOptionsRequest) throws AdapterException {
+ RuntimeOptionsRequest runtimeOptionsRequest) throws AdapterException, SpConfigurationException {
String url = workerEndpoint + WorkerPaths.getRuntimeResolvablePath(appId);
try {
String payload = JacksonSerializer.getObjectMapper().writeValueAsString(runtimeOptionsRequest);
- String responseString = Request.Post(url)
+ var response = Request.Post(url)
.bodyString(payload, ContentType.APPLICATION_JSON)
.connectTimeout(1000)
.socketTimeout(100000)
- .execute().returnContent().asString();
+ .execute()
+ .returnResponse();
- return JacksonSerializer.getObjectMapper().readValue(responseString, RuntimeOptionsResponse.class);
+ String responseString = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
+ if (response.getStatusLine().getStatusCode() == 200) {
+ return getSerializer().readValue(responseString, RuntimeOptionsResponse.class);
+ } else {
+ var exception = getSerializer().readValue(responseString, SpConfigurationException.class);
+ throw new SpConfigurationException(exception.getMessage(), exception.getCause());
+ }
} catch (IOException e) {
e.printStackTrace();
throw new AdapterException("Could not resolve runtime configurations from " + url);
@@ -245,5 +256,9 @@ public class WorkerRestClient {
private static IAdapterStorage getAdapterStorage() {
return StorageDispatcher.INSTANCE.getNoSqlStore().getAdapterInstanceStorage();
}
+
+ private static ObjectMapper getSerializer() {
+ return JacksonSerializer.getObjectMapper();
+ }
}
diff --git a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java
index 92a81fdec..72a209462 100644
--- a/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java
+++ b/streampipes-connect-container-worker/src/main/java/org/apache/streampipes/connect/container/worker/rest/RuntimeResolvableResource.java
@@ -18,6 +18,8 @@
package org.apache.streampipes.connect.container.worker.rest;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
+import org.apache.streampipes.commons.exceptions.SpRuntimeException;
import org.apache.streampipes.connect.api.Connector;
import org.apache.streampipes.connect.container.worker.management.RuntimeResovable;
import org.apache.streampipes.container.api.ResolvesContainerProvidedOptions;
@@ -47,15 +49,21 @@ public class RuntimeResolvableResource extends AbstractSharedRestInterface {
RuntimeOptionsResponse response;
RuntimeResolvableRequestHandler handler = new RuntimeResolvableRequestHandler();
- if (connector instanceof ResolvesContainerProvidedOptions) {
- response = handler.handleRuntimeResponse((ResolvesContainerProvidedOptions) connector, runtimeOptionsRequest);
- } else if (connector instanceof SupportsRuntimeConfig) {
- response = handler.handleRuntimeResponse((SupportsRuntimeConfig) connector, runtimeOptionsRequest);
- } else {
- throw new WebApplicationException(javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ try {
+ if (connector instanceof ResolvesContainerProvidedOptions) {
+ response = handler.handleRuntimeResponse((ResolvesContainerProvidedOptions) connector, runtimeOptionsRequest);
+ return ok(response);
+ } else if (connector instanceof SupportsRuntimeConfig) {
+ response = handler.handleRuntimeResponse((SupportsRuntimeConfig) connector, runtimeOptionsRequest);
+ return ok(response);
+ } else {
+ throw new SpRuntimeException("This element does not support dynamic options - is the pipeline element description up to date?");
+ }
+ } catch (SpConfigurationException e) {
+ return javax.ws.rs.core.Response
+ .status(400)
+ .entity(e)
+ .build();
}
-
- return ok(response);
}
-
}
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java
index 9936bd2bf..780b70434 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/InvocablePipelineElementResource.java
@@ -19,6 +19,7 @@
package org.apache.streampipes.container.api;
import org.apache.streampipes.commons.constants.Envs;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.commons.exceptions.SpRuntimeException;
import org.apache.streampipes.container.declarer.Declarer;
import org.apache.streampipes.container.declarer.InvocableDeclarer;
@@ -106,14 +107,21 @@ public abstract class InvocablePipelineElementResource<I extends InvocableStream
D declarer = getDeclarerById(elementId);
RuntimeOptionsResponse responseOptions;
- if (declarer instanceof ResolvesContainerProvidedOptions) {
- responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((ResolvesContainerProvidedOptions) declarer, req);
- return ok(responseOptions);
- } else if (declarer instanceof SupportsRuntimeConfig) {
- responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((SupportsRuntimeConfig) declarer, req);
- return ok(responseOptions);
- } else {
- throw new WebApplicationException(javax.ws.rs.core.Response.Status.BAD_REQUEST);
+ try {
+ if (declarer instanceof ResolvesContainerProvidedOptions) {
+ responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((ResolvesContainerProvidedOptions) declarer, req);
+ return ok(responseOptions);
+ } else if (declarer instanceof SupportsRuntimeConfig) {
+ responseOptions = new RuntimeResolvableRequestHandler().handleRuntimeResponse((SupportsRuntimeConfig) declarer, req);
+ return ok(responseOptions);
+ } else {
+ return javax.ws.rs.core.Response.status(500).build();
+ }
+ } catch (SpConfigurationException e) {
+ return javax.ws.rs.core.Response
+ .status(400)
+ .entity(e)
+ .build();
}
}
@@ -131,8 +139,7 @@ public abstract class InvocablePipelineElementResource<I extends InvocableStream
(elementId);
return ok(resolvesOutput.resolveOutputStrategy
(runtimeOptionsRequest, getExtractor(runtimeOptionsRequest)));
- } catch (SpRuntimeException e) {
- e.printStackTrace();
+ } catch (SpRuntimeException | SpConfigurationException e) {
return ok(new Response(elementId, false));
}
}
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java
index a32a1decb..110d95eaa 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOptions.java
@@ -17,6 +17,7 @@
*/
package org.apache.streampipes.container.api;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.model.staticproperty.Option;
import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor;
@@ -29,5 +30,5 @@ import java.util.List;
public interface ResolvesContainerProvidedOptions {
List<Option> resolveOptions(String staticPropertyInternalName,
- StaticPropertyExtractor parameterExtractor);
+ StaticPropertyExtractor parameterExtractor) throws SpConfigurationException;
}
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java
index 83ed622b0..ab44539ae 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/ResolvesContainerProvidedOutputStrategy.java
@@ -17,7 +17,7 @@
*/
package org.apache.streampipes.container.api;
-import org.apache.streampipes.commons.exceptions.SpRuntimeException;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.model.base.InvocableStreamPipesEntity;
import org.apache.streampipes.model.schema.EventSchema;
import org.apache.streampipes.sdk.extractor.AbstractParameterExtractor;
@@ -25,5 +25,5 @@ import org.apache.streampipes.sdk.extractor.AbstractParameterExtractor;
public interface ResolvesContainerProvidedOutputStrategy<T extends InvocableStreamPipesEntity, P
extends AbstractParameterExtractor<T>> {
- EventSchema resolveOutputStrategy(T processingElement, P parameterExtractor) throws SpRuntimeException;
+ EventSchema resolveOutputStrategy(T processingElement, P parameterExtractor) throws SpConfigurationException;
}
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java
index aba13222a..91e18f97f 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/RuntimeResolvableRequestHandler.java
@@ -18,6 +18,7 @@
package org.apache.streampipes.container.api;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.model.runtime.RuntimeOptionsRequest;
import org.apache.streampipes.model.runtime.RuntimeOptionsResponse;
import org.apache.streampipes.model.staticproperty.Option;
@@ -31,7 +32,7 @@ public class RuntimeResolvableRequestHandler {
// for backwards compatibility
public RuntimeOptionsResponse handleRuntimeResponse(ResolvesContainerProvidedOptions resolvesOptions,
- RuntimeOptionsRequest req) {
+ RuntimeOptionsRequest req) throws SpConfigurationException {
List<Option> availableOptions =
resolvesOptions.resolveOptions(req.getRequestId(),
makeExtractor(req));
@@ -43,7 +44,7 @@ public class RuntimeResolvableRequestHandler {
}
public RuntimeOptionsResponse handleRuntimeResponse(SupportsRuntimeConfig declarer,
- RuntimeOptionsRequest req) {
+ RuntimeOptionsRequest req) throws SpConfigurationException {
StaticProperty result = declarer.resolveConfiguration(
req.getRequestId(),
makeExtractor(req));
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java b/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java
index 10cacd125..4ebd76854 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java
@@ -18,12 +18,13 @@
package org.apache.streampipes.container.api;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.model.staticproperty.StaticProperty;
import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor;
public interface SupportsRuntimeConfig {
StaticProperty resolveConfiguration(String staticPropertyInternalName,
- StaticPropertyExtractor extractor);
+ StaticPropertyExtractor extractor) throws SpConfigurationException;
}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java
index e4336d842..7145858ea 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/MiloOpcUaConfigurationProvider.java
@@ -18,6 +18,7 @@
package org.apache.streampipes.connect.iiot.adapters.opcua;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.connect.iiot.adapters.opcua.configuration.SpOpcUaConfig;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfigBuilder;
@@ -31,10 +32,11 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.ExecutionException;
public class MiloOpcUaConfigurationProvider {
- public OpcUaClientConfig makeClientConfig(SpOpcUaConfig spOpcConfig) throws Exception {
+ public OpcUaClientConfig makeClientConfig(SpOpcUaConfig spOpcConfig) throws ExecutionException, InterruptedException, SpConfigurationException, URISyntaxException {
String opcServerUrl = spOpcConfig.getOpcServerURL();
List<EndpointDescription> endpoints = DiscoveryClient.getEndpoints(opcServerUrl).get();
String host = opcServerUrl.split("://")[1].split(":")[0];
@@ -43,7 +45,7 @@ public class MiloOpcUaConfigurationProvider {
.stream()
.filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
.findFirst()
- .orElseThrow(() -> new Exception("No endpoint with security policy none"));
+ .orElseThrow(() -> new SpConfigurationException("No endpoint with security policy none"));
tmpEndpoint = updateEndpointUrl(tmpEndpoint, host);
endpoints = Collections.singletonList(tmpEndpoint);
@@ -51,7 +53,7 @@ public class MiloOpcUaConfigurationProvider {
EndpointDescription endpoint = endpoints
.stream()
.filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
- .findFirst().orElseThrow(() -> new Exception("no desired endpoints returned"));
+ .findFirst().orElseThrow(() -> new SpConfigurationException("no desired endpoints returned"));
return buildConfig(endpoint, spOpcConfig);
}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java
index 57039d1ee..76b3df7e2 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/OpcUaAdapter.java
@@ -18,6 +18,7 @@
package org.apache.streampipes.connect.iiot.adapters.opcua;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.connect.adapter.Adapter;
import org.apache.streampipes.connect.adapter.util.PollingSettings;
import org.apache.streampipes.connect.api.exception.AdapterException;
@@ -270,7 +271,8 @@ public class OpcUaAdapter extends PullAdapter implements SupportsRuntimeConfig {
}
@Override
- public StaticProperty resolveConfiguration(String staticPropertyInternalName, StaticPropertyExtractor extractor) {
+ public StaticProperty resolveConfiguration(String staticPropertyInternalName,
+ StaticPropertyExtractor extractor) throws SpConfigurationException {
return OpcUaUtil.resolveConfiguration(staticPropertyInternalName, extractor);
}
}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java
index da00cbf1b..6e7b9af8f 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/SpOpcUaClient.java
@@ -19,12 +19,14 @@
package org.apache.streampipes.connect.iiot.adapters.opcua;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.connect.iiot.adapters.opcua.configuration.SpOpcUaConfig;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.config.OpcUaClientConfig;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaMonitoredItem;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription;
import org.eclipse.milo.opcua.stack.core.AttributeId;
+import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName;
@@ -37,9 +39,11 @@ import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicLong;
import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;
@@ -71,9 +75,9 @@ public class SpOpcUaClient {
/***
* Establishes appropriate connection to OPC UA endpoint depending on the {@link SpOpcUaClient} instance
*
- * @throws Exception An exception occurring during OPC connection
+ * @throws UaException An exception occurring during OPC connection
*/
- public void connect() throws Exception {
+ public void connect() throws UaException, ExecutionException, InterruptedException, SpConfigurationException, URISyntaxException {
OpcUaClientConfig clientConfig = new MiloOpcUaConfigurationProvider().makeClientConfig(spOpcConfig);
this.client = OpcUaClient.create(clientConfig);
client.connect().get();
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/ErrorMessageLd.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/ExceptionMessageExtractor.java
similarity index 61%
rename from streampipes-model/src/main/java/org/apache/streampipes/model/ErrorMessageLd.java
rename to streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/ExceptionMessageExtractor.java
index 091f35b1d..7c1b45396 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/ErrorMessageLd.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/ExceptionMessageExtractor.java
@@ -16,25 +16,23 @@
*
*/
-package org.apache.streampipes.model;
+package org.apache.streampipes.connect.iiot.adapters.opcua.utils;
-import java.util.List;
+import org.eclipse.milo.opcua.stack.core.UaException;
-public class ErrorMessageLd extends MessageLd {
+public class ExceptionMessageExtractor {
- public ErrorMessageLd() {
- super(false);
- }
-
- public ErrorMessageLd(NotificationLd...notifications) {
- super(false, notifications);
- }
-
- public ErrorMessageLd(List<NotificationLd> notifications) {
- super(false, notifications.toArray(new NotificationLd[0]));
- }
-
- public ErrorMessageLd(String elementName, List<NotificationLd> notifications) {
- super(false, notifications, elementName);
- }
+ public static String getDescription(UaException e) {
+ String[] parts = e.getMessage().split(", ");
+ if (parts.length > 1) {
+ String[] kv = parts[1].split("=");
+ if (kv.length > 1) {
+ return kv[1];
+ } else {
+ return parts[1];
+ }
+ } else {
+ return e.getMessage();
+ }
+ }
}
diff --git a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java
index 3bf5430c8..d9f95872f 100644
--- a/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java
+++ b/streampipes-extensions/streampipes-connect-adapters-iiot/src/main/java/org/apache/streampipes/connect/iiot/adapters/opcua/utils/OpcUaUtil.java
@@ -18,6 +18,7 @@
package org.apache.streampipes.connect.iiot.adapters.opcua.utils;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.connect.api.exception.AdapterException;
import org.apache.streampipes.connect.api.exception.ParseException;
import org.apache.streampipes.connect.iiot.adapters.opcua.OpcNode;
@@ -37,170 +38,174 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import java.net.URI;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ExecutionException;
/***
* Collection of several utility functions in context of OPC UA
*/
public class OpcUaUtil {
- /***
- * Ensures server address starts with {@code opc.tcp://}
- * @param serverAddress server address as given by user
- * @return correctly formated server address
- */
- public static String formatServerAddress(String serverAddress) {
+ /***
+ * Ensures server address starts with {@code opc.tcp://}
+ * @param serverAddress server address as given by user
+ * @return correctly formated server address
+ */
+ public static String formatServerAddress(String serverAddress) {
- if (!serverAddress.startsWith("opc.tcp://")) {
- serverAddress = "opc.tcp://" + serverAddress;
- }
-
- return serverAddress;
+ if (!serverAddress.startsWith("opc.tcp://")) {
+ serverAddress = "opc.tcp://" + serverAddress;
}
- /***
- * OPC UA specific implementation of {@link org.apache.streampipes.connect.adapter.Adapter}
- * @param adapterStreamDescription
- * @return guess schema
- * @throws AdapterException
- * @throws ParseException
- */
- public static GuessSchema getSchema(SpecificAdapterStreamDescription adapterStreamDescription)
- throws AdapterException, ParseException {
- GuessSchema guessSchema = new GuessSchema();
- EventSchema eventSchema = new EventSchema();
- List<EventProperty> allProperties = new ArrayList<>();
-
- SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(adapterStreamDescription));
-
- try {
- spOpcUaClient.connect();
- OpcUaNodeBrowser nodeBrowser =
- new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig());
- List<OpcNode> selectedNodes = nodeBrowser.findNodes();
-
- if (!selectedNodes.isEmpty()) {
- for (OpcNode opcNode : selectedNodes) {
- if (opcNode.hasUnitId()) {
- allProperties.add(PrimitivePropertyBuilder
- .create(opcNode.getType(), opcNode.getLabel())
- .label(opcNode.getLabel())
- .measurementUnit(new URI(opcNode.getQudtURI()))
- .build());
- } else {
- allProperties.add(PrimitivePropertyBuilder
- .create(opcNode.getType(), opcNode.getLabel())
- .label(opcNode.getLabel())
- .build());
- }
-
- }
- }
-
- spOpcUaClient.disconnect();
-
- } catch (Exception e) {
- throw new AdapterException("Could not guess schema for opc node: " + e.getMessage(), e.getCause());
+ return serverAddress;
+ }
+
+ /***
+ * OPC UA specific implementation of {@link org.apache.streampipes.connect.adapter.Adapter}
+ * @param adapterStreamDescription
+ * @return guess schema
+ * @throws AdapterException
+ * @throws ParseException
+ */
+ public static GuessSchema getSchema(SpecificAdapterStreamDescription adapterStreamDescription)
+ throws AdapterException, ParseException {
+ GuessSchema guessSchema = new GuessSchema();
+ EventSchema eventSchema = new EventSchema();
+ List<EventProperty> allProperties = new ArrayList<>();
+
+ SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(adapterStreamDescription));
+
+ try {
+ spOpcUaClient.connect();
+ OpcUaNodeBrowser nodeBrowser =
+ new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig());
+ List<OpcNode> selectedNodes = nodeBrowser.findNodes();
+
+ if (!selectedNodes.isEmpty()) {
+ for (OpcNode opcNode : selectedNodes) {
+ if (opcNode.hasUnitId()) {
+ allProperties.add(PrimitivePropertyBuilder
+ .create(opcNode.getType(), opcNode.getLabel())
+ .label(opcNode.getLabel())
+ .measurementUnit(new URI(opcNode.getQudtURI()))
+ .build());
+ } else {
+ allProperties.add(PrimitivePropertyBuilder
+ .create(opcNode.getType(), opcNode.getLabel())
+ .label(opcNode.getLabel())
+ .build());
+ }
+
}
+ }
- eventSchema.setEventProperties(allProperties);
- guessSchema.setEventSchema(eventSchema);
+ spOpcUaClient.disconnect();
- return guessSchema;
+ } catch (Exception e) {
+ throw new AdapterException("Could not guess schema for opc node: " + e.getMessage(), e.getCause());
}
-
- /***
- * OPC UA specific implementation of {@link
- * org.apache.streampipes.container.api.ResolvesContainerProvidedOptions#
- * resolveOptions(String, StaticPropertyExtractor)}.
- * @param internalName The internal name of the Static Property
- * @param parameterExtractor
- * @return {@code List<Option>} with available node names for the given OPC UA configuration
- */
- public static RuntimeResolvableTreeInputStaticProperty
- resolveConfiguration(String internalName,
- StaticPropertyExtractor parameterExtractor) {
-
- RuntimeResolvableTreeInputStaticProperty config = parameterExtractor
- .getStaticPropertyByName(internalName, RuntimeResolvableTreeInputStaticProperty.class);
- // access mode and host/url have to be selected
- try {
- parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.OPC_HOST_OR_URL.name());
- parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.ACCESS_MODE.name());
- } catch (NullPointerException nullPointerException) {
- return config;
- }
-
- SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(parameterExtractor));
- try {
- spOpcUaClient.connect();
- OpcUaNodeBrowser nodeBrowser =
- new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig());
- config.setNodes(nodeBrowser.buildNodeTreeFromOrigin());
- spOpcUaClient.disconnect();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return config;
+ eventSchema.setEventProperties(allProperties);
+ guessSchema.setEventSchema(eventSchema);
+
+ return guessSchema;
+ }
+
+
+ /***
+ * OPC UA specific implementation of {@link
+ * org.apache.streampipes.container.api.ResolvesContainerProvidedOptions#
+ * resolveOptions(String, StaticPropertyExtractor)}.
+ * @param internalName The internal name of the Static Property
+ * @param parameterExtractor to extract parameters from the OPC UA config
+ * @return {@code List<Option>} with available node names for the given OPC UA configuration
+ */
+ public static RuntimeResolvableTreeInputStaticProperty resolveConfiguration(String internalName,
+ StaticPropertyExtractor parameterExtractor) throws SpConfigurationException {
+
+ RuntimeResolvableTreeInputStaticProperty config = parameterExtractor
+ .getStaticPropertyByName(internalName, RuntimeResolvableTreeInputStaticProperty.class);
+ // access mode and host/url have to be selected
+ try {
+ parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.OPC_HOST_OR_URL.name());
+ parameterExtractor.selectedAlternativeInternalId(OpcUaLabels.ACCESS_MODE.name());
+ } catch (NullPointerException nullPointerException) {
+ return config;
}
- public static String getRuntimeNameOfNode(NodeId nodeId) {
- String[] keys = nodeId.getIdentifier().toString().split("\\.");
- String key;
+ SpOpcUaClient spOpcUaClient = new SpOpcUaClient(SpOpcUaConfigBuilder.from(parameterExtractor));
- if (keys.length > 0) {
- key = keys[keys.length - 1];
- } else {
- key = nodeId.getIdentifier().toString();
- }
+ try {
+ spOpcUaClient.connect();
+ OpcUaNodeBrowser nodeBrowser =
+ new OpcUaNodeBrowser(spOpcUaClient.getClient(), spOpcUaClient.getSpOpcConfig());
+ config.setNodes(nodeBrowser.buildNodeTreeFromOrigin());
+ spOpcUaClient.disconnect();
- return key;
+ return config;
+ } catch (UaException e) {
+ throw new SpConfigurationException(ExceptionMessageExtractor.getDescription(e), e);
+ } catch (ExecutionException | InterruptedException | URISyntaxException e) {
+ throw new SpConfigurationException("Could not connect to the OPC UA server with the provided settings", e);
}
+ }
- /**
- * connects to each node individually and updates the data type in accordance to the data from the server.
- *
- * @param opcNodes List of opcNodes where the data type is not determined appropriately
- */
- public static void retrieveDataTypesFromServer(OpcUaClient client, List<OpcNode> opcNodes) throws AdapterException {
-
- for (OpcNode opcNode : opcNodes) {
- try {
- UInteger dataTypeId =
- (UInteger) client.getAddressSpace().getVariableNode(opcNode.getNodeId()).getDataType()
- .getIdentifier();
- OpcUaTypes.getType(dataTypeId);
- opcNode.setType(OpcUaTypes.getType(dataTypeId));
- } catch (UaException e) {
- throw new AdapterException("Could not guess schema for opc node! " + e.getMessage());
- }
- }
+ public static String getRuntimeNameOfNode(NodeId nodeId) {
+ String[] keys = nodeId.getIdentifier().toString().split("\\.");
+ String key;
+
+ if (keys.length > 0) {
+ key = keys[keys.length - 1];
+ } else {
+ key = nodeId.getIdentifier().toString();
}
- /***
- * Enum for all possible labels in the context of OPC UA adapters
- */
- public enum OpcUaLabels {
- OPC_HOST_OR_URL,
- OPC_URL,
- OPC_HOST,
- OPC_SERVER_URL,
- OPC_SERVER_HOST,
- OPC_SERVER_PORT,
- NAMESPACE_INDEX,
- NODE_ID,
- ACCESS_MODE,
- USERNAME_GROUP,
- USERNAME,
- PASSWORD,
- UNAUTHENTICATED,
- AVAILABLE_NODES,
- PULLING_INTERVAL,
- ADAPTER_TYPE,
- PULL_MODE,
- SUBSCRIPTION_MODE;
+ return key;
+ }
+
+ /**
+ * connects to each node individually and updates the data type in accordance to the data from the server.
+ *
+ * @param opcNodes List of opcNodes where the data type is not determined appropriately
+ */
+ public static void retrieveDataTypesFromServer(OpcUaClient client, List<OpcNode> opcNodes) throws AdapterException {
+
+ for (OpcNode opcNode : opcNodes) {
+ try {
+ UInteger dataTypeId =
+ (UInteger) client.getAddressSpace().getVariableNode(opcNode.getNodeId()).getDataType()
+ .getIdentifier();
+ OpcUaTypes.getType(dataTypeId);
+ opcNode.setType(OpcUaTypes.getType(dataTypeId));
+ } catch (UaException e) {
+ throw new AdapterException("Could not guess schema for opc node! " + e.getMessage());
+ }
}
+ }
+
+ /***
+ * Enum for all possible labels in the context of OPC UA adapters
+ */
+ public enum OpcUaLabels {
+ OPC_HOST_OR_URL,
+ OPC_URL,
+ OPC_HOST,
+ OPC_SERVER_URL,
+ OPC_SERVER_HOST,
+ OPC_SERVER_PORT,
+ NAMESPACE_INDEX,
+ NODE_ID,
+ ACCESS_MODE,
+ USERNAME_GROUP,
+ USERNAME,
+ PASSWORD,
+ UNAUTHENTICATED,
+ AVAILABLE_NODES,
+ PULLING_INTERVAL,
+ ADAPTER_TYPE,
+ PULL_MODE,
+ SUBSCRIPTION_MODE;
+ }
}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/MessageLd.java b/streampipes-model/src/main/java/org/apache/streampipes/model/MessageLd.java
deleted file mode 100644
index 61b3cd87c..000000000
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/MessageLd.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.model;
-
-import org.apache.commons.lang3.RandomStringUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class MessageLd {
-
- private static final String prefix = "urn:streampipes.org:spi:";
-
- private String elementId;
-
- private boolean success;
-
- private String elementName;
-
- private List<NotificationLd> notifications;
-
- public MessageLd() {
- this.elementId = prefix
- + this.getClass().getSimpleName().toLowerCase()
- + ":"
- + RandomStringUtils.randomAlphabetic(6);
- this.elementName = "";
- }
-
- public MessageLd(MessageLd other) {
- this();
- this.success = other.isSuccess();
- this.elementName = other.getElementName();
- this.notifications = other.getNotifications();
- }
-
- public MessageLd(boolean success){
- this();
- this.success = success;
- this.notifications = null;
- }
-
- public MessageLd(boolean success, List<NotificationLd> notifications) {
- this();
- this.success = success;
- this.notifications = notifications;
- }
-
- public MessageLd(boolean success, List<NotificationLd> notifications, String elementName) {
- this(success, notifications);
- this.elementName = elementName;
- }
-
-
- public MessageLd(boolean success, NotificationLd...notifications) {
- this();
- this.success = success;
- this.notifications = new ArrayList<>();
- this.notifications.addAll(Arrays.asList(notifications));
- }
-
- public boolean isSuccess() {
- return success;
- }
-
- public void setSuccess(boolean success) {
- this.success = success;
- }
-
- public List<NotificationLd> getNotifications() {
- return notifications;
- }
-
- public void setNotifications(List<NotificationLd> notifications) {
- this.notifications = notifications;
- }
-
- public boolean addNotification(NotificationLd notification)
- {
- return notifications.add(notification);
- }
-
- public String getElementName() {
- return elementName;
- }
-
- public void setElementName(String elementName) {
- this.elementName = elementName;
- }
-
- public String getElementId() {
- return elementId;
- }
-
- public void setElementId(String elementId) {
- this.elementId = elementId;
- }
-
-
-}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/NotificationLd.java b/streampipes-model/src/main/java/org/apache/streampipes/model/NotificationLd.java
deleted file mode 100644
index 7b6b7b89c..000000000
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/NotificationLd.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.streampipes.model;
-
-import org.apache.commons.lang3.RandomStringUtils;
-
-public class NotificationLd {
-
- private static final String prefix = "urn:streampipes.org:spi:";
-
- private String elementId;
-
- private String title;
-
- private String description;
-
- private String additionalInformation;
-
- public NotificationLd() {
- this.elementId = prefix
- + this.getClass().getSimpleName().toLowerCase()
- + ":"
- + RandomStringUtils.randomAlphabetic(6);
- this.additionalInformation = "";
- }
-
- public NotificationLd(NotificationLd other) {
- this();
- this.title = other.getTitle();
- this.description = other.getDescription();
- this.additionalInformation = other.getAdditionalInformation();
- }
-
- public NotificationLd(String title, String description) {
- this();
- this.title = title;
- this.description = description;
- }
-
- public NotificationLd(String title, String description,
- String additionalInformation) {
- this();
- this.title = title;
- this.description = description;
- this.additionalInformation = additionalInformation;
- }
-
- public String getTitle() {
- return title;
- }
-
- public void setTitle(String title) {
- this.title = title;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getAdditionalInformation() {
- return additionalInformation;
- }
-
- public void setAdditionalInformation(String additionalInformation) {
- this.additionalInformation = additionalInformation;
- }
-
- public String getElementId() {
- return elementId;
- }
-
- public void setElementId(String elementId) {
- this.elementId = elementId;
- }
-}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java b/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java
new file mode 100644
index 000000000..d2d964090
--- /dev/null
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/StreamPipesErrorMessage.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.model;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.streampipes.model.shared.annotation.TsModel;
+
+@TsModel
+public class StreamPipesErrorMessage {
+
+ private String level;
+ private String title;
+ private String detail;
+
+ private String cause;
+ private String fullStackTrace;
+
+ public StreamPipesErrorMessage() {
+ }
+
+ public static StreamPipesErrorMessage from(Exception exception) {
+ String cause = exception.getCause() != null ? exception.getCause().getMessage() : exception.getMessage();
+ return new StreamPipesErrorMessage(
+ "error",
+ exception.getMessage(),
+ "",
+ ExceptionUtils.getStackTrace(exception),
+ cause);
+ }
+
+ public StreamPipesErrorMessage(String level,
+ String title,
+ String detail,
+ String fullStackTrace,
+ String cause) {
+ this.level = level;
+ this.title = title;
+ this.detail = detail;
+ this.fullStackTrace = fullStackTrace;
+ this.cause = cause;
+ }
+
+ public String getLevel() {
+ return level;
+ }
+
+ public void setLevel(String level) {
+ this.level = level;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDetail() {
+ return detail;
+ }
+
+ public void setDetail(String detail) {
+ this.detail = detail;
+ }
+
+ public String getFullStackTrace() {
+ return fullStackTrace;
+ }
+
+ public void setFullStackTrace(String fullStackTrace) {
+ this.fullStackTrace = fullStackTrace;
+ }
+
+ public String getCause() {
+ return cause;
+ }
+
+ public void setCause(String cause) {
+ this.cause = cause;
+ }
+}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
index 6593be344..7cdd81281 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/GuessResource.java
@@ -18,12 +18,13 @@
package org.apache.streampipes.rest.impl.connect;
+import org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableException;
import org.apache.streampipes.connect.api.exception.ParseException;
import org.apache.streampipes.connect.api.exception.WorkerAdapterException;
import org.apache.streampipes.connect.container.master.management.GuessManagement;
+import org.apache.streampipes.model.StreamPipesErrorMessage;
import org.apache.streampipes.model.connect.adapter.AdapterDescription;
import org.apache.streampipes.model.connect.guess.GuessSchema;
-import org.apache.streampipes.model.message.Notifications;
import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,6 +34,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import java.io.IOException;
@Path("/v2/connect/master/guess")
@@ -56,12 +58,12 @@ public class GuessResource extends AbstractAdapterResource<GuessManagement> {
return ok(result);
} catch (ParseException e) {
LOG.error("Error while parsing events: ", e);
- return serverError(Notifications.error(e.getMessage()));
+ return badRequest(StreamPipesErrorMessage.from(e));
} catch (WorkerAdapterException e) {
- return serverError(e.getContent());
- } catch (Exception e) {
- LOG.error("Error while guessing the schema for AdapterDescription: {}", e.getMessage());
- return serverError(Notifications.error(e.getMessage()));
+ return serverError(StreamPipesErrorMessage.from(e));
+ } catch (NoServiceEndpointsAvailableException | IOException e) {
+ LOG.error(e.getMessage());
+ return serverError(StreamPipesErrorMessage.from(e));
}
}
}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
index 1db6196b6..5f3fe1f67 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/connect/RuntimeResolvableResource.java
@@ -19,13 +19,17 @@
package org.apache.streampipes.rest.impl.connect;
import org.apache.streampipes.commons.exceptions.NoServiceEndpointsAvailableException;
+import org.apache.streampipes.commons.exceptions.SpConfigurationException;
import org.apache.streampipes.connect.api.exception.AdapterException;
import org.apache.streampipes.connect.container.master.management.WorkerAdministrationManagement;
import org.apache.streampipes.connect.container.master.management.WorkerRestClient;
import org.apache.streampipes.connect.container.master.management.WorkerUrlProvider;
+import org.apache.streampipes.model.StreamPipesErrorMessage;
import org.apache.streampipes.model.runtime.RuntimeOptionsRequest;
import org.apache.streampipes.model.runtime.RuntimeOptionsResponse;
import org.apache.streampipes.rest.shared.annotation.JacksonSerialized;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
@@ -34,6 +38,8 @@ import javax.ws.rs.core.Response;
@Path("/v2/connect/master/resolvable")
public class RuntimeResolvableResource extends AbstractAdapterResource<WorkerAdministrationManagement> {
+ private static final Logger LOG = LoggerFactory.getLogger(RuntimeResolvableResource.class);
+
private final WorkerUrlProvider workerUrlProvider;
public RuntimeResolvableResource() {
@@ -56,11 +62,16 @@ public class RuntimeResolvableResource extends AbstractAdapterResource<WorkerAdm
RuntimeOptionsResponse result = WorkerRestClient.getConfiguration(workerEndpoint, appId, runtimeOptionsRequest);
return ok(result);
- } catch (AdapterException | NoServiceEndpointsAvailableException e) {
- e.printStackTrace();
- return fail();
+ } catch (AdapterException e) {
+ LOG.error("Adapter exception occurred", e);
+ return serverError(StreamPipesErrorMessage.from(e));
+ } catch (NoServiceEndpointsAvailableException e) {
+ LOG.error("Could not find service endpoint for {} while fetching configuration", appId);
+ return serverError(StreamPipesErrorMessage.from(e));
+ } catch (SpConfigurationException e) {
+ LOG.error("Tried to fetch a runtime configuration with insufficient settings");
+ return badRequest(StreamPipesErrorMessage.from(e));
}
-
}
}
diff --git a/ui/package.json b/ui/package.json
index 30e2878f0..5be6f1bb5 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -8,8 +8,8 @@
"url": "https://github.com/apache/incubator-streampipes"
},
"scripts": {
- "build-libs": "ng build @streampipes/shared-ui && ng build @streampipes/platform-services",
- "install-libs": "npm install @streampipes/shared-ui@file:./dist/streampipes/shared-ui @streampipes/platform-services@file:./dist/streampipes/platform-services --no-save",
+ "build-libs": "ng build @streampipes/platform-services && ng build @streampipes/shared-ui",
+ "install-libs": "npm install @streampipes/platform-services@file:./dist/streampipes/platform-services @streampipes/shared-ui@file:./dist/streampipes/shared-ui --no-save",
"build-libraries": "npm run build-libs && npm run install-libs",
"start": "node ./deployment/prebuild.js && npm run build-libraries && ng serve",
"test": "node ./deployment/prebuild.js && npm run build-libraries && ng test",
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index c4f9a582e..24ebb69e4 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -18,7 +18,7 @@
/* tslint:disable */
/* eslint-disable */
// @ts-nocheck
-// Generated using typescript-generator version 2.27.744 on 2022-08-01 10:55:40.
+// Generated using typescript-generator version 2.27.744 on 2022-08-14 22:39:25.
export class AbstractStreamPipesEntity {
"@class": "org.apache.streampipes.model.base.AbstractStreamPipesEntity" | "org.apache.streampipes.model.base.NamedStreamPipesEntity" | "org.apache.streampipes.model.connect.adapter.AdapterDescription" | "org.apache.streampipes.model.connect.adapter.AdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.GenericAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.SpecificAdapterSetDescription" | "org.apache.streampipes.model.connect.adapter.AdapterStre [...]
@@ -192,9 +192,9 @@ export class AdapterDescription extends NamedStreamPipesEntity {
instance.selectedEndpointUrl = data.selectedEndpointUrl;
instance.correspondingServiceGroup = data.correspondingServiceGroup;
instance.correspondingDataStreamElementId = data.correspondingDataStreamElementId;
+ instance.streamRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.streamRules);
instance.schemaRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.schemaRules);
instance.valueRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.valueRules);
- instance.streamRules = __getCopyArrayFn(TransformationRuleDescription.fromDataUnion)(data.streamRules);
return instance;
}
@@ -987,11 +987,14 @@ export class DataExplorerWidgetModel extends DashboardEntity {
export class DataLakeMeasure extends UnnamedStreamPipesEntity {
"@class": "org.apache.streampipes.model.datalake.DataLakeMeasure";
+ _rev: string;
eventSchema: EventSchema;
measureName: string;
pipelineId: string;
pipelineIsRunning: boolean;
pipelineName: string;
+ schemaVersion: string;
+ timestampField: string;
static fromData(data: DataLakeMeasure, target?: DataLakeMeasure): DataLakeMeasure {
if (!data) {
@@ -1000,10 +1003,13 @@ export class DataLakeMeasure extends UnnamedStreamPipesEntity {
const instance = target || new DataLakeMeasure();
super.fromData(data, instance);
instance.measureName = data.measureName;
+ instance.timestampField = data.timestampField;
instance.eventSchema = EventSchema.fromData(data.eventSchema);
instance.pipelineId = data.pipelineId;
instance.pipelineName = data.pipelineName;
instance.pipelineIsRunning = data.pipelineIsRunning;
+ instance.schemaVersion = data.schemaVersion;
+ instance._rev = data._rev;
return instance;
}
}
@@ -2561,8 +2567,8 @@ export class PipelineTemplateDescription extends NamedStreamPipesEntity {
const instance = target || new PipelineTemplateDescription();
super.fromData(data, instance);
instance.boundTo = __getCopyArrayFn(BoundPipelineElement.fromData)(data.boundTo);
- instance.pipelineTemplateName = data.pipelineTemplateName;
instance.pipelineTemplateId = data.pipelineTemplateId;
+ instance.pipelineTemplateName = data.pipelineTemplateName;
instance.pipelineTemplateDescription = data.pipelineTemplateDescription;
return instance;
}
@@ -2964,8 +2970,8 @@ export class SpDataSet extends SpDataStream {
instance.datasetInvocationId = data.datasetInvocationId;
instance.correspondingPipeline = data.correspondingPipeline;
instance.selectedEndpointUrl = data.selectedEndpointUrl;
- instance.brokerHostname = data.brokerHostname;
instance.actualTopicName = data.actualTopicName;
+ instance.brokerHostname = data.brokerHostname;
return instance;
}
}
@@ -3105,6 +3111,27 @@ export class StreamPipesApplicationPackage {
}
}
+export class StreamPipesErrorMessage {
+ cause: string;
+ detail: string;
+ fullStackTrace: string;
+ level: string;
+ title: string;
+
+ static fromData(data: StreamPipesErrorMessage, target?: StreamPipesErrorMessage): StreamPipesErrorMessage {
+ if (!data) {
+ return data;
+ }
+ const instance = target || new StreamPipesErrorMessage();
+ instance.level = data.level;
+ instance.title = data.title;
+ instance.detail = data.detail;
+ instance.cause = data.cause;
+ instance.fullStackTrace = data.fullStackTrace;
+ return instance;
+ }
+}
+
export class SuccessMessage extends Message {
static fromData(data: SuccessMessage, target?: SuccessMessage): SuccessMessage {
diff --git a/ui/projects/streampipes/shared-ui/package.json b/ui/projects/streampipes/shared-ui/package.json
index a602da9ba..8a55c7fd6 100644
--- a/ui/projects/streampipes/shared-ui/package.json
+++ b/ui/projects/streampipes/shared-ui/package.json
@@ -9,6 +9,7 @@
"@angular/flex-layout": "^13.0.0-beta.38",
"@angular/material": "^13.3.0",
"@angular/router": "^13.3.0",
+ "@streampipes/platform-services": "0.0.1",
"rxjs": "^6.6.2"
},
"dependencies": {
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.html
new file mode 100644
index 000000000..3ed79a1df
--- /dev/null
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.html
@@ -0,0 +1,43 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<div class="sp-dialog-container">
+ <div class="sp-dialog-content p-20">
+ <div fxFlex="100" fxLayout="column" class="mt-10">
+ <div class="error-details-title">Probable cause</div>
+ <div class="log-message" [innerText]="message.cause">
+ </div>
+ <div class="mt-10">
+ <button mat-button color="accent" (click)="showDetails = !showDetails">Full details</button>
+ </div>
+ <div fxFlex="100" fxLayout="column" *ngIf="showDetails" class="mt-10">
+ <div class="error-details-title">Full stack trace</div>
+ <div class="log-message">
+ <div [innerText]="message.fullStackTrace"></div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ <mat-divider></mat-divider>
+ <div class="sp-dialog-actions actions-align-right">
+ <button mat-button mat-raised-button class="mat-basic" (click)="close()">
+ Close
+ </button>
+ </div>
+</div>
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.scss
similarity index 63%
copy from ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
copy to ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.scss
index 4e64c258c..c3e663fc4 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.scss
@@ -16,23 +16,30 @@
*
*/
-import { Component, Input, OnInit } from '@angular/core';
-import { Notification } from '@streampipes/platform-services';
-
-@Component({
- selector: 'sp-error-message',
- templateUrl: './error-message.component.html',
- styleUrls: ['./error-message.component.scss']
-})
-export class ErrorMessageComponent implements OnInit {
-
- @Input() errorMessages: Notification[];
-
- showErrorMessage = false;
+.log-message {
+ background-color: black;
+ font: 9pt Inconsolata, monospace;
+ text-shadow: 0 0 5px #C8C8C8;
+ color: white;
+ padding: 10px;
+ max-width: 100%;
+ max-height: 300px;
+ overflow-y: scroll;
+ white-space: pre-wrap;
+}
- constructor() { }
+.error-details-title {
+ font-size: 13pt;
+ font-weight: var(--color-default-text);
+ border-left: 3px solid var(--color-accent);
+ padding-left: 10px;
+ margin-bottom: 15px;
+}
- ngOnInit(): void {
- }
+.mt-10 {
+ margin-top: 10px;
+}
+.p-20 {
+ padding: 20px;
}
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.ts
similarity index 56%
copy from ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
copy to ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.ts
index 4e64c258c..28eef5829 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component.ts
@@ -16,23 +16,28 @@
*
*/
-import { Component, Input, OnInit } from '@angular/core';
-import { Notification } from '@streampipes/platform-services';
+import { Component, Input } from '@angular/core';
+import { StreamPipesErrorMessage } from '@streampipes/platform-services';
+import { DialogRef } from '../../../dialog/base-dialog/dialog-ref';
@Component({
- selector: 'sp-error-message',
- templateUrl: './error-message.component.html',
- styleUrls: ['./error-message.component.scss']
+ selector: 'sp-exception-details-dialog',
+ templateUrl: './exception-details-dialog.component.html',
+ styleUrls: ['./exception-details-dialog.component.scss', '../../../../../../../../src/scss/sp/sp-dialog.scss']
})
-export class ErrorMessageComponent implements OnInit {
+export class SpExceptionDetailsDialogComponent {
- @Input() errorMessages: Notification[];
+ @Input()
+ message: StreamPipesErrorMessage;
- showErrorMessage = false;
+ showDetails = false;
- constructor() { }
+ constructor(private dialogRef: DialogRef<SpExceptionDetailsDialogComponent>) {
- ngOnInit(): void {
+ }
+
+ close() {
+ this.dialogRef.close();
}
}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.html b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.html
new file mode 100644
index 000000000..46238bfc4
--- /dev/null
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.html
@@ -0,0 +1,38 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<div fxLayout="column" fxFlex="100" class="error-panel error">
+ <div fxLayout="row">
+ <div fxFlex="100" fxLayoutAlign="start center">
+ <div fxLayout="row" fxLayoutAlign="start center" class="p-5" fxFlex="100">
+ <div fxLayoutAlign="start center">
+ <i class="material-icons color-warn" style="margin-right: 15px;">warning</i>
+ <h5 fxFlex class="color-warn">{{message.title}}</h5>
+ </div>
+ <span fxFlex></span>
+ <div fxLayoutAlign="end center" *ngIf="showDetails">
+ <button mat-button (click)="openDetailsDialog()">
+ <i class="material-icons">visibility</i> Details
+ </button>
+ </div>
+ </div>
+
+ </div>
+ </div>
+
+</div>
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.scss
similarity index 68%
copy from streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java
copy to ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.scss
index 10cacd125..15a00db00 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/api/SupportsRuntimeConfig.java
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.scss
@@ -16,14 +16,15 @@
*
*/
-package org.apache.streampipes.container.api;
-
-import org.apache.streampipes.model.staticproperty.StaticProperty;
-import org.apache.streampipes.sdk.extractor.StaticPropertyExtractor;
-
-public interface SupportsRuntimeConfig {
+.error-panel {
+ background: var(--color-bg-1);
+ border-radius: 5px;
+}
- StaticProperty resolveConfiguration(String staticPropertyInternalName,
- StaticPropertyExtractor extractor);
+.error {
+ border: 1px solid var(--color-warn);
+}
+.color-warn {
+ color: var(--color-warn);
}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.ts b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.ts
new file mode 100644
index 000000000..2d78e1b02
--- /dev/null
+++ b/ui/projects/streampipes/shared-ui/src/lib/components/sp-exception-message/sp-exception-message.component.ts
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, Input } from '@angular/core';
+import { StreamPipesErrorMessage } from '@streampipes/platform-services';
+import { DialogService } from '../../dialog/base-dialog/base-dialog.service';
+import { PanelType } from '../../dialog/base-dialog/base-dialog.model';
+import { SpExceptionDetailsDialogComponent } from './exception-details-dialog/exception-details-dialog.component';
+
+@Component({
+ selector: 'sp-exception-message',
+ templateUrl: './sp-exception-message.component.html',
+ styleUrls: ['./sp-exception-message.component.scss']
+})
+export class SpExceptionMessageComponent {
+
+ @Input()
+ level = 'error';
+
+ @Input()
+ showDetails = true;
+
+ @Input()
+ message: StreamPipesErrorMessage;
+
+ constructor(private dialogService: DialogService) {
+
+ }
+
+ openDetailsDialog() {
+ this.dialogService.open(SpExceptionDetailsDialogComponent, {
+ panelType: PanelType.STANDARD_PANEL,
+ width: '80vw',
+ title: 'Error Details',
+ data: {
+ 'message': this.message
+ }
+ });
+ }
+
+}
diff --git a/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts b/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts
index d69664dd2..8e40ee51f 100644
--- a/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts
+++ b/ui/projects/streampipes/shared-ui/src/lib/shared-ui.module.ts
@@ -32,6 +32,9 @@ import { SpBasicNavTabsComponent } from './components/basic-nav-tabs/basic-nav-t
import { MatTabsModule } from '@angular/material/tabs';
import { SpBasicInnerPanelComponent } from './components/basic-inner-panel/basic-inner-panel.component';
import { SpBasicHeaderTitleComponent } from './components/basic-header-title/header-title.component';
+import { SpExceptionMessageComponent } from './components/sp-exception-message/sp-exception-message.component';
+import { SpExceptionDetailsDialogComponent } from './components/sp-exception-message/exception-details-dialog/exception-details-dialog.component';
+import { MatDividerModule } from '@angular/material/divider';
@NgModule({
declarations: [
@@ -41,12 +44,15 @@ import { SpBasicHeaderTitleComponent } from './components/basic-header-title/hea
SpBasicInnerPanelComponent,
SpBasicHeaderTitleComponent,
SpBasicViewComponent,
- SpBasicNavTabsComponent
+ SpBasicNavTabsComponent,
+ SpExceptionMessageComponent,
+ SpExceptionDetailsDialogComponent
],
imports: [
CommonModule,
FlexLayoutModule,
MatButtonModule,
+ MatDividerModule,
MatIconModule,
MatTabsModule,
MatTooltipModule,
@@ -61,6 +67,8 @@ import { SpBasicHeaderTitleComponent } from './components/basic-header-title/hea
SpBasicHeaderTitleComponent,
SpBasicViewComponent,
SpBasicNavTabsComponent,
+ SpExceptionMessageComponent,
+ SpExceptionDetailsDialogComponent
]
})
export class SharedUiModule {
diff --git a/ui/projects/streampipes/shared-ui/src/public-api.ts b/ui/projects/streampipes/shared-ui/src/public-api.ts
index 41e289808..a19dfd5af 100644
--- a/ui/projects/streampipes/shared-ui/src/public-api.ts
+++ b/ui/projects/streampipes/shared-ui/src/public-api.ts
@@ -30,6 +30,8 @@ export * from './lib/components/basic-header-title/header-title.component';
export * from './lib/components/basic-inner-panel/basic-inner-panel.component';
export * from './lib/components/basic-view/basic-view.component';
export * from './lib/components/basic-nav-tabs/basic-nav-tabs.component';
+export * from './lib/components/sp-exception-message/sp-exception-message.component';
+export * from './lib/components/sp-exception-message/exception-details-dialog/exception-details-dialog.component';
export * from './lib/models/sp-navigation.model';
diff --git a/ui/src/app/connect/components/new-adapter/new-adapter.component.ts b/ui/src/app/connect/components/new-adapter/new-adapter.component.ts
index 1cdee14b4..2a0566e89 100644
--- a/ui/src/app/connect/components/new-adapter/new-adapter.component.ts
+++ b/ui/src/app/connect/components/new-adapter/new-adapter.component.ts
@@ -176,7 +176,6 @@ export class NewAdapterComponent implements OnInit, AfterViewInit {
clickSpecificSettingsNextButton() {
this.shepherdService.trigger('specific-settings-next-button');
- console.log(this.adapter);
this.guessEventSchema();
this.goForward();
}
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.html
index 8172ea552..ecfdf152a 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.html
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.html
@@ -17,22 +17,10 @@
-->
<div fxLayout="column" fxFlex="100">
- <div fxLayout="row" fxLayoutAlign="center center" class="error-color" fxFlex="100">
- <mat-icon fxLayoutAlign="start center">warning</mat-icon>
- <div fxLayoutAlign="start center" class="error-text"> Sorry, there was an error while guessing the schema of your configured data source...</div>
+ <div fxLayout="row" fxLayoutAlign="center center" fxFlex="100">
+ <div fxLayoutAlign="start center" class="error-text"> There was an error while guessing the schema of your configured data source:</div>
</div>
<div fxLayout="row" fxLayoutAlign="center center" class="mt-10">
- <button mat-button color="accent">
- <div *ngIf="!showErrorMessage" (click)="showErrorMessage = true">Show Details</div>
- <div *ngIf="showErrorMessage" (click)="showErrorMessage = false">Hide Details</div>
- </button>
- </div>
- <div fxLayoutAlign="center center" *ngIf="showErrorMessage">
- <div class="error-message">
- <div *ngFor="let error of errorMessages" style="margin-bottom: 5px; margin-top: 5px">
- <div>{{error.title}}</div>
- <div>{{error.description}}</div>
- </div>
- </div>
+ <sp-exception-message [message]="errorMessage"></sp-exception-message>
</div>
</div>
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
index 4e64c258c..b6dc01d70 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/error-message/error-message.component.ts
@@ -18,6 +18,7 @@
import { Component, Input, OnInit } from '@angular/core';
import { Notification } from '@streampipes/platform-services';
+import { StreamPipesErrorMessage } from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
@Component({
selector: 'sp-error-message',
@@ -26,7 +27,7 @@ import { Notification } from '@streampipes/platform-services';
})
export class ErrorMessageComponent implements OnInit {
- @Input() errorMessages: Notification[];
+ @Input() errorMessage: StreamPipesErrorMessage;
showErrorMessage = false;
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html
index 163fbb730..6e85d424f 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.html
@@ -72,7 +72,7 @@
<sp-loading-message *ngIf="isLoading"></sp-loading-message>
<sp-error-message
- [errorMessages]="errorMessages"
+ [errorMessage]="errorMessage"
*ngIf="isError">
</sp-error-message>
diff --git a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
index 6ad0b7299..5ca2b4e58 100644
--- a/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
+++ b/ui/src/app/connect/components/new-adapter/schema-editor/event-schema/event-schema.component.ts
@@ -32,6 +32,7 @@ import {
} from '@streampipes/platform-services';
import { MatStepper } from '@angular/material/stepper';
import { UserErrorMessage } from '../../../../../core-model/base/UserErrorMessage';
+import { StreamPipesErrorMessage } from '../../../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
@Component({
selector: 'sp-event-schema',
@@ -73,7 +74,7 @@ export class EventSchemaComponent implements OnChanges {
isLoading = false;
isError = false;
isPreviewEnabled = false;
- errorMessages: Notification[];
+ errorMessage: StreamPipesErrorMessage;
nodes: EventProperty[] = new Array<EventProperty>();
validEventSchema = false;
schemaErrorHints: UserErrorMessage[] = [];
@@ -117,7 +118,7 @@ export class EventSchemaComponent implements OnChanges {
this.isLoading = false;
},
errorMessage => {
- this.errorMessages = errorMessage.error.notifications;
+ this.errorMessage = errorMessage.error;
this.isError = true;
this.isLoading = false;
this.eventSchema = new EventSchema();
diff --git a/ui/src/app/connect/connect.module.ts b/ui/src/app/connect/connect.module.ts
index e7e324795..1b23c969c 100644
--- a/ui/src/app/connect/connect.module.ts
+++ b/ui/src/app/connect/connect.module.ts
@@ -123,7 +123,8 @@ import { SpAdapterTemplateDialogComponent } from './dialog/adapter-template/adap
SharedUiModule
],
exports: [
- PipelineElementRuntimeInfoComponent
+ PipelineElementRuntimeInfoComponent,
+ ErrorMessageComponent
],
declarations: [
AdapterDescriptionComponent,
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts
index b24bc7afa..c1589be9e 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-any-input/static-runtime-resolvable-any-input.component.ts
@@ -53,4 +53,7 @@ export class StaticRuntimeResolvableAnyInputComponent
return staticProperty as RuntimeResolvableAnyStaticProperty;
}
+ afterErrorReceived() {
+ }
+
}
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts
index 229beba9b..b2f33e393 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-input/base-runtime-resolvable-input.ts
@@ -30,6 +30,7 @@ import { RuntimeResolvableService } from './runtime-resolvable.service';
import { Observable } from 'rxjs';
import { Directive, Input, OnChanges, SimpleChanges } from '@angular/core';
import { ConfigurationInfo } from '../../../connect/model/ConfigurationInfo';
+import { StreamPipesErrorMessage } from '../../../../../projects/streampipes/platform-services/src/lib/model/gen/streampipes-model';
@Directive()
// tslint:disable-next-line:directive-class-suffix
@@ -43,6 +44,8 @@ export abstract class BaseRuntimeResolvableInput<T
showOptions = false;
loading = false;
+ error = false;
+ errorMessage: StreamPipesErrorMessage;
dependentStaticProperties: any = new Map();
constructor(private runtimeResolvableService: RuntimeResolvableService) {
@@ -70,6 +73,8 @@ export abstract class BaseRuntimeResolvableInput<T
this.showOptions = false;
this.loading = true;
+ this.error = false;
+ this.errorMessage = undefined;
const observable: Observable<RuntimeOptionsResponse> = this.adapterId ?
this.runtimeResolvableService.fetchRemoteOptionsForAdapter(resolvableOptionsParameterRequest, this.adapterId) :
this.runtimeResolvableService.fetchRemoteOptionsForPipelineElement(resolvableOptionsParameterRequest);
@@ -80,6 +85,12 @@ export abstract class BaseRuntimeResolvableInput<T
}
this.loading = false;
this.showOptions = true;
+ }, errorMessage => {
+ this.loading = false;
+ this.showOptions = true;
+ this.error = true;
+ this.errorMessage = errorMessage.error as StreamPipesErrorMessage;
+ this.afterErrorReceived();
});
}
@@ -107,4 +118,6 @@ export abstract class BaseRuntimeResolvableInput<T
abstract afterOptionsLoaded(staticProperty: T);
+ abstract afterErrorReceived();
+
}
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts
index a6c12b1d6..cae01d7c1 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-oneof-input/static-runtime-resolvable-oneof-input.component.ts
@@ -54,4 +54,7 @@ export class StaticRuntimeResolvableOneOfInputComponent
parse(staticProperty: StaticPropertyUnion): RuntimeResolvableOneOfStaticProperty {
return staticProperty as RuntimeResolvableOneOfStaticProperty;
}
+
+ afterErrorReceived() {
+ }
}
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html
index c9216e29c..49e036de3 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.html
@@ -29,6 +29,9 @@
[mode]="'indeterminate'"
[diameter]="20"></mat-spinner>
</div>
+ <div fxLayout="column" *ngIf="error" class="mt-10">
+ <sp-exception-message [message]="errorMessage"></sp-exception-message>
+ </div>
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="sp-tree">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
<mat-checkbox color="accent"
diff --git a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts
index 3be93789f..cb2fa1883 100644
--- a/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts
+++ b/ui/src/app/core-ui/static-properties/static-runtime-resolvable-tree-input/static-tree-input.component.ts
@@ -26,6 +26,7 @@ import {
import { RuntimeResolvableService } from '../static-runtime-resolvable-input/runtime-resolvable.service';
import { NestedTreeControl } from '@angular/cdk/tree';
import { MatTreeNestedDataSource } from '@angular/material/tree';
+import { AbstractControl, FormControl, ValidationErrors, ValidatorFn } from '@angular/forms';
@Component({
selector: 'sp-runtime-resolvable-tree-input',
@@ -55,6 +56,7 @@ export class StaticRuntimeResolvableTreeInputComponent
this.showOptions = true;
}
super.onInit();
+ this.parentForm.addControl(this.staticProperty.internalName, new FormControl(this.staticProperty.nodes, []));
}
parse(staticProperty: StaticPropertyUnion): RuntimeResolvableTreeInputStaticProperty {
@@ -64,10 +66,12 @@ export class StaticRuntimeResolvableTreeInputComponent
afterOptionsLoaded(staticProperty: RuntimeResolvableTreeInputStaticProperty) {
this.staticProperty.nodes = staticProperty.nodes;
this.dataSource.data = this.staticProperty.nodes;
+ this.performValidation();
}
toggleNodeSelection(node: TreeInputNode) {
node.selected = !node.selected;
+ this.performValidation();
}
toggleAllNodeSelection(node: any) {
@@ -75,6 +79,7 @@ export class StaticRuntimeResolvableTreeInputComponent
const newState = !node.selected;
node.selected = newState;
descendants.forEach(d => d.selected = newState);
+ this.performValidation();
}
descendantsAllSelected(node: TreeInputNode) {
@@ -93,4 +98,30 @@ export class StaticRuntimeResolvableTreeInputComponent
return result && !this.descendantsAllSelected(node);
}
+ performValidation() {
+ let error = {error: true};
+ if (this.anyNodeSelected()) {
+ error = undefined;
+ }
+ this.parentForm.controls[this.staticProperty.internalName].setErrors(error);
+ }
+
+ anyNodeSelected(): boolean {
+ return this.dataSource.data.find(d => this.anySelected(d)) !== undefined;
+ }
+
+ anySelected(node: TreeInputNode): boolean {
+ if (node.selected) {
+ return true;
+ } else {
+ return node.children.find(n => this.anySelected(n)) !== undefined;
+ }
+ }
+
+ afterErrorReceived() {
+ this.staticProperty.nodes = [];
+ this.dataSource.data = [];
+ this.performValidation();
+ }
+
}