From 384f028ef4574384a1bfb4cd0c94be4b5b90b12a Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Tue, 3 Sep 2019 20:24:10 -0400 Subject: [PATCH] Si eclipse integration start --- .../.classpath | 7 + .../.project | 28 +++ .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 9 + .../build.properties | 5 + .../plugin.xml | 14 ++ .../eclipse/si/view/LiveGraphView.java | 25 +++ .../commons/STS4LanguageClientImpl.java | 5 + headless-services/sprotty-si-view/build.sh | 1 + .../client/css/eclipse-page.css | 4 + .../sprotty-si-view/client/css/page.css | 2 +- .../sprotty-si-view/client/eclipse.html | 17 ++ .../sprotty-si-view/client/src/di.config.ts | 11 +- .../sprotty-si-view/client/src/layout.ts | 187 ++++++++++++++++++ .../sprotty-si-view/client/src/standalone.ts | 11 +- .../ide/si/view/SIDiagramGenerator.java | 45 +---- .../ide/si/view/SprottySiViewApplication.java | 5 +- 17 files changed, 337 insertions(+), 46 deletions(-) create mode 100644 eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.classpath create mode 100644 eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.project create mode 100644 eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.settings/org.eclipse.jdt.core.prefs create mode 100644 eclipse-language-servers/org.springframework.tooling.eclipse.si.view/META-INF/MANIFEST.MF create mode 100644 eclipse-language-servers/org.springframework.tooling.eclipse.si.view/build.properties create mode 100644 eclipse-language-servers/org.springframework.tooling.eclipse.si.view/plugin.xml create mode 100644 eclipse-language-servers/org.springframework.tooling.eclipse.si.view/src/org/springframework/tooling/eclipse/si/view/LiveGraphView.java create mode 100644 headless-services/sprotty-si-view/client/css/eclipse-page.css create mode 100644 headless-services/sprotty-si-view/client/eclipse.html create mode 100644 headless-services/sprotty-si-view/client/src/layout.ts diff --git a/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.classpath b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.classpath new file mode 100644 index 000000000..eca7bdba8 --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.project b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.project new file mode 100644 index 000000000..465f3fbeb --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.project @@ -0,0 +1,28 @@ + + + org.springframework.tooling.eclipse.si.view + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.settings/org.eclipse.jdt.core.prefs b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..0c68a61dc --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/META-INF/MANIFEST.MF new file mode 100644 index 000000000..1db9389f1 --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/META-INF/MANIFEST.MF @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Spring Integration View +Bundle-SymbolicName: org.springframework.tooling.eclipse.si.view;singleton:=true +Bundle-Version: 4.4.0.qualifier +Automatic-Module-Name: org.springframework.tooling.eclipse.si.view +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime diff --git a/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/build.properties b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/build.properties new file mode 100644 index 000000000..e9863e281 --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/plugin.xml b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/plugin.xml new file mode 100644 index 000000000..df2cc7868 --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/plugin.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/src/org/springframework/tooling/eclipse/si/view/LiveGraphView.java b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/src/org/springframework/tooling/eclipse/si/view/LiveGraphView.java new file mode 100644 index 000000000..4579f2a42 --- /dev/null +++ b/eclipse-language-servers/org.springframework.tooling.eclipse.si.view/src/org/springframework/tooling/eclipse/si/view/LiveGraphView.java @@ -0,0 +1,25 @@ +package org.springframework.tooling.eclipse.si.view; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.browser.Browser; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.part.ViewPart; + +public class LiveGraphView extends ViewPart { + + private Browser browser; + + @Override + public void createPartControl(Composite parent) { + browser = new Browser(parent, SWT.NONE); + browser.setUrl("http://localhost:8877"); + } + + @Override + public void setFocus() { + if (!browser.isFocusControl()) { + browser.setFocus(); + } + } + +} diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java index f25b587e9..53e870543 100644 --- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java +++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.commons/src/org/springframework/tooling/ls/eclipse/commons/STS4LanguageClientImpl.java @@ -96,6 +96,7 @@ import org.springframework.tooling.ls.eclipse.commons.preferences.PreferenceCons import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonObject; @SuppressWarnings("restriction") public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4LanguageClient { @@ -540,4 +541,8 @@ public class STS4LanguageClientImpl extends LanguageClientImpl implements STS4La }); } + @Override + public void sprottyMessage(JsonObject message) { + } + } diff --git a/headless-services/sprotty-si-view/build.sh b/headless-services/sprotty-si-view/build.sh index 1963f357e..6a50da321 100755 --- a/headless-services/sprotty-si-view/build.sh +++ b/headless-services/sprotty-si-view/build.sh @@ -19,6 +19,7 @@ mkdir -p $static_dir echo "cp ${client_dir}/bundle* $static_dir" cp ${client_dir}/bundle* $static_dir cp ${client_dir}/index.html $static_dir +cp ${client_dir}/eclipse.html $static_dir cp -R ${client_dir}/css $static_dir/css cp -R ${client_dir}/lib $static_dir/lib cp -R ${client_dir}/src $static_dir/src diff --git a/headless-services/sprotty-si-view/client/css/eclipse-page.css b/headless-services/sprotty-si-view/client/css/eclipse-page.css new file mode 100644 index 000000000..e57c4103a --- /dev/null +++ b/headless-services/sprotty-si-view/client/css/eclipse-page.css @@ -0,0 +1,4 @@ +svg { + width: 100%; + height: 100vh; +} diff --git a/headless-services/sprotty-si-view/client/css/page.css b/headless-services/sprotty-si-view/client/css/page.css index 555630d7d..59d355034 100644 --- a/headless-services/sprotty-si-view/client/css/page.css +++ b/headless-services/sprotty-si-view/client/css/page.css @@ -38,7 +38,7 @@ svg { margin-top: 15px; width: 100%; - height: 500px; + height: 600px; border-style: solid; border-width: 1px; border-color: #bbb; diff --git a/headless-services/sprotty-si-view/client/eclipse.html b/headless-services/sprotty-si-view/client/eclipse.html new file mode 100644 index 000000000..6a3391d90 --- /dev/null +++ b/headless-services/sprotty-si-view/client/eclipse.html @@ -0,0 +1,17 @@ + + + + + + Spring Integration Graph + + + + + +
+
+ + + + \ No newline at end of file diff --git a/headless-services/sprotty-si-view/client/src/di.config.ts b/headless-services/sprotty-si-view/client/src/di.config.ts index 4808fcd06..ee4866d55 100644 --- a/headless-services/sprotty-si-view/client/src/di.config.ts +++ b/headless-services/sprotty-si-view/client/src/di.config.ts @@ -51,7 +51,7 @@ import { HtmlRoot, PreRenderedView, PreRenderedElement, - labelEditModule, edgeEditModule, RectangularPort + labelEditModule, edgeEditModule, RectangularPort, LayoutRegistry, VBoxLayouter, HBoxLayouter } from "sprotty"; import { IntegrationNodeView, @@ -65,6 +65,7 @@ import { import fadeModule from "sprotty/lib/features/fade/di.config"; import buttonModule from "sprotty/lib/features/button/di.config"; import expandModule from "sprotty/lib/features/expand/di.config"; +import {MyHBoxLayouter, MyVBoxLayouter} from "./layout"; export enum TransportMedium { None, @@ -113,5 +114,13 @@ export default (transport: TransportMedium, clientId: string) => { viewportModule, fadeModule, hoverModule, exportModule, expandModule, buttonModule, updateModule, graphModule, routingModule, edgeEditModule, edgeLayoutModule, labelEditModule, modelSourceModule, integrationGaphModule); + + const layoutRegistry = container.get(TYPES.LayoutRegistry); + layoutRegistry.deregister(VBoxLayouter.KIND); + layoutRegistry.register(VBoxLayouter.KIND, new MyVBoxLayouter()); + layoutRegistry.deregister(HBoxLayouter.KIND); + layoutRegistry.register(HBoxLayouter.KIND, new MyHBoxLayouter()); + + return container; }; diff --git a/headless-services/sprotty-si-view/client/src/layout.ts b/headless-services/sprotty-si-view/client/src/layout.ts new file mode 100644 index 000000000..cc1aad52e --- /dev/null +++ b/headless-services/sprotty-si-view/client/src/layout.ts @@ -0,0 +1,187 @@ +/******************************************************************************** + * Copyright (c) 2017-2018 TypeFox and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ + +import { Bounds, + Point, + isValidDimension, + SParentElement, + SChildElement, + LayoutContainer, + isLayoutableChild, + StatefulLayouter } from 'sprotty'; +import {AbstractLayoutOptions, HAlignment, VAlignment} from "sprotty/lib/features/bounds/layout-options"; +import {AbstractLayout} from "sprotty/lib/features/bounds/abstract-layout"; +import {BoundsData} from "sprotty/lib/features/bounds/hidden-bounds-updater"; + +export interface VBoxLayoutOptions extends AbstractLayoutOptions { + vGap: number + hAlign: HAlignment +} + +/** + * Layouts children of a container in vertical (top->bottom) direction. + */ +export class MyVBoxLayouter extends AbstractLayout { + + protected getChildrenSize(container: SParentElement & LayoutContainer, + containerOptions: VBoxLayoutOptions, + layouter: StatefulLayouter) { + let maxWidth = containerOptions.minWidth; + let maxHeight = 0; + let isFirst = true; + container.children.forEach( + child => { + if (isLayoutableChild(child)) { + const bounds = layouter.getBoundsData(child).bounds; + if (bounds !== undefined && isValidDimension(bounds)) { + maxHeight += bounds.height; + if (isFirst) + isFirst = false; + else + maxHeight += containerOptions.vGap; + maxWidth = Math.max(maxWidth, bounds.width); + } + } + } + ); + return { + width: maxWidth, + height: maxHeight + }; + } + + protected layoutChild(child: SChildElement, + boundsData: BoundsData, + bounds: Bounds, + childOptions: VBoxLayoutOptions, + containerOptions: VBoxLayoutOptions, + currentOffset: Point, + maxWidth: number, + maxHeight: number) { + const dx = this.getDx(childOptions.hAlign, bounds, maxWidth); + boundsData.bounds = { + x: containerOptions.paddingLeft + (child as any).bounds.x - bounds.x + dx, + y: currentOffset.y + (child as any).bounds.y - bounds.y, + width: bounds.width, + height: bounds.height + }; + boundsData.boundsChanged = true; + return { + x: currentOffset.x, + y: currentOffset.y + bounds.height + containerOptions.vGap + }; + } + + protected getDefaultLayoutOptions(): VBoxLayoutOptions { + return { + resizeContainer: true, + paddingTop: 5, + paddingBottom: 5, + paddingLeft: 5, + paddingRight: 5, + paddingFactor: 1, + vGap: 1, + hAlign: 'center', + minWidth: 0, + minHeight: 0 + }; + } + + protected spread(a: VBoxLayoutOptions, b: VBoxLayoutOptions): VBoxLayoutOptions { + return { ...a, ...b }; + } +} + +export interface HBoxLayoutOptions extends AbstractLayoutOptions { + hGap: number + vAlign: VAlignment +} + +/** + * Layouts children of a container in horizontal (left->right) direction. + */ +export class MyHBoxLayouter extends AbstractLayout { + + protected getChildrenSize(container: SParentElement & LayoutContainer, + containerOptions: HBoxLayoutOptions, + layouter: StatefulLayouter) { + let maxWidth = 0; + let maxHeight = containerOptions.minHeight; + let isFirst = true; + container.children.forEach( + child => { + if (isLayoutableChild(child)) { + const bounds = layouter.getBoundsData(child).bounds; + if (bounds !== undefined && isValidDimension(bounds)) { + if (isFirst) + isFirst = false; + else + maxWidth += containerOptions.hGap; + maxWidth += bounds.width; + maxHeight = Math.max(maxHeight, bounds.height); + } + } + } + ); + return { + width: maxWidth, + height: maxHeight + }; + } + + protected layoutChild(child: SChildElement, + boundsData: BoundsData, + bounds: Bounds, + childOptions: HBoxLayoutOptions, + containerOptions: HBoxLayoutOptions, + currentOffset: Point, + maxWidth: number, + maxHeight: number): Point { + const dy = this.getDy(childOptions.vAlign, bounds, maxHeight); + boundsData.bounds = { + x: currentOffset.x + (child as any).bounds.x - bounds.x, + y: containerOptions.paddingTop + (child as any).bounds.y - bounds.y + dy, + width: bounds.width, + height: bounds.height + }; + boundsData.boundsChanged = true; + return { + x: currentOffset.x + bounds.width + containerOptions.hGap, + y: currentOffset.y + }; + } + + protected getDefaultLayoutOptions(): HBoxLayoutOptions { + return { + resizeContainer: true, + paddingTop: 5, + paddingBottom: 5, + paddingLeft: 5, + paddingRight: 5, + paddingFactor: 1, + hGap: 1, + vAlign: 'center', + minWidth: 0, + minHeight: 0 + }; + } + + protected spread(a: HBoxLayoutOptions, b: HBoxLayoutOptions): HBoxLayoutOptions { + return { ...a, ...b }; + } + +} + diff --git a/headless-services/sprotty-si-view/client/src/standalone.ts b/headless-services/sprotty-si-view/client/src/standalone.ts index 6670ad700..429fb705c 100644 --- a/headless-services/sprotty-si-view/client/src/standalone.ts +++ b/headless-services/sprotty-si-view/client/src/standalone.ts @@ -51,9 +51,12 @@ export default function runStandalone() { } // Button features - document.getElementById('refresh')!.addEventListener('click', () => { - dispatcher.dispatch(requestModelAction()); - }); + const refreshButton = document.getElementById('refresh'); + if (refreshButton) { + refreshButton.addEventListener('click', () => { + dispatcher.dispatch(requestModelAction()); + }); + } function getOptionFromDom(att: string) : string | null { const appDiv = document.getElementById('sprotty-app'); @@ -66,7 +69,7 @@ export default function runStandalone() { function getTarget() : string { const input = document.getElementById('target-url'); const target = input && input.value; - return target || 'target-missing'; + return target || /*'target-missing'*/'http://localhost:8080/integration'; } function requestModelAction() : RequestModelAction { diff --git a/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SIDiagramGenerator.java b/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SIDiagramGenerator.java index ffc3c4038..b16771ffe 100644 --- a/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SIDiagramGenerator.java +++ b/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SIDiagramGenerator.java @@ -11,7 +11,6 @@ import org.eclipse.sprotty.EdgePlacement.Side; import org.eclipse.sprotty.LayoutOptions; import org.eclipse.sprotty.Point; import org.eclipse.sprotty.RequestModelAction; -import org.eclipse.sprotty.SCompartment; import org.eclipse.sprotty.SEdge; import org.eclipse.sprotty.SGraph; import org.eclipse.sprotty.SLabel; @@ -40,12 +39,10 @@ import com.google.gson.JsonObject; @Component public class SIDiagramGenerator implements DiagramGenerator { + private static final double INTEGRATION_NODE_VERTICAL_PADDING = 20.0; + static final String TYPE_INTEGRATION_GRAPH = "graph"; - private static final double CHANNEL_HEIGHT = 40D; - - private static final double NODE_MIN_HEIGHT = 80D; - private static final double MIN_WIDTH = 120D; private static final Logger log = LoggerFactory.getLogger(SIDiagramGenerator.class); @@ -113,20 +110,9 @@ public class SIDiagramGenerator implements DiagramGenerator { String sourceId = link.getFrom()+""; String targetId = link.getTo()+""; - SEdge e = createEdge(id, sourceId, targetId, getEdgeLabel(nodesById.get(sourceId)), link.getType()); children.add(e); } - // - // LiveBeansModel beansModel = app.getBeans(); - // for (String targetBeanId : beansModel.getBeanNames()) { - // for (LiveBean bean : beansModel.getBeansOfName(targetBeanId)) { - // graphChildren.add(createBean(bean.getId(), bean.getShortName(), new Point(), new Dimension())); - // } - // for (LiveBean sourceBean : beansModel.getBeansDependingOn(targetBeanId)) { - // graphChildren.add(createEdge(sourceBean.getId() + " " + targetBeanId, sourceBean.getId(), targetBeanId)); - // } - // } return graph; } @@ -152,37 +138,19 @@ public class SIDiagramGenerator implements DiagramGenerator { SNode node = new SNode(); node.setId(id); node.setType("node:"+type); - node.setLayout("hbox"); - node.setPosition(new Point(Math.random() * 1024, Math.random() * 768)); + node.setLayout("vbox"); node.setSize(new Dimension(80, 80)); node.setChildren(new ArrayList<>()); centerNode(node); - SCompartment compartment = new SCompartment(); - node.getChildren().add(compartment); - compartment.setId(id + "-comp"); - compartment.setType("compartment"); - compartment.setLayout("vbox"); - compartment.setChildren(new ArrayList<>()); - centerNode(compartment); - { SLabel label = new SLabel(); label.setId(id + "-label"); label.setType("node:label"); label.setText(labelText); centerNode(label); - compartment.getChildren().add(label); + node.getChildren().add(label); } - { - SLabel label = new SLabel(); - label.setId(id + "-label-test"); - label.setType("node:label"); - label.setText("s"); - centerNode(label); - compartment.getChildren().add(label); - } - SPort outputPort = new SPort(); outputPort.setType("output-port"); @@ -208,12 +176,13 @@ public class SIDiagramGenerator implements DiagramGenerator { options.setHAlign("center"); options.setVAlign("center"); } - + private static SNode createIntegrationNode(String id, String labelText) { SNode node = createNode(id, labelText, "integration_node"); LayoutOptions layoutOptions = new LayoutOptions(); - layoutOptions.setMinHeight(NODE_MIN_HEIGHT); layoutOptions.setMinWidth(MIN_WIDTH); + layoutOptions.setPaddingBottom(INTEGRATION_NODE_VERTICAL_PADDING); + layoutOptions.setPaddingTop(20.0); node.setLayoutOptions(layoutOptions); SPort errorPort = new SPort(); diff --git a/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SprottySiViewApplication.java b/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SprottySiViewApplication.java index caab7274c..6fbadcb2c 100644 --- a/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SprottySiViewApplication.java +++ b/headless-services/sprotty-si-view/src/main/java/org/springframework/ide/si/view/SprottySiViewApplication.java @@ -1,5 +1,6 @@ package org.springframework.ide.si.view; +import org.eclipse.elk.alg.layered.options.FixedAlignment; import org.eclipse.elk.alg.layered.options.LayeredOptions; import org.eclipse.elk.core.options.PortConstraints; import org.eclipse.elk.core.options.PortSide; @@ -8,7 +9,6 @@ import org.eclipse.sprotty.layout.SprottyLayoutConfigurator; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -import org.springframework.ide.si.view.json.SpringIntegrationGraphJson; @SpringBootApplication public class SprottySiViewApplication { @@ -26,7 +26,8 @@ public class SprottySiViewApplication { IPropertyHolder holder = configurator.configureByType(SIDiagramGenerator.TYPE_INTEGRATION_GRAPH); holder.setProperty(LayeredOptions.SPACING_COMPONENT_COMPONENT, 60.0); holder.setProperty(LayeredOptions.SPACING_NODE_NODE_BETWEEN_LAYERS, 60.0); - + holder.setProperty(LayeredOptions.NODE_PLACEMENT_BK_FIXED_ALIGNMENT, FixedAlignment.BALANCED); + holder = configurator.configureByType("output-port"); holder.setProperty(LayeredOptions.PORT_SIDE, PortSide.EAST);