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 2020/05/20 22:01:20 UTC

[incubator-streampipes] branch dev updated: [STREAMPIPES-134]: Add initial version of UserDefinedOutputStrategy

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

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


The following commit(s) were added to refs/heads/dev by this push:
     new c5d8ecd  [STREAMPIPES-134]: Add initial version of UserDefinedOutputStrategy
c5d8ecd is described below

commit c5d8ecd9f50ec88cb3180682b13e2a2d49c08bdd
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Thu May 21 00:01:07 2020 +0200

    [STREAMPIPES-134]: Add initial version of UserDefinedOutputStrategy
---
 .../model/output/UserDefinedOutputStrategy.java    | 57 ++++++++++++++
 .../org/apache/streampipes/model/util/Cloner.java  | 13 +---
 .../matching/output/OutputSchemaFactory.java       | 11 +--
 .../output/UserDefinedOutputSchemaGenerator.java   | 50 +++++++++++++
 .../streampipes/sdk/helpers/OutputStrategies.java  | 18 +++--
 .../jsonld/CustomAnnotationProvider.java           |  1 +
 .../apache/streampipes/vocabulary/StreamPipes.java |  1 +
 .../user-defined-output.component.ts               | 33 ++++++++
 .../user-defined-output.controller.ts              | 87 ++++++++++++++++++++++
 .../user-defined-output.tmpl.html                  | 55 ++++++++++++++
 .../customizeElementDialog.tmpl.html               | 12 ++-
 ui/src/app/editor/editor.module.ts                 |  2 +
 12 files changed, 312 insertions(+), 28 deletions(-)

diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/output/UserDefinedOutputStrategy.java b/streampipes-model/src/main/java/org/apache/streampipes/model/output/UserDefinedOutputStrategy.java
new file mode 100644
index 0000000..e364dc3
--- /dev/null
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/output/UserDefinedOutputStrategy.java
@@ -0,0 +1,57 @@
+/*
+ * 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.output;
+
+import io.fogsy.empire.annotations.RdfProperty;
+import io.fogsy.empire.annotations.RdfsClass;
+import org.apache.streampipes.model.schema.EventProperty;
+import org.apache.streampipes.vocabulary.StreamPipes;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.OneToMany;
+import java.util.List;
+
+@RdfsClass(StreamPipes.USER_DEFINED_OUTPUT_STRATEGY)
+@Entity
+public class UserDefinedOutputStrategy extends OutputStrategy {
+
+  @OneToMany(fetch = FetchType.EAGER,
+          cascade = {CascadeType.ALL})
+  @RdfProperty(StreamPipes.PRODUCES_PROPERTY)
+  private List<EventProperty> eventProperties;
+
+  public UserDefinedOutputStrategy() {
+    super();
+  }
+
+  public UserDefinedOutputStrategy(UserDefinedOutputStrategy other) {
+    super(other);
+    this.eventProperties = other.getEventProperties();
+  }
+
+  public List<EventProperty> getEventProperties() {
+    return eventProperties;
+  }
+
+  public void setEventProperties(List<EventProperty> eventProperties) {
+    this.eventProperties = eventProperties;
+  }
+}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/util/Cloner.java b/streampipes-model/src/main/java/org/apache/streampipes/model/util/Cloner.java
index 4f66239..7d3b871 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/util/Cloner.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/util/Cloner.java
@@ -18,6 +18,7 @@
 
 package org.apache.streampipes.model.util;
 
+import org.apache.streampipes.model.output.*;
 import org.apache.streampipes.model.staticproperty.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,16 +43,6 @@ import org.apache.streampipes.model.grounding.TransportFormat;
 import org.apache.streampipes.model.grounding.TransportProtocol;
 import org.apache.streampipes.model.grounding.WildcardTopicDefinition;
 import org.apache.streampipes.model.grounding.WildcardTopicMapping;
-import org.apache.streampipes.model.output.AppendOutputStrategy;
-import org.apache.streampipes.model.output.CustomOutputStrategy;
-import org.apache.streampipes.model.output.CustomTransformOutputStrategy;
-import org.apache.streampipes.model.output.FixedOutputStrategy;
-import org.apache.streampipes.model.output.KeepOutputStrategy;
-import org.apache.streampipes.model.output.ListOutputStrategy;
-import org.apache.streampipes.model.output.OutputStrategy;
-import org.apache.streampipes.model.output.PropertyRenameRule;
-import org.apache.streampipes.model.output.TransformOperation;
-import org.apache.streampipes.model.output.TransformOutputStrategy;
 import org.apache.streampipes.model.quality.Accuracy;
 import org.apache.streampipes.model.quality.EventPropertyQualityDefinition;
 import org.apache.streampipes.model.quality.EventPropertyQualityRequirement;
@@ -89,6 +80,8 @@ public class Cloner {
       return new TransformOutputStrategy((TransformOutputStrategy) other);
     } else if (other instanceof CustomTransformOutputStrategy) {
       return new CustomTransformOutputStrategy((CustomTransformOutputStrategy) other);
+    } else if (other instanceof UserDefinedOutputStrategy) {
+      return new UserDefinedOutputStrategy((UserDefinedOutputStrategy) other);
     } else {
       return new AppendOutputStrategy((AppendOutputStrategy) other);
     }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/OutputSchemaFactory.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/OutputSchemaFactory.java
index 9859a06..2828b8a 100644
--- a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/OutputSchemaFactory.java
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/OutputSchemaFactory.java
@@ -19,14 +19,7 @@
 package org.apache.streampipes.manager.matching.output;
 
 import org.apache.streampipes.model.graph.DataProcessorInvocation;
-import org.apache.streampipes.model.output.AppendOutputStrategy;
-import org.apache.streampipes.model.output.CustomOutputStrategy;
-import org.apache.streampipes.model.output.CustomTransformOutputStrategy;
-import org.apache.streampipes.model.output.FixedOutputStrategy;
-import org.apache.streampipes.model.output.KeepOutputStrategy;
-import org.apache.streampipes.model.output.ListOutputStrategy;
-import org.apache.streampipes.model.output.OutputStrategy;
-import org.apache.streampipes.model.output.TransformOutputStrategy;
+import org.apache.streampipes.model.output.*;
 
 public class OutputSchemaFactory {
 
@@ -53,6 +46,8 @@ public class OutputSchemaFactory {
       return TransformOutputSchemaGenerator.from(outputStrategy, dataProcessorInvocation);
     } else if (outputStrategy instanceof CustomTransformOutputStrategy) {
       return CustomTransformOutputSchemaGenerator.from(outputStrategy, dataProcessorInvocation);
+    } else if (outputStrategy instanceof UserDefinedOutputStrategy) {
+      return UserDefinedOutputSchemaGenerator.from(outputStrategy);
     } else {
       throw new IllegalArgumentException();
     }
diff --git a/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/UserDefinedOutputSchemaGenerator.java b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/UserDefinedOutputSchemaGenerator.java
new file mode 100644
index 0000000..e070f98
--- /dev/null
+++ b/streampipes-pipeline-management/src/main/java/org/apache/streampipes/manager/matching/output/UserDefinedOutputSchemaGenerator.java
@@ -0,0 +1,50 @@
+package org.apache.streampipes.manager.matching.output;/*
+ * 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 org.apache.streampipes.model.SpDataStream;
+import org.apache.streampipes.model.output.OutputStrategy;
+import org.apache.streampipes.model.output.UserDefinedOutputStrategy;
+import org.apache.streampipes.model.schema.EventProperty;
+import org.apache.streampipes.model.schema.EventSchema;
+import org.apache.streampipes.sdk.helpers.Tuple2;
+
+import java.util.List;
+
+public class UserDefinedOutputSchemaGenerator extends OutputSchemaGenerator<UserDefinedOutputStrategy> {
+
+  private List<EventProperty> producedProperties;
+
+  public static UserDefinedOutputSchemaGenerator from(OutputStrategy strategy) {
+    return new UserDefinedOutputSchemaGenerator((UserDefinedOutputStrategy) strategy);
+  }
+
+  public UserDefinedOutputSchemaGenerator(UserDefinedOutputStrategy strategy) {
+    super(strategy);
+    this.producedProperties = strategy.getEventProperties();
+  }
+
+  @Override
+  public Tuple2<EventSchema, UserDefinedOutputStrategy> buildFromOneStream(SpDataStream stream) {
+    return makeTuple(new EventSchema(producedProperties));
+  }
+
+  @Override
+  public Tuple2<EventSchema, UserDefinedOutputStrategy> buildFromTwoStreams(SpDataStream stream1, SpDataStream stream2) {
+    return buildFromOneStream(stream1);
+  }
+}
diff --git a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/OutputStrategies.java b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/OutputStrategies.java
index 11f8414..e58e6b2 100644
--- a/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/OutputStrategies.java
+++ b/streampipes-sdk/src/main/java/org/apache/streampipes/sdk/helpers/OutputStrategies.java
@@ -18,14 +18,7 @@
 
 package org.apache.streampipes.sdk.helpers;
 
-import org.apache.streampipes.model.output.AppendOutputStrategy;
-import org.apache.streampipes.model.output.CustomOutputStrategy;
-import org.apache.streampipes.model.output.CustomTransformOutputStrategy;
-import org.apache.streampipes.model.output.FixedOutputStrategy;
-import org.apache.streampipes.model.output.KeepOutputStrategy;
-import org.apache.streampipes.model.output.ListOutputStrategy;
-import org.apache.streampipes.model.output.TransformOperation;
-import org.apache.streampipes.model.output.TransformOutputStrategy;
+import org.apache.streampipes.model.output.*;
 import org.apache.streampipes.model.schema.EventProperty;
 
 import java.util.Arrays;
@@ -91,6 +84,15 @@ public class OutputStrategies {
         return new KeepOutputStrategy();
     }
 
+    /**
+     * Creates a {@link org.apache.streampipes.model.output.UserDefinedOutputStrategy}. User-defined output strategies are
+     * fully flexible output strategies which are created by users at pipeline development time.
+     * @return UserDefinedOutputStrategy
+     */
+    public static UserDefinedOutputStrategy userDefined() {
+        return new UserDefinedOutputStrategy();
+    }
+
     public static KeepOutputStrategy keep(boolean mergeInputStreams) {
         return new KeepOutputStrategy("Rename", mergeInputStreams);
     }
