streampipes-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t..@apache.org
Subject [incubator-streampipes] 01/01: [STREAMPIPES-17] WIP Connect Assets - create endpoints for assets - Connect-UI gets icon from connect-container - support locals for Adapter/Protocols - starts to update Adapters/Protocol with assets and locals
Date Wed, 08 Jan 2020 14:44:15 GMT
This is an automated email from the ASF dual-hosted git repository.

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

commit eda23a8072f1ebbf2b60f8e10e6749896186362f
Author: tex <tex@fzi.de>
AuthorDate: Wed Jan 8 15:43:30 2020 +0100

    [STREAMPIPES-17] WIP Connect Assets
    - create endpoints for assets
    - Connect-UI gets icon from connect-container
    - support locals for Adapter/Protocols
    - starts to update Adapters/Protocol with assets and locals
---
 .../master/management/DescriptionManagement.java   |  34 ++
 .../master/management/WorkerRestClient.java        |  79 +++-
 .../container/master/rest/DescriptionResource.java |  78 ++++
 .../worker/init/AdapterWorkerContainer.java        |  34 +-
 .../init/AdapterWorkerContainerResourceConfig.java |   4 +
 .../worker/management/AdapterWorkerManagement.java |  12 +-
 .../container/worker/rest/AdapterResource.java     |  74 ++++
 .../container/worker/rest/ProtocolResource.java    |  74 ++++
 .../connect/management/AdapterUtils.java           |   4 +-
 .../container/locales/LabelGenerator.java          |  64 ++-
 .../streampipes/container/util/AssetsUtil.java     |  34 ++
 .../builder/adapter/AdapterDescriptionBuilder.java |   5 +
 .../adapter/ProtocolDescriptionBuilder.java        |  14 +-
 .../adapter/SpecificDataSetAdapterBuilder.java     |  13 +
 .../adapter/SpecificDataStreamAdapterBuilder.java  |  15 +
 .../adapter-description.component.html             | 148 +++----
 .../adapter-description.component.ts               | 255 +++++------
 .../data-marketplace/data-marketplace.service.ts   | 482 +++++++++++----------
 .../connect/model/connect/AdapterDescription.ts    |  13 +
 .../connect/new-adapter/new-adapter.component.html |   2 +-
 .../protocol-component/protocol.component.html     |   2 +-
 21 files changed, 975 insertions(+), 465 deletions(-)

diff --git a/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/DescriptionManagement.java b/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/DescriptionManagement.java
index 6f698b5..d78a493 100644
--- a/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/DescriptionManagement.java
+++ b/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/DescriptionManagement.java
@@ -19,9 +19,12 @@
 package org.apache.streampipes.connect.container.master.management;
 
 import org.apache.streampipes.connect.adapter.AdapterRegistry;
+import org.apache.streampipes.connect.adapter.exception.AdapterException;
 import org.apache.streampipes.connect.adapter.model.generic.Format;
+import org.apache.streampipes.model.connect.adapter.AdapterDescription;
 import org.apache.streampipes.model.connect.adapter.AdapterDescriptionList;
 import org.apache.streampipes.model.connect.grounding.FormatDescriptionList;
+import org.apache.streampipes.model.connect.grounding.ProtocolDescription;
 import org.apache.streampipes.model.connect.grounding.ProtocolDescriptionList;
 import org.apache.streampipes.model.connect.worker.ConnectWorkerContainer;
 import org.apache.streampipes.storage.couchdb.impl.ConnectionWorkerContainerStorageImpl;
@@ -70,4 +73,35 @@ public class DescriptionManagement {
 
         return result;
     }
+
+    public AdapterDescription getAdapter(String id) throws AdapterException {
+        return getAdapters().getList().stream()
+                .filter(desc -> desc.getAppId().equals(id))
+                .findFirst()
+                .orElseThrow(AdapterException::new);
+    }
+
+    public String getAdapterAssets(AdapterDescription desc, String baseUrl) throws AdapterException {
+        return WorkerRestClient.getAdapterAssets(baseUrl, desc);
+    }
+
+    public byte[] getAdapterIconAsset(AdapterDescription desc, String baseUrl) throws AdapterException {
+        return WorkerRestClient.getAdapterIconAsset(baseUrl, desc);
+    }
+
+    public String getAdapterDocumentationAsset(AdapterDescription desc, String baseUrl) throws AdapterException {
+        return WorkerRestClient.getAdapterDocumentationAsset(baseUrl, desc);
+    }
+
+    public String getProtocolAssets(AdapterDescription desc, String baseUrl) throws AdapterException {
+        return WorkerRestClient.getProtocolAssets(baseUrl, desc);
+    }
+
+    public byte[] getProtocolIconAsset(AdapterDescription desc, String baseUrl) throws AdapterException {
+        return WorkerRestClient.getProtocolIconAsset(baseUrl, desc);
+    }
+
+    public String getProtocolDocumentationAsset(AdapterDescription desc, String baseUrl) throws AdapterException {
+        return WorkerRestClient.getProtocolDocumentationAsset(baseUrl, desc);
+    }
 }
