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/15 12:48:27 UTC

[incubator-streampipes] branch STREAMPIPES-577 created (now 2b924ab56)

This is an automated email from the ASF dual-hosted git repository.

riemer pushed a change to branch STREAMPIPES-577
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git


      at 2b924ab56 [STREAMPIPES-577] Improve error handling in StreamPipes Connect

This branch includes the following new commits:

     new 2c1c82f5d [hotfix] Improve x axis representation of line chart
     new 2b924ab56 [STREAMPIPES-577] Improve error handling in StreamPipes Connect

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[incubator-streampipes] 02/02: [STREAMPIPES-577] Improve error handling in StreamPipes Connect

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch STREAMPIPES-577
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit 2b924ab5667e7b8d32aead1960e20f630f601598
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>&nbsp;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">&nbsp;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">&nbsp;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();
+  }
+
 }


[incubator-streampipes] 01/02: [hotfix] Improve x axis representation of line chart

Posted by ri...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch STREAMPIPES-577
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git

commit 2c1c82f5dec57cca780bc92b62953d128cda763e
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Mon Aug 15 13:09:19 2022 +0200

    [hotfix] Improve x axis representation of line chart
---
 .../dashboard/components/widgets/base/base-ngx-line-charts-widget.ts   | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts
index 94fef221b..55d608560 100644
--- a/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts
+++ b/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts
@@ -63,8 +63,9 @@ export abstract class BaseNgxLineChartsStreamPipesWidget extends BaseNgxChartsSt
     }
 
     timestampTickFormatting(timestamp: any): string {
+        const padL = (nr, len = 2, chr = `0`) => `${nr}`.padStart(2, chr);
         const date = new Date(timestamp);
-        return date.getHours() + ':' + date.getMinutes().toString().substr(-2) + ':' + date.getSeconds().toString().substr(-2);
+        return date.getHours() + ':' + `${padL(date.getMinutes())}` + ':' + `${padL(date.getSeconds())}`;
     }
 
     protected getQueryLimit(extractor: StaticPropertyExtractor): number {