diff --git a/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java b/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java
index b04b7f1..91c8a62 100644
--- a/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java
+++ b/streampipes-serializers/src/main/java/org/apache/streampipes/serializers/jsonld/CustomAnnotationProvider.java
@@ -191,6 +191,7 @@ public class CustomAnnotationProvider implements EmpireAnnotationProvider {
             EventRateTransformationRuleDescription.class,
             SecretStaticProperty.class,
             DashboardWidgetModel.class,
+            UserDefinedOutputStrategy.class,
             VisualizablePipeline.class,
             StreamPipesJsonLdContainer.class
 
diff --git a/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java b/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java
index 2beb33a..55e3ac0 100644
--- a/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java
+++ b/streampipes-vocabulary/src/main/java/org/apache/streampipes/vocabulary/StreamPipes.java
@@ -386,4 +386,5 @@ public class StreamPipes {
   public static final String HAS_LANGUAGE = NS + "hasLanguage";
   public static final String HAS_CODE_INPUT = NS + "hasCodeInput";
   public static final String HAS_CODE_TEMPLATE = NS + "hasCodeTemplate";
+  public static final String USER_DEFINED_OUTPUT_STRATEGY = NS + "UserDefinedOutputStrategy";
 }
diff --git a/ui/src/app/editor/components/userdefinedoutput/user-defined-output.component.ts b/ui/src/app/editor/components/userdefinedoutput/user-defined-output.component.ts
new file mode 100644
index 0000000..d89210e
--- /dev/null
+++ b/ui/src/app/editor/components/userdefinedoutput/user-defined-output.component.ts
@@ -0,0 +1,33 @@
+/*
+ * 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 {UserDefinedOutputController} from "./user-defined-output.controller";
+
+declare const require: any;
+
+export let UserDefinedOutputComponent = {
+    template: require('./user-defined-output.tmpl.html'),
+    bindings: {
+        outputStrategy: "=",
+        selectedElement: "=",
+        customizeForm: "=",
+        restrictedEditMode: "<"
+    },
+    controller: UserDefinedOutputController,
+    controllerAs: 'ctrl'
+};
diff --git a/ui/src/app/editor/components/userdefinedoutput/user-defined-output.controller.ts b/ui/src/app/editor/components/userdefinedoutput/user-defined-output.controller.ts
new file mode 100644
index 0000000..d605049
--- /dev/null
+++ b/ui/src/app/editor/components/userdefinedoutput/user-defined-output.controller.ts
@@ -0,0 +1,87 @@
+/*
+ * 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 {RdfId} from "../../../platform-services/tsonld/RdfId";
+
+export class UserDefinedOutputController {
+
+    private prefix = "urn:streampipes.org:spi:";
+    private chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    outputStrategy: any;
+    selectedElement: any;
+    collectedPropertiesFirstStream: any;
+    collectedPropertiesSecondStream: any;
+    customizeForm: any;
+
+    primitiveClasses = [{"label": "String", "id": "http://www.w3.org/2001/XMLSchema#string"},
+        {"label": "Boolean", "id": "http://www.w3.org/2001/XMLSchema#boolean"},
+        {"label": "Integer", "id": "http://www.w3.org/2001/XMLSchema#integer"},
+        {"label": "Long", "id": "http://www.w3.org/2001/XMLSchema#long"},
+        {"label": "Double", "id": "http://www.w3.org/2001/XMLSchema#double"},
+        {"label": "Float", "id": "http://www.w3.org/2001/XMLSchema#float"}];
+
+    constructor() {
+
+    }
+
+    $onInit() {
+        if (!this.outputStrategy.properties.eventProperties) {
+            this.outputStrategy.properties.eventProperties = [];
+        }
+    }
+
+    applyDefaultSchema() {
+        this.outputStrategy.properties.eventProperties =
+            this.selectedElement.inputStreams[0].eventSchema.eventProperties;
+    }
+
+    removeProperty(ep: any) {
+        this.outputStrategy.properties.eventProperties
+            .splice(this.outputStrategy.properties.eventProperties.indexOf(ep), 1);
+    }
+
+    addProperty() {
+        this.outputStrategy.properties.eventProperties.push(this.makeDefaultProperty());
+    }
+
+    makeDefaultProperty() {
+        let ep = {} as any;
+        ep.type = "org.apache.streampipes.model.schema.EventPropertyPrimitive";
+        ep.properties = {};
+        ep.properties.domainProperties = [];
+        ep.properties.elementId = "urn:streampipes.org:spi:eventpropertyprimitive:" + this.makeId();
+
+        return ep;
+    }
+
+   makeId() {
+        return this.prefix + this.randomString(6);
+    }
+
+    randomString(length) {
+        let result = '';
+        for (let i = length; i > 0; --i) result += this.chars[Math.floor(Math.random() * this.chars.length)];
+        return result;
+    }
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/ui/src/app/editor/components/userdefinedoutput/user-defined-output.tmpl.html b/ui/src/app/editor/components/userdefinedoutput/user-defined-output.tmpl.html
new file mode 100644
index 0000000..ad56102
--- /dev/null
+++ b/ui/src/app/editor/components/userdefinedoutput/user-defined-output.tmpl.html
@@ -0,0 +1,55 @@
+<!--
+  ~ 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 flex="100" layout="row" layout-align="start center" style="margin-bottom:20px;">
+    <sp-button sp-button-blue sp-button-small-padding ng-click="ctrl.applyDefaultSchema()" ng-disabled="ctrl.restrictedEditMode">Use input schema
+    </sp-button>&nbsp;&nbsp;
+</div>
+
+<div flex="100" layout="row" ng-repeat="ep in ctrl.outputStrategy.properties.eventProperties track by $index">
+    <div layout="column" flex="30">
+        <md-input-container flex="100">
+            <label>Runtime name</label>
+            <input ng-model="ep.properties.runtimeName" ng-disabled="ctrl.restrictedEditMode">
+        </md-input-container>
+    </div>
+    <div layout="column" flex="30">
+        <md-input-container>
+            <label>Runtime type</label>
+            <md-select ng-model="ep.properties.runtimeType" ng-disabled="ctrl.restrictedEditMode">
+                <md-option ng-repeat="primitive in ctrl.primitiveClasses" ng-value="primitive.id">
+                    {{primitive.label}}
+                </md-option>
+            </md-select>
+        </md-input-container>
+    </div>
+    <div layout="column" flex="30">
+        <md-input-container flex="100">
+            <label>Semantic type</label>
+            <input ng-model="ep.properties.domainProperties[0]" ng-disabled="ctrl.restrictedEditMode">
+        </md-input-container>
+    </div>
+    <div layout="column" flex="10">
+        <md-button class="md-icon-button" ng-click="ctrl.removeProperty(ep)" ng-disabled="ctrl.restrictedEditMode">
+            <i class="material-icons">delete</i>
+        </md-button>
+    </div>
+</div>
+<md-button ng-click="ctrl.addProperty()" ng-disabled="ctrl.restrictedEditMode">
+    Add Field
+</md-button>
diff --git a/ui/src/app/editor/dialog/customize-pipeline-element/customizeElementDialog.tmpl.html b/ui/src/app/editor/dialog/customize-pipeline-element/customizeElementDialog.tmpl.html
index 24b38e7..87cafed 100644
--- a/ui/src/app/editor/dialog/customize-pipeline-element/customizeElementDialog.tmpl.html
+++ b/ui/src/app/editor/dialog/customize-pipeline-element/customizeElementDialog.tmpl.html
@@ -103,7 +103,8 @@
                                     </div>
                                 </div>
                             </div>
-                            <div ng-if="outputStrategy.type === 'org.apache.streampipes.model.output.CustomOutputStrategy'">
+                            <div ng-if="outputStrategy.type === 'org.apache.streampipes.model.output.CustomOutputStrategy' ||
+                                        outputStrategy.type === 'org.apache.streampipes.model.output.UserDefinedOutputStrategy'">
                                 <div layout="column" class="customize-item-main sp-blue-border-nopadding">
                                     <div class="customize-item-title sp-blue-bg" layout="row" flex="100">
                                         <div flex="80" layout="row" layout-align="start center">
@@ -114,13 +115,20 @@
 
                                         </div>
                                     </div>
-                                    <div class="customize-item-content">
+                                    <div class="customize-item-content" ng-if="outputStrategy.type === 'org.apache.streampipes.model.output.CustomOutputStrategy'">
                                         <custom-output output-strategy="outputStrategy"
                                                        selected-element="ctrl.selectedElement"
                                                        customize-form="ctrl.customizeForm"
                                                        restricted-edit-mode="ctrl.restrictedEditMode">
                                         </custom-output>
                                     </div>
+                                    <div class="customize-item-content" ng-if="outputStrategy.type === 'org.apache.streampipes.model.output.UserDefinedOutputStrategy'">
+                                        <user-defined-output output-strategy="outputStrategy"
+                                                       selected-element="ctrl.selectedElement"
+                                                       customize-form="ctrl.customizeForm"
+                                                       restricted-edit-mode="ctrl.restrictedEditMode">
+                                        </user-defined-output>
+                                    </div>
                                 </div>
                             </div>
                         </div>
diff --git a/ui/src/app/editor/editor.module.ts b/ui/src/app/editor/editor.module.ts
index 1305c2a..db4c26e 100644
--- a/ui/src/app/editor/editor.module.ts
+++ b/ui/src/app/editor/editor.module.ts
@@ -73,6 +73,7 @@ import {FileUploadComponent} from "./components/fileupload/fileupload.component"
 import {AnyRemoteComponent} from "./components/any-remote/any-remote.component";
 import {CodeInputComponent} from "./components/code/code.component";
 import {CodeEditorDirective} from "./components/code/code-editor.directive";
+import {UserDefinedOutputComponent} from "./components/userdefinedoutput/user-defined-output.component";
 
 
 export default angular.module('sp.editor', [spServices, 'ngSanitize', 'angularTrix', 'ngAnimate', 'datatables', 'ng-showdown'])
@@ -87,6 +88,7 @@ export default angular.module('sp.editor', [spServices, 'ngSanitize', 'angularTr
     .component('any', AnyComponent)
     .component('anyRemote', AnyRemoteComponent)
     .component('customOutput', CustomOutputComponent)
+    .component('userDefinedOutput', UserDefinedOutputComponent)
     .component('domainConceptInput', DomainConceptComponent)
     .component('freetext', FreeTextComponent)
     .component('secret', SecretComponent)