diff --git a/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/WorkerRestClient.java b/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/WorkerRestClient.java
index 373ab00..023f96f 100644
--- a/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/WorkerRestClient.java
+++ b/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/management/WorkerRestClient.java
@@ -212,7 +212,7 @@ public class WorkerRestClient {
 
     public static void deleteFileFromWorker(String baseUrl, String fileName) throws AdapterException {
         String url = baseUrl + "worker/file/" + fileName;
-        logger.info("Trying to delete filefrom endpoint: " + url);
+        logger.info("Trying to delete file from endpoint: " + url);
 
         try {
             int statusCode = Request.Delete(url)
@@ -232,7 +232,82 @@ public class WorkerRestClient {
         }
     }
 
-   private static AdapterDescription getAdapterDescriptionById(AdapterStorageImpl adapterStorage, String id) {
+    public static String getAdapterAssets(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        return getAssets(baseUrl + "worker/adapters", ad);
+    }
+
+    public static String getProtocolAssets(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        return getAssets(baseUrl + "worker/protocol", ad);
+    }
+
+    private static String getAssets(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        String url = baseUrl + "/" + ad.getAppId() + "/assets";
+        logger.info("Trying to Assets from endpoint: " + url + " for adapter: " + ad.getId());
+
+        try {
+            String responseString = Request.Get(url)
+                    .connectTimeout(1000)
+                    .socketTimeout(100000)
+                    .execute().returnContent().asString();
+            return responseString;
+        } catch (IOException e) {
+            logger.error(e.getMessage());
+            throw new AdapterException("Could not get assets endpoint: " + url + " for adapter: " + ad.getId());
+        }
+
+    }
+
+    public static byte[] getAdapterIconAsset(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        return getIconAsset(baseUrl + "worker/adapters", ad);
+    }
+
+    public static byte[] getProtocolIconAsset(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        return getIconAsset(baseUrl + "worker/protocols", ad);
+
+    }
+
+    private static byte[] getIconAsset(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        String url = baseUrl + "/" + ad.getAppId() + "/assets/icon";
+        logger.info("Trying to Icon from endpoint: " + url);
+
+        try {
+            byte[] responseString = Request.Get(url)
+                    .connectTimeout(1000)
+                    .socketTimeout(100000)
+                    .execute().returnContent().asBytes();
+            return responseString;
+        } catch (IOException e) {
+            logger.error(e.getMessage());
+            throw new AdapterException("Could not get icon endpoint: " + url);
+        }
+    }
+
+    public static String getAdapterDocumentationAsset(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        return getDocumentationAsset(baseUrl + "worker/adapters", ad);
+    }
+
+    public static String getProtocolDocumentationAsset(String baseUrl,  AdapterDescription ad) throws AdapterException {
+        return getDocumentationAsset(baseUrl + "worker/protocols", ad);
+    }
+
+    private static String getDocumentationAsset(String baseUrl,  AdapterDescription ad) throws AdapterException  {
+        String url = baseUrl + "/" + ad.getAppId() + "/assets/documentation";
+        logger.info("Trying to documentation from endpoint: " + url);
+
+        try {
+            String responseString = Request.Get(url)
+                    .connectTimeout(1000)
+                    .socketTimeout(100000)
+                    .execute().returnContent().asString();
+            return responseString;
+        } catch (IOException e) {
+            logger.error(e.getMessage());
+            throw new AdapterException("Could not get documentation endpoint: " + url + " for adapter: " + ad.getId());
+        }
+    }
+
+
+    private static AdapterDescription getAdapterDescriptionById(AdapterStorageImpl adapterStorage, String id) {
         AdapterDescription adapterDescription = null;
         List<AdapterDescription> allAdapters = adapterStorage.getAllAdapters();
         for (AdapterDescription a : allAdapters) {
diff --git a/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/rest/DescriptionResource.java b/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/rest/DescriptionResource.java
index 35a596e..5310cd0 100644
--- a/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/rest/DescriptionResource.java
+++ b/streampipes-connect-container-master/src/main/java/org/streampipes/connect/container/master/rest/DescriptionResource.java
@@ -18,8 +18,13 @@
 
 package org.apache.streampipes.connect.container.master.rest;
 
+import org.apache.streampipes.connect.adapter.exception.AdapterException;
+import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.connect.adapter.GenericAdapterDescription;
+import org.apache.streampipes.model.connect.grounding.ProtocolDescription;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.apache.streampipes.connect.container.master.management.Utils;
 import org.apache.streampipes.connect.container.master.management.DescriptionManagement;
 import org.apache.streampipes.connect.rest.AbstractContainerResource;
 import org.apache.streampipes.model.connect.adapter.AdapterDescriptionList;
@@ -30,7 +35,9 @@ import org.apache.streampipes.rest.shared.util.SpMediaType;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
 @Path("/api/v1/{username}/master/description")
@@ -81,4 +88,75 @@ public class DescriptionResource extends AbstractContainerResource {
     public void setDescriptionManagement(DescriptionManagement descriptionManagement) {
         this.descriptionManagement = descriptionManagement;
     }
+
+    @GET
+    @Path("/{id}/assets")
+    @Produces("application/zip")
+    public Response getAdapterAssets(@PathParam("id") String id, @PathParam("username") String userName) {
+        try {
+            AdapterDescription adapterDescription = descriptionManagement.getAdapter(id);
+
+            String workerUrl = new Utils().getWorkerUrl(adapterDescription);
+            String newUrl = Utils.addUserNameToApi(workerUrl, userName);
+
+            String result = "";
+            if (adapterDescription instanceof GenericAdapterDescription) {
+                result = descriptionManagement.getProtocolAssets(adapterDescription, newUrl);
+            } else {
+                result = descriptionManagement.getAdapterAssets(adapterDescription, newUrl);
+
+            }
+            return ok(result);
+        } catch (AdapterException e) {
+            logger.error("Not found adapter with id " + id, e);
+            return fail();
+        }
+    }
+
+    @GET
+    @Path("/{id}/assets/icon")
+    @Produces("image/png")
+    public Response getAdapterIconAsset(@PathParam("id") String id, @PathParam("username") String userName) {
+        try {
+            AdapterDescription adapterDescription = descriptionManagement.getAdapter(id);
+
+            String workerUrl = new Utils().getWorkerUrl(adapterDescription);
+            String newUrl = Utils.addUserNameToApi(workerUrl, userName);
+
+            byte[] result;
+            if (adapterDescription instanceof GenericAdapterDescription) {
+                result = descriptionManagement.getProtocolIconAsset(adapterDescription, newUrl);
+            } else {
+                result = descriptionManagement.getAdapterIconAsset(adapterDescription, newUrl);
+
+            }
+            return ok(result);
+        } catch (AdapterException e) {
+            logger.error("Not found adapter with id " + id, e);
+            return fail();
+        }
+    }
+
+    @GET
+    @Path("/{id}/assets/documentation")
+    @Produces(MediaType.TEXT_PLAIN)
+    public Response getAdapterDocumentationAsset(@PathParam("id") String id, @PathParam("username") String userName) {
+        try {
+            AdapterDescription adapterDescription = descriptionManagement.getAdapter(id);
+
+            String workerUrl = new Utils().getWorkerUrl(adapterDescription);
+            String newUrl = Utils.addUserNameToApi(workerUrl, userName);
+
+            String result = "";
+            if (adapterDescription instanceof GenericAdapterDescription) {
+                result =  descriptionManagement.getProtocolDocumentationAsset(adapterDescription, newUrl);
+            } else {
+                result =  descriptionManagement.getAdapterDocumentationAsset(adapterDescription, newUrl);
+            }
+            return ok(result);
+        } catch (AdapterException e) {
+            logger.error("Not found adapter with id " + id, e);
+            return fail();
+        }
+    }
 }
diff --git a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainer.java b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainer.java
index ff98a30..9f31c57 100644
--- a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainer.java
+++ b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainer.java
@@ -18,6 +18,9 @@
 
 package org.apache.streampipes.connect.container.worker.init;
 
+import org.apache.streampipes.container.locales.LabelGenerator;
+import org.apache.streampipes.model.base.NamedStreamPipesEntity;
+import org.apache.streampipes.model.connect.adapter.GenericAdapterDescription;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.SpringApplication;
@@ -32,6 +35,7 @@ import org.apache.streampipes.model.connect.adapter.AdapterDescription;
 import org.apache.streampipes.model.connect.grounding.ProtocolDescription;
 import org.apache.streampipes.model.connect.worker.ConnectWorkerContainer;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -51,7 +55,6 @@ public abstract class AdapterWorkerContainer {
     app.setDefaultProperties(Collections.singletonMap("server.port", workerPort));
     app.run();
 
-
     boolean connected = false;
 
     while (!connected) {
@@ -76,15 +79,40 @@ public abstract class AdapterWorkerContainer {
 
     List<AdapterDescription> adapters = new ArrayList<>();
     for (Adapter a : AdapterDeclarerSingleton.getInstance().getAllAdapters()) {
-      adapters.add(a.declareModel());
+      AdapterDescription desc = (AdapterDescription) rewrite(a.declareModel(), endpointUrl);
+      adapters.add(desc);
     }
 
     List<ProtocolDescription> protocols = new ArrayList<>();
     for (Protocol p : AdapterDeclarerSingleton.getInstance().getAllProtocols()) {
-      protocols.add(p.declareModel());
+      ProtocolDescription desc = (ProtocolDescription) rewrite(p.declareModel(), endpointUrl);
+      protocols.add(desc);
     }
 
     ConnectWorkerContainer result = new ConnectWorkerContainer(endpointUrl, protocols, adapters);
     return result;
   }
+
+  private NamedStreamPipesEntity rewrite(NamedStreamPipesEntity entity, String endpointUrl) {
+    if (!(entity instanceof GenericAdapterDescription)) {
+      if (entity instanceof  ProtocolDescription) {
+        entity.setElementId(endpointUrl +  "protocol/" + entity.getElementId());
+      } else if (entity instanceof  AdapterDescription) {
+        entity.setElementId(endpointUrl + "adapter/" + entity.getElementId());
+      }
+    }
+
+    // TODO remove after full internationalization support has been implemented
+    if (entity.isIncludesLocales()) {
+      LabelGenerator lg = new LabelGenerator(entity);
+      try {
+        entity = lg.generateLabels();
+      } catch (IOException e) {
+        LOG.error("Could not load labels for: " + entity.getAppId());
+      }
+    }
+    return entity;
+  }
+
+
 }
diff --git a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainerResourceConfig.java b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainerResourceConfig.java
index 072d803..7f66328 100644
--- a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainerResourceConfig.java
+++ b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/init/AdapterWorkerContainerResourceConfig.java
@@ -25,6 +25,8 @@ import org.apache.streampipes.connect.container.worker.rest.RuntimeResolvableRes
 import org.apache.streampipes.connect.container.worker.rest.WelcomePageWorker;
 import org.apache.streampipes.connect.container.worker.rest.WorkerResource;
 import org.apache.streampipes.connect.init.AdapterContainerConfig;
+import org.streampipes.connect.container.worker.rest.AdapterResource;
+import org.streampipes.connect.container.worker.rest.ProtocolResource;
 
 @Component
 public class AdapterWorkerContainerResourceConfig extends AdapterContainerConfig {
@@ -37,5 +39,7 @@ public class AdapterWorkerContainerResourceConfig extends AdapterContainerConfig
     register(WorkerResource.class);
     register(FileResource.class);
     register(MultiPartFeature.class);
+    register(AdapterResource.class);
+    register(ProtocolResource.class);
   }
 }
diff --git a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/management/AdapterWorkerManagement.java b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/management/AdapterWorkerManagement.java
index 5bd8f81..7a38d16 100644
--- a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/management/AdapterWorkerManagement.java
+++ b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/management/AdapterWorkerManagement.java
@@ -45,10 +45,18 @@ public class AdapterWorkerManagement {
         return AdapterDeclarerSingleton.getInstance().getAllProtocols();
     }
 
+    public Protocol getProtocol(String id) {
+        return AdapterDeclarerSingleton.getInstance().getProtocol(id);
+    }
+
     public Collection<Adapter> getAllAdapters() {
         return AdapterDeclarerSingleton.getInstance().getAllAdapters();
     }
 
+    public Adapter getAdapter(String id) {
+        return AdapterDeclarerSingleton.getInstance().getAdapter(id);
+    }
+
     public void invokeStreamAdapter(AdapterStreamDescription adapterStreamDescription) throws AdapterException {
 
 
@@ -57,7 +65,9 @@ public class AdapterWorkerManagement {
 
         Protocol protocol = null;
         if (adapterStreamDescription instanceof GenericAdapterStreamDescription) {
-            protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterStreamDescription) adapterStreamDescription).getProtocolDescription().getElementId());
+            //TODO Need to check with ElementId?
+            //protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterStreamDescription) adapterStreamDescription).getProtocolDescription().getElementId());
+            protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterStreamDescription) adapterStreamDescription).getProtocolDescription().getAppId());
             if (protocol == null) {
                 protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterStreamDescription) adapterStreamDescription).getProtocolDescription().getAppId());
             }
diff --git a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/rest/AdapterResource.java b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/rest/AdapterResource.java
new file mode 100644
index 0000000..3e0b124
--- /dev/null
+++ b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/rest/AdapterResource.java
@@ -0,0 +1,74 @@
+/*
+Copyright 2019 FZI Forschungszentrum Informatik
+
+Licensed 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.streampipes.connect.container.worker.rest;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import org.apache.streampipes.connect.container.worker.management.AdapterWorkerManagement;
+import org.apache.streampipes.connect.rest.AbstractContainerResource;
+import org.apache.streampipes.container.assets.AssetZipGenerator;
+import org.apache.streampipes.container.util.AssetsUtil;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+@Path("/api/v1/{username}/worker/adapters")
+public class AdapterResource extends AbstractContainerResource {
+
+    private AdapterWorkerManagement adapterWorkerManagement;
+
+    public AdapterResource() {
+        this.adapterWorkerManagement = new AdapterWorkerManagement();
+    }
+
+
+    @GET
+    @Path("/{id}/assets")
+    @Produces("application/zip")
+    public Response getAssets(@PathParam("id") String id) {
+        List<String> includedAssets = this.adapterWorkerManagement.getAdapter(id).declareModel().getIncludedAssets();
+        try {
+            return ok(new AssetZipGenerator(id, includedAssets).makeZip());
+        } catch (IOException e) {
+            e.printStackTrace();
+            return fail();
+        }
+    }
+
+    @GET
+    @Path("/{id}/assets/icon")
+    @Produces("image/png")
+    public Response getIconAsset(@PathParam("id") String elementId) throws IOException {
+        URL iconUrl = Resources.getResource(AssetsUtil.makeIconPath(elementId));
+        return ok(Resources.toByteArray(iconUrl));
+    }
+
+    @GET
+    @Path("/{id}/assets/documentation")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String getDocumentationAsset(@PathParam("id") String elementId) throws IOException {
+        URL documentationUrl = Resources.getResource(AssetsUtil.makeDocumentationPath(elementId));
+        return Resources.toString(documentationUrl, Charsets.UTF_8);
+    }
+}
diff --git a/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/rest/ProtocolResource.java b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/rest/ProtocolResource.java
new file mode 100644
index 0000000..5d12938
--- /dev/null
+++ b/streampipes-connect-container-worker/src/main/java/org/streampipes/connect/container/worker/rest/ProtocolResource.java
@@ -0,0 +1,74 @@
+/*
+Copyright 2019 FZI Forschungszentrum Informatik
+
+Licensed 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.streampipes.connect.container.worker.rest;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import org.apache.streampipes.connect.container.worker.management.AdapterWorkerManagement;
+import org.apache.streampipes.connect.rest.AbstractContainerResource;
+import org.apache.streampipes.container.assets.AssetZipGenerator;
+import org.apache.streampipes.container.util.AssetsUtil;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+@Path("/api/v1/{username}/worker/protocols")
+public class ProtocolResource extends AbstractContainerResource {
+
+    private AdapterWorkerManagement adapterWorkerManagement;
+
+    public ProtocolResource() {
+        this.adapterWorkerManagement = new AdapterWorkerManagement();
+    }
+
+
+    @GET
+    @Path("/{id}/assets")
+    @Produces("application/zip")
+    public Response getAssets(@PathParam("id") String id) {
+        List<String> includedAssets = this.adapterWorkerManagement.getProtocol(id).declareModel().getIncludedAssets();
+        try {
+            return ok(new AssetZipGenerator(id, includedAssets).makeZip());
+        } catch (IOException e) {
+            e.printStackTrace();
+            return fail();
+        }
+    }
+
+    @GET
+    @Path("/{id}/assets/icon")
+    @Produces("image/png")
+    public Response getIconAsset(@PathParam("id") String elementId) throws IOException {
+        URL iconUrl = Resources.getResource(AssetsUtil.makeIconPath(elementId));
+        return ok(Resources.toByteArray(iconUrl));
+    }
+
+    @GET
+    @Path("/{id}/assets/documentation")
+    @Produces(MediaType.TEXT_PLAIN)
+    public String getDocumentationAsset(@PathParam("id") String elementId) throws IOException {
+        URL documentationUrl = Resources.getResource(AssetsUtil.makeDocumentationPath(elementId));
+        return Resources.toString(documentationUrl, Charsets.UTF_8);
+    }
+}
diff --git a/streampipes-connect-container/src/main/java/org/apache/streampipes/connect/management/AdapterUtils.java b/streampipes-connect-container/src/main/java/org/apache/streampipes/connect/management/AdapterUtils.java
index 4ce0a5c..59bd90a 100644
--- a/streampipes-connect-container/src/main/java/org/apache/streampipes/connect/management/AdapterUtils.java
+++ b/streampipes-connect-container/src/main/java/org/apache/streampipes/connect/management/AdapterUtils.java
@@ -70,12 +70,12 @@ public class AdapterUtils {
 
         Protocol protocol = null;
         if (adapterDescription instanceof GenericAdapterSetDescription) {
-            protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterSetDescription) adapterDescription).getProtocolDescription().getElementId());
+            protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterSetDescription) adapterDescription).getProtocolDescription().getAppId());
             ((GenericAdapter) adapter).setProtocol(protocol);
         }
 
         if (adapterDescription instanceof GenericAdapterStreamDescription) {
-            protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterStreamDescription) adapterDescription).getProtocolDescription().getElementId());
+            protocol = AdapterDeclarerSingleton.getInstance().getProtocol(((GenericAdapterStreamDescription) adapterDescription).getProtocolDescription().getAppId());
             ((GenericAdapter) adapter).setProtocol(protocol);
         }
 
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/locales/LabelGenerator.java b/streampipes-container/src/main/java/org/apache/streampipes/container/locales/LabelGenerator.java
index fc2a8b8..79c6765 100644
--- a/streampipes-container/src/main/java/org/apache/streampipes/container/locales/LabelGenerator.java
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/locales/LabelGenerator.java
@@ -21,14 +21,16 @@ import static org.apache.streampipes.container.util.LocalesUtil.makePath;
 
 import org.apache.streampipes.model.base.ConsumableStreamPipesEntity;
 import org.apache.streampipes.model.base.NamedStreamPipesEntity;
+import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.connect.grounding.ProtocolDescription;
 import org.apache.streampipes.model.graph.DataProcessorDescription;
 import org.apache.streampipes.model.output.AppendOutputStrategy;
 import org.apache.streampipes.model.output.FixedOutputStrategy;
-import org.apache.streampipes.model.staticproperty.StaticPropertyAlternatives;
-import org.apache.streampipes.model.staticproperty.StaticPropertyGroup;
+import org.apache.streampipes.model.staticproperty.*;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 import java.util.Properties;
 
 public class LabelGenerator {
@@ -49,24 +51,19 @@ public class LabelGenerator {
       desc.setName(getTitle(props, desc.getAppId()));
       desc.setDescription(getDescription(props, desc.getAppId()));
 
+      if (isAdapter() || isProtocol()) {
+          List<StaticProperty> properties = ((AdapterDescription) desc).getConfig();
+          if (properties != null) {
+              properties.forEach(sp -> {
+                  generateLabels(props, sp);
+              });
+          }
+      }
+
+
       if (isConsumable()) {
         ((ConsumableStreamPipesEntity) desc).getStaticProperties().forEach(sp -> {
-          sp.setLabel(getTitle(props, sp.getInternalName()));
-          sp.setDescription(getDescription(props, sp.getInternalName()));
-          if (sp instanceof StaticPropertyAlternatives) {
-            ((StaticPropertyAlternatives) sp).getAlternatives().forEach(a -> {
-              a.setLabel(getTitle(props, a.getInternalName()));
-              a.setDescription(getDescription(props, a.getInternalName()));
-              a.getStaticProperty().setLabel(getTitle(props, a.getStaticProperty().getInternalName()));
-              a.getStaticProperty().setDescription(getDescription(props, a.getStaticProperty().getInternalName()));
-              if (a.getStaticProperty() instanceof StaticPropertyGroup) {
-                ((StaticPropertyGroup) a.getStaticProperty()).getStaticProperties().forEach(g -> {
-                  g.setLabel(getTitle(props, g.getInternalName()));
-                  g.setDescription(getDescription(props, g.getInternalName()));
-                });
-              }
-            });
-          }
+            generateLabels(props, sp);
         });
       }
 
@@ -90,6 +87,29 @@ public class LabelGenerator {
     return desc;
   }
 
+  private StaticProperty generateLabels(Properties props, StaticProperty sp) {
+    sp.setLabel(getTitle(props, sp.getInternalName()));
+    sp.setDescription(getDescription(props, sp.getInternalName()));
+    if (sp instanceof CollectionStaticProperty) {
+      ((CollectionStaticProperty) sp).getMembers().forEach(a -> {
+        generateLabels(props, a);
+      });
+    } else if (sp instanceof StaticPropertyGroup) {
+      ((StaticPropertyGroup) sp).getStaticProperties().forEach(g -> {
+        g.setLabel(getTitle(props, g.getInternalName()));
+        g.setDescription(getDescription(props, g.getInternalName()));
+      });
+    } else if (sp instanceof StaticPropertyAlternatives) {
+      ((StaticPropertyAlternatives) sp).getAlternatives().forEach(a -> {
+        generateLabels(props, a);
+      });
+    } else if (sp instanceof StaticPropertyAlternative) {
+      generateLabels(props, ((StaticPropertyAlternative) sp).getStaticProperty());
+    }
+
+    return sp;
+  }
+
   private Properties makeProperties() throws IOException {
     Properties props = new Properties();
     props.load(loadResource());
@@ -120,6 +140,14 @@ public class LabelGenerator {
     return desc instanceof DataProcessorDescription;
   }
 
+  private boolean isAdapter() {
+    return desc instanceof AdapterDescription;
+  }
+
+  private boolean isProtocol() {
+    return desc instanceof ProtocolDescription;
+  }
+
 
   private InputStream loadResource() {
     if (desc.getIncludedLocales().size() > 0) {
diff --git a/streampipes-container/src/main/java/org/apache/streampipes/container/util/AssetsUtil.java b/streampipes-container/src/main/java/org/apache/streampipes/container/util/AssetsUtil.java
new file mode 100644
index 0000000..e7cc621
--- /dev/null
+++ b/streampipes-container/src/main/java/org/apache/streampipes/container/util/AssetsUtil.java
@@ -0,0 +1,34 @@
+/*
+Copyright 2019 FZI Forschungszentrum Informatik
+
+Licensed 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.container.util;
+
+import org.apache.streampipes.commons.constants.GlobalStreamPipesConstants;
+
+public class AssetsUtil {
+
+    public static String makeIconPath(String elementId) {
+        return makePath(elementId, GlobalStreamPipesConstants.STD_ICON_NAME);
+    }
+
+    public static String makeDocumentationPath(String elementId) {
+        return makePath(elementId, GlobalStreamPipesConstants.STD_DOCUMENTATION_NAME);
+    }
+
+    public static String makePath(String elementId, String assetAppendix) {
+        return elementId + "/" + assetAppendix;
+    }
+}
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/AdapterDescriptionBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/AdapterDescriptionBuilder.java
index 30c3a28..d6792f6 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/AdapterDescriptionBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/AdapterDescriptionBuilder.java
@@ -28,6 +28,11 @@ public abstract class AdapterDescriptionBuilder<BU extends
         AdapterDescriptionBuilder<BU, T>, T extends AdapterDescription> extends
         AbstractConfigurablePipelineElementBuilder<BU, T> {
 
+  protected AdapterDescriptionBuilder(String id, T element) {
+    super(id, element);
+    this.elementDescription.setAdapterId(id);
+  }
+
   protected AdapterDescriptionBuilder(String id, String label, String description,
                                    T adapterTypeInstance) {
     super(id, label, description, adapterTypeInstance);
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/ProtocolDescriptionBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/ProtocolDescriptionBuilder.java
index 9a20674..c84a429 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/ProtocolDescriptionBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/ProtocolDescriptionBuilder.java
@@ -32,9 +32,13 @@ public class ProtocolDescriptionBuilder extends
     super(appId, label, description, new ProtocolDescription());
   }
 
+  private ProtocolDescriptionBuilder(String id) {
+    super(id, new ProtocolDescription());
+  }
+
   /**
    * Creates a new protocol description using the builder pattern.
-   * @param id A unique identifier of the new element, e.g., com.mycompany.sink.mynewdatasink
+   * @param id A unique identifier of the new element, e.g., com.mycompany.protocol.mynewprotocol
    * @param label A human-readable name of the element. Will later be shown as the element name in the StreamPipes UI.
    * @param description A human-readable description of the element.
    */
@@ -42,6 +46,14 @@ public class ProtocolDescriptionBuilder extends
     return new ProtocolDescriptionBuilder(id, label, description);
   }
 
+  /**
+   * Creates a new protocol description using the builder pattern.
+   * @param id A unique identifier of the new element, e.g., com.mycompany.protocol.mynewprotocol
+   */
+  public static ProtocolDescriptionBuilder create(String id) {
+    return new ProtocolDescriptionBuilder(id);
+  }
+
   public ProtocolDescriptionBuilder sourceType(AdapterSourceType sourceType) {
     this.elementDescription.setSourceType(sourceType.toString());
     return this;
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataSetAdapterBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataSetAdapterBuilder.java
index 5c16a5d..1010ee4 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataSetAdapterBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataSetAdapterBuilder.java
@@ -28,6 +28,10 @@ public class SpecificDataSetAdapterBuilder extends
     super(id, label, description, new SpecificAdapterSetDescription());
   }
 
+  private SpecificDataSetAdapterBuilder(String appId) {
+    super(appId, new SpecificAdapterSetDescription());
+  }
+
   /**
    * Creates a new specific data set adapter using the builder pattern.
    * @param appId A unique identifier of the new element, e.g., com.mycompany.set.mynewdataset
@@ -40,6 +44,15 @@ public class SpecificDataSetAdapterBuilder extends
     return new SpecificDataSetAdapterBuilder(appId, label, description);
   }
 
+  /**
+   * Creates a new specific data set adapter using the builder pattern.
+   * @param appId A unique identifier of the new element, e.g., com.mycompany.set.mynewdataset
+   * @return a new instance of {@link DataSetBuilder}
+   */
+  public static SpecificDataSetAdapterBuilder create(String appId) {
+    return new SpecificDataSetAdapterBuilder(appId);
+  }
+
   @Override
   protected SpecificDataSetAdapterBuilder me() {
     return this;
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataStreamAdapterBuilder.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataStreamAdapterBuilder.java
index 779ac54..e24433d 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataStreamAdapterBuilder.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/builder/adapter/SpecificDataStreamAdapterBuilder.java
@@ -27,6 +27,10 @@ public class SpecificDataStreamAdapterBuilder extends
     super(id, label, description, new SpecificAdapterStreamDescription());
   }
 
+  private SpecificDataStreamAdapterBuilder(String appId) {
+    super(appId, new SpecificAdapterStreamDescription());
+  }
+
   /**
    * Creates a new specific data stream adapter using the builder pattern.
    * @param appId A unique identifier of the new element, e.g., com.mycompany.set.mynewdataset
@@ -39,6 +43,17 @@ public class SpecificDataStreamAdapterBuilder extends
     return new SpecificDataStreamAdapterBuilder(appId, label, description);
   }
 
+  /**
+   * Creates a new specific data stream adapter using the builder pattern.
+   * @param appId A unique identifier of the new element, e.g., com.mycompany.set.mynewdataset
+   * @return a new instance of {@link DataSetBuilder}
+   */
+  public static SpecificDataStreamAdapterBuilder create(String appId) {
+    return new SpecificDataStreamAdapterBuilder(appId);
+  }
+
+
+
   @Override
   protected SpecificDataStreamAdapterBuilder me() {
     return this;
diff --git a/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.html b/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.html
index 9c03b80..0b5eb71 100644
--- a/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.html
+++ b/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.html
@@ -1,75 +1,75 @@
-<!--
-  ~ 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 [className]="className" fxFlex="100"
- fxLayout="column">
-    <div fxLayout="column">
-        <div class="type" fxLayout="column" fxLayoutAlign="start start">
-            <div class="type-data" fxLayout="row" fxLayoutAlign="start start">
-                <mat-icon *ngIf="isDataSetDescription" class="historic">lens</mat-icon>
-                <mat-icon *ngIf="isDataStreamDescription" class="real-time">lens</mat-icon>
-                <p *ngIf="isDataSetDescription">Data Set</p>
-                <p *ngIf="isDataStreamDescription">Data Stream</p>
-            </div>
-        </div>
-        <div fxLayoutAlign="start center" fxLayout="column" class="icon">
-            <img *ngIf="adapter.iconUrl && !adapter.icon" [src]="'assets/img/connect/' +adapter.iconUrl" class="iconImg"/>
-            <img *ngIf="adapter.icon" [src]="adapter.icon" style="min-height: 50px;" class="iconImg"/>
-        </div>
-        <h3>{{adapter.label}}</h3>
-    </div>
-    <div fxLayout="row">
-        <div fxFlex="70" class="description" fxLayoutAlign="start start">
-            <p [innerHTML]="adapter.description"></p>
-        </div>
-        <div fxFlex="30" fxLayout="row" fxLayoutAlign="end end" *ngIf="isRunningAdapter" class="delete">
-            <button id="{{ 'create-template-' + adapter.label.split(' ').join('_') }}" matTooltip="Create Adapter Template" color="secondary" class="edit" mat-fab (click)="createTemplate(adapter)">
-                <i class="material-icons">
-                   file_copy
-                </i>
-            </button>
-            <button id="{{ 'delete-' + adapterLabel }}" matTooltip="Delete Adapter" color="primary" mat-fab (click)="deleteAdapter(adapter)" [disabled]="deleteInProgress(adapter.couchDbId)">
-                <i class="material-icons" *ngIf="!deleteInProgress(adapter.couchDbId)">
-                    delete
-                </i>
-                <mat-spinner *ngIf="deleteInProgress(adapter.couchDbId)" [diameter]="20" fxLayoutAlign="center"></mat-spinner>
-            </button>
-        </div>
-        <div fxFlex="30" fxLayout="row" fxLayoutAlign="end end" *ngIf="adapter.isTemplate" class="delete">
-            <button id="{{ 'share-template-' + adapterLabel }}" matTooltip="Delete Adapter Template" color="secondary" mat-fab (click)="shareAdapterTemplate(adapter); $event.stopPropagation()">
-                <i class="material-icons" *ngIf="!deleteInProgress(adapter.couchDbId)">
-                    share
-                </i>
-            </button>
-            <button id="{{ 'delete-template-' + adapterLabel }}" matTooltip="Share Adapter Template" color="primary" mat-fab (click)="deleteAdapterTemplate(adapter); $event.stopPropagation()" [disabled]="deleteInProgress(adapter.couchDbId)">
-                <i class="material-icons" *ngIf="!deleteInProgress(adapter.couchDbId)">
-                    delete
-                </i>
-                <mat-spinner *ngIf="deleteInProgress(adapter.couchDbId)" [diameter]="20" fxLayoutAlign="center"></mat-spinner>
-            </button>
-
-        </div>
-        <!--<div fxFlex="30" *ngIf="!adapter.couchDbId" fxLayout="row" fxLayoutAlign="end end">-->
-            <!--<button color="primary" mat-fab>-->
-                <!--<i class="material-icons">-->
-                    <!--add-->
-                <!--</i>-->
-            <!--</button>-->
-        <!--</div>-->
-    </div>
+<!--
+  ~ 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 [className]="className" fxFlex="100"
+ fxLayout="column">
+    <div fxLayout="column">
+        <div class="type" fxLayout="column" fxLayoutAlign="start start">
+            <div class="type-data" fxLayout="row" fxLayoutAlign="start start">
+                <mat-icon *ngIf="isDataSetDescription" class="historic">lens</mat-icon>
+                <mat-icon *ngIf="isDataStreamDescription" class="real-time">lens</mat-icon>
+                <p *ngIf="isDataSetDescription">Data Set</p>
+                <p *ngIf="isDataStreamDescription">Data Stream</p>
+            </div>
+        </div>
+        <div fxLayoutAlign="start center" fxLayout="column" class="icon">
+            <img *ngIf="getIconUrl() && !adapter.icon" [src]="getIconUrl()" class="iconImg"/>
+            <img *ngIf="adapter.icon" [src]="adapter.icon" style="min-height: 50px;" class="iconImg"/>
+        </div>
+        <h3>{{adapter.label}}</h3>
+    </div>
+    <div fxLayout="row">
+        <div fxFlex="70" class="description" fxLayoutAlign="start start">
+            <p [innerHTML]="adapter.description"></p>
+        </div>
+        <div fxFlex="30" fxLayout="row" fxLayoutAlign="end end" *ngIf="isRunningAdapter" class="delete">
+            <button id="{{ 'create-template-' + adapter.label.split(' ').join('_') }}" matTooltip="Create Adapter Template" color="secondary" class="edit" mat-fab (click)="createTemplate(adapter)">
+                <i class="material-icons">
+                   file_copy
+                </i>
+            </button>
+            <button id="{{ 'delete-' + adapterLabel }}" matTooltip="Delete Adapter" color="primary" mat-fab (click)="deleteAdapter(adapter)" [disabled]="deleteInProgress(adapter.couchDbId)">
+                <i class="material-icons" *ngIf="!deleteInProgress(adapter.couchDbId)">
+                    delete
+                </i>
+                <mat-spinner *ngIf="deleteInProgress(adapter.couchDbId)" [diameter]="20" fxLayoutAlign="center"></mat-spinner>
+            </button>
+        </div>
+        <div fxFlex="30" fxLayout="row" fxLayoutAlign="end end" *ngIf="adapter.isTemplate" class="delete">
+            <button id="{{ 'share-template-' + adapterLabel }}" matTooltip="Delete Adapter Template" color="secondary" mat-fab (click)="shareAdapterTemplate(adapter); $event.stopPropagation()">
+                <i class="material-icons" *ngIf="!deleteInProgress(adapter.couchDbId)">
+                    share
+                </i>
+            </button>
+            <button id="{{ 'delete-template-' + adapterLabel }}" matTooltip="Share Adapter Template" color="primary" mat-fab (click)="deleteAdapterTemplate(adapter); $event.stopPropagation()" [disabled]="deleteInProgress(adapter.couchDbId)">
+                <i class="material-icons" *ngIf="!deleteInProgress(adapter.couchDbId)">
+                    delete
+                </i>
+                <mat-spinner *ngIf="deleteInProgress(adapter.couchDbId)" [diameter]="20" fxLayoutAlign="center"></mat-spinner>
+            </button>
+
+        </div>
+        <!--<div fxFlex="30" *ngIf="!adapter.couchDbId" fxLayout="row" fxLayoutAlign="end end">-->
+            <!--<button color="primary" mat-fab>-->
+                <!--<i class="material-icons">-->
+                    <!--add-->
+                <!--</i>-->
+            <!--</button>-->
+        <!--</div>-->
+    </div>
 </div>
\ No newline at end of file
diff --git a/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.ts b/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.ts
index 7ac76ce..151e3d7 100644
--- a/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.ts
+++ b/ui/src/app/connect/data-marketplace/adapter-description/adapter-description.component.ts
@@ -1,123 +1,132 @@
-/*
- * 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, EventEmitter, Output } from '@angular/core';
-import { AdapterDescription } from '../../model/connect/AdapterDescription';
-import { ConnectService } from '../../connect.service';
-import {DataMarketplaceService} from "../data-marketplace.service";
-import {AdapterExportDialog} from '../adapter-export/adapter-export-dialog.component';
-import {MatDialog} from '@angular/material';
-
-@Component({
-  selector: 'sp-adapter-description',
-  templateUrl: './adapter-description.component.html',
-  styleUrls: ['./adapter-description.component.css'],
-})
-export class AdapterDescriptionComponent {
-
-  @Input()
-  adapter: AdapterDescription;
-
-  @Output()
-  updateAdapterEmitter: EventEmitter<void> = new EventEmitter<void>();
-
-  @Output()
-  createTemplateEmitter: EventEmitter<AdapterDescription> = new EventEmitter<AdapterDescription>();
-
-  adapterToDelete: string;
-  deleting: boolean = false;
-  className: string = "";
-  isDataSetDescription: boolean = false;
-  isDataStreamDescription: boolean = false;
-  isRunningAdapter: boolean = false;
-  adapterLabel: string;
-
-  constructor(private connectService: ConnectService, private dataMarketplaceService: DataMarketplaceService, public dialog: MatDialog) {}
-
-  ngOnInit() {
-      this.isDataSetDescription = this.connectService.isDataSetDescription(this.adapter);
-      this.isDataStreamDescription = this.connectService.isDataStreamDescription(this.adapter);
-      this.isRunningAdapter = (this.adapter.couchDbId != undefined && !this.adapter.isTemplate);
-      this.adapterLabel = this.adapter.label.split(' ').join('_');
-      this.className = this.getClassName();
-  }
-
-  isGenericDescription(): boolean {
-    return this.connectService.isGenericDescription(this.adapter);
-  }
-
-  isSpecificDescription(): boolean {
-    return this.connectService.isSpecificDescription(this.adapter);
-  }
-
-  deleteAdapter(adapter: AdapterDescription): void {
-  this.deleting = true;
-      this.adapterToDelete = adapter.couchDbId;
-      this.dataMarketplaceService.deleteAdapter(adapter).subscribe(res => {
-          this.adapterToDelete = undefined;
-          this.updateAdapterEmitter.emit();
-          this.deleting = false;
-      });
-  }
-
-  shareAdapterTemplate(adapter: AdapterDescription): void {
-
-        let dialogRef = this.dialog.open(AdapterExportDialog, {
-            width: '70%',
-            data: { adapter: adapter
-            },
-            panelClass: 'sp-no-padding-dialog'
-        });
-
-        dialogRef.afterClosed().subscribe(result => {
-
-        });
-
-
-  }
-
-
-  deleteAdapterTemplate(adapter: AdapterDescription): void {
-      this.adapterToDelete = adapter.couchDbId;
-      this.dataMarketplaceService.deleteAdapterTemplate(adapter).subscribe(res => {
-          this.adapterToDelete = undefined;
-          this.updateAdapterEmitter.emit();
-          this.deleting = false;
-      });
-  }
-
-  createTemplate(adapter: AdapterDescription): void {
-      this.createTemplateEmitter.emit(adapter);
-  }
-
-  getClassName() {
-    let className = this.isRunningAdapter ? "adapter-box" : "adapter-description-box";
-
-    if (this.isDataSetDescription) {
-      className += " adapter-box-set";
-    } else {
-      className +=" adapter-box-stream";
-    }
-
-    return className;
-  }
-
-  deleteInProgress(adapterCouchDbId) {
-    return this.deleting && (adapterCouchDbId === this.adapterToDelete);
-  }
-}
+/*
+ * 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, EventEmitter, Output } from '@angular/core';
+import { AdapterDescription } from '../../model/connect/AdapterDescription';
+import { ConnectService } from '../../connect.service';
+import {DataMarketplaceService} from "../data-marketplace.service";
+import {AdapterExportDialog} from '../adapter-export/adapter-export-dialog.component';
+import {MatDialog} from '@angular/material';
+
+@Component({
+  selector: 'sp-adapter-description',
+  templateUrl: './adapter-description.component.html',
+  styleUrls: ['./adapter-description.component.css'],
+})
+export class AdapterDescriptionComponent {
+
+  @Input()
+  adapter: AdapterDescription;
+
+  @Output()
+  updateAdapterEmitter: EventEmitter<void> = new EventEmitter<void>();
+
+  @Output()
+  createTemplateEmitter: EventEmitter<AdapterDescription> = new EventEmitter<AdapterDescription>();
+
+  adapterToDelete: string;
+  deleting: boolean = false;
+  className: string = "";
+  isDataSetDescription: boolean = false;
+  isDataStreamDescription: boolean = false;
+  isRunningAdapter: boolean = false;
+  adapterLabel: string;
+
+  constructor(private connectService: ConnectService, private dataMarketplaceService: DataMarketplaceService, public dialog: MatDialog) {}
+
+  ngOnInit() {
+      this.isDataSetDescription = this.connectService.isDataSetDescription(this.adapter);
+      this.isDataStreamDescription = this.connectService.isDataStreamDescription(this.adapter);
+      this.isRunningAdapter = (this.adapter.couchDbId != undefined && !this.adapter.isTemplate);
+      this.adapterLabel = this.adapter.label.split(' ').join('_');
+      this.className = this.getClassName();
+  }
+
+  isGenericDescription(): boolean {
+    return this.connectService.isGenericDescription(this.adapter);
+  }
+
+  isSpecificDescription(): boolean {
+    return this.connectService.isSpecificDescription(this.adapter);
+  }
+
+  deleteAdapter(adapter: AdapterDescription): void {
+  this.deleting = true;
+      this.adapterToDelete = adapter.couchDbId;
+      this.dataMarketplaceService.deleteAdapter(adapter).subscribe(res => {
+          this.adapterToDelete = undefined;
+          this.updateAdapterEmitter.emit();
+          this.deleting = false;
+      });
+  }
+
+  shareAdapterTemplate(adapter: AdapterDescription): void {
+
+        let dialogRef = this.dialog.open(AdapterExportDialog, {
+            width: '70%',
+            data: { adapter: adapter
+            },
+            panelClass: 'sp-no-padding-dialog'
+        });
+
+        dialogRef.afterClosed().subscribe(result => {
+
+        });
+
+
+  }
+
+
+  deleteAdapterTemplate(adapter: AdapterDescription): void {
+      this.adapterToDelete = adapter.couchDbId;
+      this.dataMarketplaceService.deleteAdapterTemplate(adapter).subscribe(res => {
+          this.adapterToDelete = undefined;
+          this.updateAdapterEmitter.emit();
+          this.deleting = false;
+      });
+  }
+
+  createTemplate(adapter: AdapterDescription): void {
+      this.createTemplateEmitter.emit(adapter);
+  }
+
+  getClassName() {
+    let className = this.isRunningAdapter ? "adapter-box" : "adapter-description-box";
+
+    if (this.isDataSetDescription) {
+      className += " adapter-box-set";
+    } else {
+      className +=" adapter-box-stream";
+    }
+
+    return className;
+  }
+
+  deleteInProgress(adapterCouchDbId) {
+    return this.deleting && (adapterCouchDbId === this.adapterToDelete);
+  }
+
+  getIconUrl() {
+    //TODO Use "this.adapter.includesAssets" if boolean demoralizing is working
+    if (this.adapter.includedAssets.length > 0) {
+      return this.dataMarketplaceService.getAssetUrl(this.adapter.appId) + "/icon";
+    } else {
+      return 'assets/img/connect/' + this.adapter.iconUrl;
+    }
+  }
+}
diff --git a/ui/src/app/connect/data-marketplace/data-marketplace.service.ts b/ui/src/app/connect/data-marketplace/data-marketplace.service.ts
index aba692c..bdf36da 100644
--- a/ui/src/app/connect/data-marketplace/data-marketplace.service.ts
+++ b/ui/src/app/connect/data-marketplace/data-marketplace.service.ts
@@ -1,239 +1,243 @@
-/*
- * 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 { Injectable } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
-import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
-
-
-import { TsonLd } from '../../platform-services/tsonld';
-import { AuthStatusService } from '../../services/auth-status.service';
-import { AdapterDescriptionList } from '../model/connect/AdapterDescriptionList';
-import { AdapterDescription } from '../model/connect/AdapterDescription';
-import { AdapterSetDescription } from '../model/connect/AdapterSetDescription';
-import { GenericAdapterSetDescription } from '../model/connect/GenericAdapterSetDescription';
-import { SpecificAdapterSetDescription } from '../model/connect/SpecificAdapterSetDescription';
-import { AdapterStreamDescription } from '../model/connect/AdapterStreamDescription';
-import { GenericAdapterStreamDescription } from '../model/connect/GenericAdapterStreamDescription';
-import { SpecificAdapterStreamDescription } from '../model/connect/SpecificAdapterStreamDescription';
-import { FreeTextStaticProperty } from '../model/FreeTextStaticProperty';
-import { ProtocolDescription } from '../model/connect/grounding/ProtocolDescription';
-import { ProtocolDescriptionList } from '../model/connect/grounding/ProtocolDescriptionList';
-import { FormatDescription } from '../model/connect/grounding/FormatDescription';
-import { DataStreamDescription } from '../model/DataStreamDescription';
-import { EventSchema } from '../schema-editor/model/EventSchema';
-import { EventPropertyPrimitive } from '../schema-editor/model/EventPropertyPrimitive';
-import { ConnectService } from '../connect.service';
-import { AnyStaticProperty } from '../model/AnyStaticProperty';
-import { Option } from '../model/Option';
-import { RenameRuleDescription} from '../model/connect/rules/RenameRuleDescription';
-import { DeleteRuleDescription} from '../model/connect/rules/DeleteRuleDescription';
-import { AddNestedRuleDescription} from '../model/connect/rules/AddNestedRuleDescription';
-import { MoveRuleDescription} from '../model/connect/rules/MoveRuleDesctiption';
-import { EventPropertyNested} from '../schema-editor/model/EventPropertyNested';
-import {EventPropertyList} from '../schema-editor/model/EventPropertyList';
-import {UUID} from 'angular2-uuid';
-import {DataSetDescription} from '../model/DataSetDescription';
-import {OneOfStaticProperty} from '../model/OneOfStaticProperty';
-import {UnitTransformRuleDescription} from '../model/connect/rules/UnitTransformRuleDescription';
-import {RemoveDuplicatesRuleDescription} from '../model/connect/rules/RemoveDuplicatesRuleDescription';
-import {AddTimestampRuleDescription} from '../model/connect/rules/AddTimestampRuleDescription';
-import {AddValueTransformationRuleDescription} from '../model/connect/rules/AddValueTransformationRuleDescription';
-import {FileStaticProperty} from '../model/FileStaticProperty';
-import {TimestampTransformationRuleDescription} from '../model/connect/rules/TimestampTransformationRuleDescription';
-import {RestApi} from "../../services/rest-api.service";
-import {TsonLdSerializerService} from "../../platform-services/tsonld-serializer.service";
-import {AlternativesStaticProperty} from "../model/AlternativesStaticProperty";
-import {GroupStaticProperty} from "../model/GroupStaticProperty";
-import {StaticProperty} from "../model/StaticProperty";
-
-@Injectable()
-export class DataMarketplaceService {
-  private host = '/streampipes-connect/';
-
-  constructor(
-    private http: HttpClient,
-    private authStatusService: AuthStatusService,
-    private connectService: ConnectService,
-    private restApi: RestApi,
-    private tsonLdSerializer: TsonLdSerializerService
-  ) {}
-
-
-  getAdapterDescriptions(): Observable<AdapterDescription[]> {
-      return this.requestAdapterDescriptions('/master/description/adapters');
-  }
-
-  getAdapters(): Observable<AdapterDescription[]> {
-    return this.requestAdapterDescriptions('/master/adapters');
-  }
-
-  getAdapterTemplates(): Observable<AdapterDescription[]> {
-    return this.requestAdapterDescriptions('/master/adapters/template/all');
-  }
-
-  requestAdapterDescriptions(path: string) : Observable<AdapterDescription[]> {
-    return this.http
-      .get(
-        this.host +
-          'api/v1/' +
-          this.authStatusService.email +
-          path
-      )
-      .pipe(map(response => {
-        if(response['@graph'] === undefined) return [];
-        const res: AdapterDescriptionList = this.tsonLdSerializer.fromJsonLd(
-          response,
-          'sp:AdapterDescriptionList'
-        );
-        res.list.forEach(adapterDescription => {
-          adapterDescription.config.sort((a, b) => a.index - b.index);
-          adapterDescription.config.forEach(sp => {
-            this.sortStaticProperties(sp)
-          });
-        });
-        return res.list;
-      }));
-  }
-
-  deleteAdapter(adapter: AdapterDescription): Observable<Object> {
-    return this.deleteRequest(adapter, '/master/adapters/')
-  }
-
-  deleteAdapterTemplate(adapter: AdapterDescription): Observable<Object> {
-      return this.deleteRequest(adapter, '/master/adapters/template/')
-  }
-
-  getAdapterCategories(): Observable<Object> {
-    return this.http.get(
-        this.baseUrl +
-        '/api/v2' +
-        "/categories/adapter"
-    )
-  }
-
-  private deleteRequest(adapter: AdapterDescription, url: String) {
-    return this.http.delete(
-      this.host +
-        'api/v1/' +
-        this.authStatusService.email +
-        url +
-        adapter.couchDbId
-    );
-  }
-
-  getProtocols(): Observable<ProtocolDescription[]> {
-    return this.http
-      .get(
-        this.host +
-          'api/v1/' +
-          this.authStatusService.email +
-          '/master/description/protocols'
-      )
-      .pipe(map(response => {
-        const res = this.tsonLdSerializer.fromJsonLd(
-          response,
-          'sp:ProtocolDescriptionList'
-        );
-        res.list.forEach(protocolDescription => {
-          protocolDescription.config.sort((a, b) => a.index - b.index);
-          protocolDescription.config.forEach(sp => {
-            this.sortStaticProperties(sp)
-          });
-        });
-        return res.list;
-      }));
-  }
-
-  sortStaticProperties(sp: StaticProperty) {
-    if (sp instanceof AlternativesStaticProperty) {
-      sp.alternatives.sort((a, b) => a.index - b.index);
-      sp.alternatives.forEach(a => {
-        if (a.staticProperty instanceof GroupStaticProperty) {
-          a.staticProperty.staticProperties.sort((a, b) => a.index - b.index);
-        }
-      })
-    } else if (sp instanceof GroupStaticProperty) {
-      sp.staticProperties.sort((a, b) => a.index - b.index);
-    }
-  }
-
-  getGenericAndSpecifigAdapterDescriptions(): Observable<
-    Observable<AdapterDescription[]>
-  > {
-    return this.getAdapterDescriptions().pipe(map(adapterDescriptions => {
-      adapterDescriptions = adapterDescriptions.filter(
-        this.connectService.isSpecificDescription
-      );
-
-      return this.getProtocols().pipe(map(protocols => {
-        for (let protocol of protocols) {
-          let newAdapterDescription: AdapterDescription;
-          if (protocol.id.includes('sp:protocol/set')) {
-            newAdapterDescription = new GenericAdapterSetDescription(
-              'http://streampipes.org/genericadaptersetdescription'
-            );
-          } else if (protocol.id.includes('sp:protocol/stream')) {
-            newAdapterDescription = new GenericAdapterStreamDescription(
-              'http://streampipes.org/genericadapterstreamdescription'
-            );
-          }
-          newAdapterDescription.label = protocol.label;
-          newAdapterDescription.description = protocol.description;
-          newAdapterDescription.iconUrl = protocol.iconUrl;
-          newAdapterDescription.uri = newAdapterDescription.id;
-          newAdapterDescription.category = protocol.category;
-
-          if (
-            newAdapterDescription instanceof GenericAdapterSetDescription ||
-            newAdapterDescription instanceof GenericAdapterStreamDescription
-          ) {
-            newAdapterDescription.protocol = protocol;
-          }
-          adapterDescriptions.push(newAdapterDescription);
-        }
-        return adapterDescriptions;
-      }));
-    }));
-  }
-
-  cloneAdapterDescription(toClone: AdapterDescription): AdapterDescription {
-    var result: AdapterDescription;
-
-      if (this.connectService.isGenericDescription(toClone)) {
-          if (this.connectService.isDataStreamDescription(toClone)) {
-              result = Object.assign(new GenericAdapterStreamDescription(toClone.id), toClone);
-          } else {
-              result = Object.assign(new GenericAdapterSetDescription(toClone.id), toClone);
-          }
-      } else {
-          if (this.connectService.isDataStreamDescription(toClone)) {
-              result = Object.assign(new SpecificAdapterStreamDescription(toClone.id), toClone);
-          } else {
-              result = Object.assign(new SpecificAdapterSetDescription(toClone.id), toClone);
-          }
-      }
-
-    return result;
-  }
-
-  private get baseUrl() {
-    return '/streampipes-backend';
-  }
-}
+/*
+ * 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 { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+
+
+import { TsonLd } from '../../platform-services/tsonld';
+import { AuthStatusService } from '../../services/auth-status.service';
+import { AdapterDescriptionList } from '../model/connect/AdapterDescriptionList';
+import { AdapterDescription } from '../model/connect/AdapterDescription';
+import { AdapterSetDescription } from '../model/connect/AdapterSetDescription';
+import { GenericAdapterSetDescription } from '../model/connect/GenericAdapterSetDescription';
+import { SpecificAdapterSetDescription } from '../model/connect/SpecificAdapterSetDescription';
+import { AdapterStreamDescription } from '../model/connect/AdapterStreamDescription';
+import { GenericAdapterStreamDescription } from '../model/connect/GenericAdapterStreamDescription';
+import { SpecificAdapterStreamDescription } from '../model/connect/SpecificAdapterStreamDescription';
+import { FreeTextStaticProperty } from '../model/FreeTextStaticProperty';
+import { ProtocolDescription } from '../model/connect/grounding/ProtocolDescription';
+import { ProtocolDescriptionList } from '../model/connect/grounding/ProtocolDescriptionList';
+import { FormatDescription } from '../model/connect/grounding/FormatDescription';
+import { DataStreamDescription } from '../model/DataStreamDescription';
+import { EventSchema } from '../schema-editor/model/EventSchema';
+import { EventPropertyPrimitive } from '../schema-editor/model/EventPropertyPrimitive';
+import { ConnectService } from '../connect.service';
+import { AnyStaticProperty } from '../model/AnyStaticProperty';
+import { Option } from '../model/Option';
+import { RenameRuleDescription} from '../model/connect/rules/RenameRuleDescription';
+import { DeleteRuleDescription} from '../model/connect/rules/DeleteRuleDescription';
+import { AddNestedRuleDescription} from '../model/connect/rules/AddNestedRuleDescription';
+import { MoveRuleDescription} from '../model/connect/rules/MoveRuleDesctiption';
+import { EventPropertyNested} from '../schema-editor/model/EventPropertyNested';
+import {EventPropertyList} from '../schema-editor/model/EventPropertyList';
+import {UUID} from 'angular2-uuid';
+import {DataSetDescription} from '../model/DataSetDescription';
+import {OneOfStaticProperty} from '../model/OneOfStaticProperty';
+import {UnitTransformRuleDescription} from '../model/connect/rules/UnitTransformRuleDescription';
+import {RemoveDuplicatesRuleDescription} from '../model/connect/rules/RemoveDuplicatesRuleDescription';
+import {AddTimestampRuleDescription} from '../model/connect/rules/AddTimestampRuleDescription';
+import {AddValueTransformationRuleDescription} from '../model/connect/rules/AddValueTransformationRuleDescription';
+import {FileStaticProperty} from '../model/FileStaticProperty';
+import {TimestampTransformationRuleDescription} from '../model/connect/rules/TimestampTransformationRuleDescription';
+import {RestApi} from "../../services/rest-api.service";
+import {TsonLdSerializerService} from "../../platform-services/tsonld-serializer.service";
+import {AlternativesStaticProperty} from "../model/AlternativesStaticProperty";
+import {GroupStaticProperty} from "../model/GroupStaticProperty";
+import {StaticProperty} from "../model/StaticProperty";
+
+@Injectable()
+export class DataMarketplaceService {
+  private host = '/streampipes-connect/';
+
+  constructor(
+    private http: HttpClient,
+    private authStatusService: AuthStatusService,
+    private connectService: ConnectService,
+    private restApi: RestApi,
+    private tsonLdSerializer: TsonLdSerializerService
+  ) {}
+
+
+  getAdapterDescriptions(): Observable<AdapterDescription[]> {
+      return this.requestAdapterDescriptions('/master/description/adapters');
+  }
+
+  getAdapters(): Observable<AdapterDescription[]> {
+    return this.requestAdapterDescriptions('/master/adapters');
+  }
+
+  getAdapterTemplates(): Observable<AdapterDescription[]> {
+    return this.requestAdapterDescriptions('/master/adapters/template/all');
+  }
+
+  requestAdapterDescriptions(path: string) : Observable<AdapterDescription[]> {
+    return this.http
+      .get(
+        this.host +
+          'api/v1/' +
+          this.authStatusService.email +
+          path
+      )
+      .pipe(map(response => {
+        if(response['@graph'] === undefined) return [];
+        const res: AdapterDescriptionList = this.tsonLdSerializer.fromJsonLd(
+          response,
+          'sp:AdapterDescriptionList'
+        );
+        res.list.forEach(adapterDescription => {
+          adapterDescription.config.sort((a, b) => a.index - b.index);
+          adapterDescription.config.forEach(sp => {
+            this.sortStaticProperties(sp)
+          });
+        });
+        return res.list;
+      }));
+  }
+
+  deleteAdapter(adapter: AdapterDescription): Observable<Object> {
+    return this.deleteRequest(adapter, '/master/adapters/')
+  }
+
+  deleteAdapterTemplate(adapter: AdapterDescription): Observable<Object> {
+      return this.deleteRequest(adapter, '/master/adapters/template/')
+  }
+
+  getAdapterCategories(): Observable<Object> {
+    return this.http.get(
+        this.baseUrl +
+        '/api/v2' +
+        "/categories/adapter"
+    )
+  }
+
+  private deleteRequest(adapter: AdapterDescription, url: String) {
+    return this.http.delete(
+      this.host +
+        'api/v1/' +
+        this.authStatusService.email +
+        url +
+        adapter.couchDbId
+    );
+  }
+
+  getProtocols(): Observable<ProtocolDescription[]> {
+    return this.http
+      .get(
+        this.host +
+          'api/v1/' +
+          this.authStatusService.email +
+          '/master/description/protocols'
+      )
+      .pipe(map(response => {
+        const res = this.tsonLdSerializer.fromJsonLd(
+          response,
+          'sp:ProtocolDescriptionList'
+        );
+        res.list.forEach(protocolDescription => {
+          protocolDescription.config.sort((a, b) => a.index - b.index);
+          protocolDescription.config.forEach(sp => {
+            this.sortStaticProperties(sp)
+          });
+        });
+        return res.list;
+      }));
+  }
+
+  sortStaticProperties(sp: StaticProperty) {
+    if (sp instanceof AlternativesStaticProperty) {
+      sp.alternatives.sort((a, b) => a.index - b.index);
+      sp.alternatives.forEach(a => {
+        if (a.staticProperty instanceof GroupStaticProperty) {
+          a.staticProperty.staticProperties.sort((a, b) => a.index - b.index);
+        }
+      })
+    } else if (sp instanceof GroupStaticProperty) {
+      sp.staticProperties.sort((a, b) => a.index - b.index);
+    }
+  }
+
+  getGenericAndSpecifigAdapterDescriptions(): Observable<
+    Observable<AdapterDescription[]>
+  > {
+    return this.getAdapterDescriptions().pipe(map(adapterDescriptions => {
+      adapterDescriptions = adapterDescriptions.filter(
+        this.connectService.isSpecificDescription
+      );
+
+      return this.getProtocols().pipe(map(protocols => {
+        for (let protocol of protocols) {
+          let newAdapterDescription: AdapterDescription;
+          if (protocol.id.includes('sp:protocol/set') || protocol.sourceType === 'SET') {
+            newAdapterDescription = new GenericAdapterSetDescription(
+              'http://streampipes.org/genericadaptersetdescription'
+            );
+          } else if (protocol.id.includes('sp:protocol/stream') || protocol.sourceType === 'STREAM') {
+            newAdapterDescription = new GenericAdapterStreamDescription(
+              'http://streampipes.org/genericadapterstreamdescription'
+            );
+          }
+          newAdapterDescription.label = protocol.label;
+          newAdapterDescription.description = protocol.description;
+          newAdapterDescription.iconUrl = protocol.iconUrl;
+          newAdapterDescription.uri = newAdapterDescription.id;
+          newAdapterDescription.category = protocol.category;
+
+          if (
+            newAdapterDescription instanceof GenericAdapterSetDescription ||
+            newAdapterDescription instanceof GenericAdapterStreamDescription
+          ) {
+            newAdapterDescription.protocol = protocol;
+          }
+          adapterDescriptions.push(newAdapterDescription);
+        }
+        return adapterDescriptions;
+      }));
+    }));
+  }
+
+  cloneAdapterDescription(toClone: AdapterDescription): AdapterDescription {
+    var result: AdapterDescription;
+
+      if (this.connectService.isGenericDescription(toClone)) {
+          if (this.connectService.isDataStreamDescription(toClone)) {
+              result = Object.assign(new GenericAdapterStreamDescription(toClone.id), toClone);
+          } else {
+              result = Object.assign(new GenericAdapterSetDescription(toClone.id), toClone);
+          }
+      } else {
+          if (this.connectService.isDataStreamDescription(toClone)) {
+              result = Object.assign(new SpecificAdapterStreamDescription(toClone.id), toClone);
+          } else {
+              result = Object.assign(new SpecificAdapterSetDescription(toClone.id), toClone);
+          }
+      }
+
+    return result;
+  }
+
+  getAssetUrl(appId) {
+    return this.host + 'api/v1/' + this.authStatusService.email + "/master/description/" + appId + "/assets"
+  }
+
+  private get baseUrl() {
+    return '/streampipes-backend';
+  }
+}
diff --git a/ui/src/app/connect/model/connect/AdapterDescription.ts b/ui/src/app/connect/model/connect/AdapterDescription.ts
index e3a2092..882124d 100644
--- a/ui/src/app/connect/model/connect/AdapterDescription.ts
+++ b/ui/src/app/connect/model/connect/AdapterDescription.ts
@@ -64,6 +64,19 @@ export class AdapterDescription {
   @RdfProperty('sp:config')
   public config: StaticProperty[] = [];
 
+  @RdfProperty('sp:includesAssets')
+  public includesAssets: Boolean;
+
+  @RdfProperty('sp:includesLocales')
+  public includesLocales: Boolean;
+
+  @RdfProperty('sp:includedAssets')
+  public includedAssets: string[] = [];
+
+  @RdfProperty('sp:includedLocales')
+  public includedLocales: string[] = [];
+
+
   public templateTitle: String;
 
   public isTemplate: boolean;
diff --git a/ui/src/app/connect/new-adapter/new-adapter.component.html b/ui/src/app/connect/new-adapter/new-adapter.component.html
index 0f84d91..955467b 100644
--- a/ui/src/app/connect/new-adapter/new-adapter.component.html
+++ b/ui/src/app/connect/new-adapter/new-adapter.component.html
@@ -54,7 +54,7 @@
                 </div>
                 <div class="sp-blue-border padding">
                     <app-static-property *ngFor="let config of adapter.config" [staticProperty]="config"
-                        [staticProperties]="adapter.config" [adapterId]="adapter.id"
+                        [staticProperties]="adapter.config" [adapterId]="adapter.appId"
                         (updateEmitter)="triggerUpdate($event)" [completedStaticProperty]="completedStaticProperty">
                     </app-static-property>
                     <app-protocol (validateEmitter)="validateProtocol($event)" [protocol]="adapter.protocol"
diff --git a/ui/src/app/connect/protocol-component/protocol.component.html b/ui/src/app/connect/protocol-component/protocol.component.html
index 3443d52..ff99ad7 100644
--- a/ui/src/app/connect/protocol-component/protocol.component.html
+++ b/ui/src/app/connect/protocol-component/protocol.component.html
@@ -16,4 +16,4 @@
   ~
   -->
 
-<app-select-static-properties [adapterId]="protocol.id" [staticProperties]="protocol.config" (validateEmitter)="validateText($event)" id="test"></app-select-static-properties>
\ No newline at end of file
+<app-select-static-properties [adapterId]="protocol.appId" [staticProperties]="protocol.config" (validateEmitter)="validateText($event)" id="test"></app-select-static-properties>
\ No newline at end of file


Mime
View raw message