Initial POC
This commit is contained in:
@@ -120,6 +120,14 @@ public class LiveBean {
|
||||
public String[] getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
int idx = id.lastIndexOf('.');
|
||||
if (idx >= 0) {
|
||||
return id.substring(idx + 1);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
40
headless-services/commons/commons-sprotty/pom.xml
Normal file
40
headless-services/commons/commons-sprotty/pom.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.ide.vscode</groupId>
|
||||
<artifactId>commons-parent</artifactId>
|
||||
<version>1.11.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>commons-sprotty</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.sprotty</groupId>
|
||||
<artifactId>org.eclipse.sprotty.server</artifactId>
|
||||
<version>${sprotty-version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.eclipse.elk/org.eclipse.elk.core -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.elk</groupId>
|
||||
<artifactId>org.eclipse.elk.core</artifactId>
|
||||
<version>${elk-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.elk</groupId>
|
||||
<artifactId>org.eclipse.elk.alg.layered</artifactId>
|
||||
<version>${elk-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.springframework.ide.vscode.commons.sprotty.autoconf;
|
||||
|
||||
import org.eclipse.sprotty.IPopupModelFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.commons.sprotty.scan.DiagramWebsocketServer;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses = DiagramWebsocketServer.class)
|
||||
public class SprottyAutoConf {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(IPopupModelFactory.class)
|
||||
public IPopupModelFactory popupModelFactory() {
|
||||
return new IPopupModelFactory.NullImpl();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.ide.vscode.commons.sprotty.elk;
|
||||
|
||||
import org.eclipse.elk.core.RecursiveGraphLayoutEngine;
|
||||
import org.eclipse.elk.core.util.BasicProgressMonitor;
|
||||
import org.eclipse.elk.graph.ElkNode;
|
||||
import org.eclipse.sprotty.ILayoutEngine;
|
||||
import org.eclipse.sprotty.SModelRoot;
|
||||
|
||||
public class ElkLayoutEngine implements ILayoutEngine {
|
||||
|
||||
@Override
|
||||
public void layout(SModelRoot root) {
|
||||
ElkUtils utils = new ElkUtils(root);
|
||||
ElkNode graph = utils.graph;
|
||||
new RecursiveGraphLayoutEngine().layout(graph, new BasicProgressMonitor());
|
||||
utils.applyLayout();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package org.springframework.ide.vscode.commons.sprotty.elk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.eclipse.elk.alg.layered.options.ContentAlignment;
|
||||
import org.eclipse.elk.alg.layered.options.FixedAlignment;
|
||||
import org.eclipse.elk.alg.layered.options.LayeredOptions;
|
||||
import org.eclipse.elk.alg.layered.options.NodePlacementStrategy;
|
||||
import org.eclipse.elk.core.options.Alignment;
|
||||
import org.eclipse.elk.core.options.Direction;
|
||||
import org.eclipse.elk.graph.ElkBendPoint;
|
||||
import org.eclipse.elk.graph.ElkEdge;
|
||||
import org.eclipse.elk.graph.ElkEdgeSection;
|
||||
import org.eclipse.elk.graph.ElkNode;
|
||||
import org.eclipse.elk.graph.properties.IProperty;
|
||||
import org.eclipse.elk.graph.properties.Property;
|
||||
import org.eclipse.elk.graph.util.ElkGraphUtil;
|
||||
import org.eclipse.sprotty.Point;
|
||||
import org.eclipse.sprotty.SEdge;
|
||||
import org.eclipse.sprotty.SModelElement;
|
||||
import org.eclipse.sprotty.SModelRoot;
|
||||
import org.eclipse.sprotty.SNode;
|
||||
import org.eclipse.sprotty.SShapeElement;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
public class ElkUtils {
|
||||
|
||||
private static final IProperty<SModelElement> SPROTTY_ELEMENT = new Property<>("sprotty-element");
|
||||
public final ElkNode graph;
|
||||
private Map<String, ElkNode> nodes = new HashMap<>();;
|
||||
|
||||
public ElkUtils(SModelRoot root) {
|
||||
graph = ElkGraphUtil.createGraph();
|
||||
|
||||
// graph.setProperty(LayeredOptions.DIRECTION, Direction.DOWN);
|
||||
// graph.setProperty(LayeredOptions.CONTENT_ALIGNMENT, EnumSet.of(ContentAlignment.H_CENTER));
|
||||
// graph.setProperty(LayeredOptions.ALIGNMENT, Alignment.RIGHT);
|
||||
|
||||
// graph.setProperty(LayeredOptions.NODE_PLACEMENT_STRATEGY, NodePlacementStrategy.SIMPLE);
|
||||
graph.setProperty(LayeredOptions.NODE_PLACEMENT_BK_FIXED_ALIGNMENT, FixedAlignment.BALANCED);
|
||||
|
||||
List<SEdge> edges = new ArrayList<>();
|
||||
for (SModelElement child : root.getChildren()) {
|
||||
System.out.println(child.getClass());
|
||||
if (child instanceof SNode) {
|
||||
nodes.put(child.getId(), toElk((SNode)child, graph));
|
||||
} else if (child instanceof SEdge) {
|
||||
edges.add((SEdge)child);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported graph layout element");
|
||||
}
|
||||
}
|
||||
|
||||
for (SEdge edge : edges) {
|
||||
toElk(edge);
|
||||
}
|
||||
}
|
||||
|
||||
private ElkEdge toElk(SEdge child) {
|
||||
ElkNode source = nodes.get(child.getSourceId());
|
||||
ElkNode target = nodes.get(child.getTargetId());
|
||||
Assert.isTrue(source != null);
|
||||
Assert.isTrue(target != null);
|
||||
ElkEdge edge = ElkGraphUtil.createSimpleEdge(source, target);
|
||||
edge.setProperty(SPROTTY_ELEMENT, child);
|
||||
return edge;
|
||||
}
|
||||
|
||||
private ElkNode toElk(SNode child, ElkNode parent) {
|
||||
ElkNode node = ElkGraphUtil.createNode(parent);
|
||||
node.setX(child.getPosition().getX());
|
||||
node.setY(child.getPosition().getY());
|
||||
node.setWidth(child.getSize().getWidth());
|
||||
node.setHeight(child.getSize().getHeight());
|
||||
node.setIdentifier(child.getId());
|
||||
node.setProperty(SPROTTY_ELEMENT, child);
|
||||
// node.setProperty(LayeredOptions.ALIGNMENT, Alignment.CENTER);
|
||||
return node;
|
||||
}
|
||||
|
||||
public void applyLayout() {
|
||||
for (Entry<String, ElkNode> entry : nodes.entrySet()) {
|
||||
ElkNode elkNode = entry.getValue();
|
||||
SModelElement element = elkNode.getProperty(SPROTTY_ELEMENT);
|
||||
if (element instanceof SShapeElement) {
|
||||
SShapeElement shape = (SShapeElement) element;
|
||||
shape.setPosition(new Point(elkNode.getX(), elkNode.getY()));
|
||||
}
|
||||
}
|
||||
|
||||
for (ElkEdge elkEdge : graph.getContainedEdges()) {
|
||||
SModelElement element = elkEdge.getProperty(SPROTTY_ELEMENT);
|
||||
if (element instanceof SEdge) {
|
||||
SEdge edge = (SEdge) element;
|
||||
List<Point> bendpoints = new ArrayList<>();
|
||||
for (ElkEdgeSection section : elkEdge.getSections()) {
|
||||
bendpoints.add(new Point(section.getStartX(), section.getStartY()));
|
||||
for (ElkBendPoint elkBend : section.getBendPoints()) {
|
||||
Point bendpoint = new Point(elkBend.getX(), elkBend.getY());
|
||||
bendpoints.add(bendpoint);
|
||||
}
|
||||
bendpoints.add(new Point(section.getEndX(), section.getEndY()));
|
||||
}
|
||||
edge.setRoutingPoints(bendpoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.springframework.ide.vscode.commons.sprotty.scan;
|
||||
|
||||
import org.eclipse.elk.alg.layered.options.LayeredMetaDataProvider;
|
||||
import org.eclipse.elk.alg.layered.options.LayeredOptions;
|
||||
import org.eclipse.elk.core.data.LayoutMetaDataService;
|
||||
import org.eclipse.sprotty.DefaultDiagramServer;
|
||||
import org.eclipse.sprotty.IDiagramExpansionListener;
|
||||
import org.eclipse.sprotty.IDiagramOpenListener;
|
||||
import org.eclipse.sprotty.IDiagramSelectionListener;
|
||||
import org.eclipse.sprotty.IDiagramServer;
|
||||
import org.eclipse.sprotty.ILayoutEngine;
|
||||
import org.eclipse.sprotty.IModelUpdateListener;
|
||||
import org.eclipse.sprotty.IPopupModelFactory;
|
||||
import org.eclipse.sprotty.SModelCloner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ide.vscode.commons.sprotty.elk.ElkLayoutEngine;
|
||||
|
||||
@Configuration
|
||||
public class DiagramServerConfiguration {
|
||||
|
||||
@Bean
|
||||
public IDiagramServer diagramServer() {
|
||||
DefaultDiagramServer diagramServer = new DefaultDiagramServer("spring-boot");
|
||||
return diagramServer;
|
||||
}
|
||||
|
||||
@Bean public IModelUpdateListener modelUpdateListener() {
|
||||
return new IModelUpdateListener.NullImpl();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ILayoutEngine layoutEngine() {
|
||||
LayoutMetaDataService.getInstance().registerLayoutMetaDataProviders(new LayeredMetaDataProvider());
|
||||
return new ElkLayoutEngine();
|
||||
}
|
||||
|
||||
@Bean public IDiagramSelectionListener diagramSelectionListener() {
|
||||
return new IDiagramSelectionListener.NullImpl();
|
||||
}
|
||||
|
||||
@Bean public IDiagramExpansionListener diagramExpansionListener() {
|
||||
return new IDiagramExpansionListener.NullImpl();
|
||||
}
|
||||
|
||||
@Bean public IDiagramOpenListener diagramOpenListener() {
|
||||
return new IDiagramOpenListener.NullImpl();
|
||||
}
|
||||
|
||||
@Bean public SModelCloner modelCloner() {
|
||||
return new SModelCloner();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.springframework.ide.vscode.commons.sprotty.scan;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
public class DiagramServerWebsocketConfiguration {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package org.springframework.ide.vscode.commons.sprotty.scan;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.sprotty.ActionMessage;
|
||||
import org.eclipse.sprotty.IDiagramServer;
|
||||
import org.eclipse.sprotty.server.json.ActionTypeAdapter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
@Controller
|
||||
public class DiagramWebsocketServer implements WebSocketConfigurer, InitializingBean {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DiagramWebsocketServer.class);
|
||||
|
||||
private Set<WebSocketSession> ws_sessions = new HashSet<>();
|
||||
|
||||
private Gson gson;
|
||||
|
||||
@Autowired
|
||||
private IDiagramServer diagramServer;
|
||||
|
||||
private void initializeGson() {
|
||||
if (gson == null) {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
ActionTypeAdapter.configureGson(builder);
|
||||
gson = builder.create();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
initializeGson();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
registry.addHandler(WsMessageHandler(), "/websocket")
|
||||
.setAllowedOrigins("*")
|
||||
.withSockJS();
|
||||
}
|
||||
|
||||
private final String END_MESSAGE = "@end";
|
||||
/**
|
||||
* WebSocketHandler which receives messages from a websocket and forwards them to a
|
||||
* spring-cloud-stream.
|
||||
*/
|
||||
@Bean
|
||||
public WebSocketHandler WsMessageHandler() {
|
||||
return new TextWebSocketHandler() {
|
||||
|
||||
private StringBuilder buff = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
synchronized (ws_sessions) {
|
||||
ws_sessions.add(session);
|
||||
}
|
||||
log.info("Websocket connection OPENED in: "+this);
|
||||
log.info("Number of active sessions = {}", ws_sessions.size());
|
||||
diagramServer.setRemoteEndpoint(message -> {
|
||||
sendMessage(gson.toJson(message, ActionMessage.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
String payload = message.getPayload();
|
||||
log.info(payload);
|
||||
try {
|
||||
if (END_MESSAGE.equals(payload)) {
|
||||
ActionMessage actionMessage = gson.fromJson(buff.toString(), ActionMessage.class);
|
||||
buff = new StringBuilder();
|
||||
diagramServer.accept(actionMessage);
|
||||
} else {
|
||||
buff.append(payload);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||
log.info("Websocket connection CLOSED in: "+this);
|
||||
synchronized (ws_sessions) {
|
||||
ws_sessions.remove(session);
|
||||
}
|
||||
log.info("Number of active sessions = {}", ws_sessions.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
|
||||
log.error("Websocket trasnport error: ", exception);
|
||||
synchronized (ws_sessions) {
|
||||
ws_sessions.remove(session);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private void sendMessage(String msg) {
|
||||
synchronized (ws_sessions) {
|
||||
for (WebSocketSession ws : ws_sessions) {
|
||||
try {
|
||||
if (ws.isOpen()) {
|
||||
log.info("Sent: {}", msg);
|
||||
ws.sendMessage(new TextMessage(msg));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error forwarding message to ws session", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.ide.vscode.commons.sprotty.autoconf.SprottyAutoConf
|
||||
@@ -13,8 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.0.M2</version>
|
||||
<relativePath></relativePath>
|
||||
<version>2.2.0.M5</version>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -119,6 +118,8 @@
|
||||
<reactor-netty>0.7.5.RELEASE</reactor-netty>
|
||||
<commons-io-version>2.4</commons-io-version>
|
||||
<commons-codec-version>1.11</commons-codec-version>
|
||||
<sprotty-version>0.7.0-SNAPSHOT</sprotty-version>
|
||||
<elk-version>0.6.0-SNAPSHOT</elk-version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -106,6 +106,19 @@
|
||||
<artifactId>org.eclipse.lsp4j.jsonrpc</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/io.typefox.sprotty/diagram-api -->
|
||||
<dependency>
|
||||
<groupId>io.typefox.sprotty</groupId>
|
||||
<artifactId>diagram-api</artifactId>
|
||||
<version>0.4.0</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/io.typefox.sprotty/diagram-server -->
|
||||
<dependency>
|
||||
<groupId>io.typefox.sprotty</groupId>
|
||||
<artifactId>diagram-server</artifactId>
|
||||
<version>0.4.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test harness -->
|
||||
@@ -133,6 +146,11 @@
|
||||
<version>${mockito-version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ide.vscode</groupId>
|
||||
<artifactId>commons-sprotty</artifactId>
|
||||
<version>${dependencies.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@@ -14,10 +14,8 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
@@ -58,19 +56,22 @@ import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContext;
|
||||
import org.springframework.ide.vscode.commons.yaml.completion.YamlAssistContextProvider;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlDocument;
|
||||
import org.springframework.ide.vscode.commons.yaml.structure.YamlStructureProvider;
|
||||
import org.springframework.ide.vscode.languageserver.starter.LanguageServerAutoConf;
|
||||
import org.springframework.ide.vscode.languageserver.starter.LanguageServerRunnerAutoConf;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
@SpringBootConfiguration(proxyBeanMethods = false)
|
||||
@ImportAutoConfiguration({
|
||||
// During development you can uncomment the below so that boot dash can detect started state properly:
|
||||
// SpringApplicationAdminJmxAutoConfiguration.class,
|
||||
LanguageServerAutoConf.class,
|
||||
LanguageServerRunnerAutoConf.class,
|
||||
ConfigurationPropertiesAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class
|
||||
})
|
||||
//@ImportAutoConfiguration({
|
||||
// // During development you can uncomment the below so that boot dash can detect started state properly:
|
||||
// // SpringApplicationAdminJmxAutoConfiguration.class,
|
||||
// LanguageServerAutoConf.class,
|
||||
// LanguageServerRunnerAutoConf.class,
|
||||
// ConfigurationPropertiesAutoConfiguration.class,
|
||||
// PropertyPlaceholderAutoConfiguration.class,
|
||||
// SprottyAutoConf.class,
|
||||
// WebSocketServletAutoConfiguration.class,
|
||||
// WebMvcAutoConfiguration.class
|
||||
//})
|
||||
@EnableAutoConfiguration
|
||||
@EnableConfigurationProperties(BootLsConfigProperties.class)
|
||||
@ComponentScan
|
||||
public class BootLanguagServerBootApp {
|
||||
@@ -112,6 +113,12 @@ public class BootLanguagServerBootApp {
|
||||
@Bean ValueProviderRegistry valueProviders() {
|
||||
return new ValueProviderRegistry();
|
||||
}
|
||||
|
||||
@Bean ThreadPoolTaskScheduler taskScheduler() {
|
||||
ThreadPoolTaskScheduler t = new ThreadPoolTaskScheduler();
|
||||
t.initialize();
|
||||
return t;
|
||||
}
|
||||
|
||||
@Bean InitializingBean initializeValueProviders(ValueProviderRegistry r, @Qualifier("adHocProperties") ProjectBasedPropertyIndexProvider adHocProperties, SourceLinks sourceLinks) {
|
||||
return () -> {
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package org.springframework.ide.vscode.boot.app.diagram;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.sprotty.Dimension;
|
||||
import org.eclipse.sprotty.IDiagramServer;
|
||||
import org.eclipse.sprotty.Point;
|
||||
import org.eclipse.sprotty.SCompartment;
|
||||
import org.eclipse.sprotty.SEdge;
|
||||
import org.eclipse.sprotty.SGraph;
|
||||
import org.eclipse.sprotty.SLabel;
|
||||
import org.eclipse.sprotty.SModelElement;
|
||||
import org.eclipse.sprotty.SModelRoot;
|
||||
import org.eclipse.sprotty.SNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class LiveBeanDiagramModel implements InitializingBean {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LiveBeanDiagramModel.class);
|
||||
|
||||
@Autowired
|
||||
private IDiagramServer diagramServer;
|
||||
|
||||
@Autowired
|
||||
private RunningAppProvider runningAppProvider;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("taskScheduler")
|
||||
private TaskScheduler taskScheduler;
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
taskScheduler.scheduleAtFixedRate(() -> diagramServer.setModel(generateModel()), Duration.ofSeconds(15));
|
||||
}
|
||||
|
||||
private SModelRoot generateModel() {
|
||||
try {
|
||||
Collection<SpringBootApp> apps = runningAppProvider.getAllRunningSpringApps();
|
||||
if (!apps.isEmpty()) {
|
||||
return toSprottyGraph(apps.iterator().next());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return SGraph.EMPTY_ROOT;
|
||||
}
|
||||
|
||||
private SModelRoot toSprottyGraph(SpringBootApp app) throws Exception {
|
||||
SModelRoot graph = new SModelRoot();
|
||||
graph.setId(app.getProcessName());
|
||||
graph.setType("graph");
|
||||
|
||||
graph.setChildren(new ArrayList<>());
|
||||
List<SModelElement> graphChildren = graph.getChildren();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static SNode createBean(String id, String labelText, Point location, Dimension size) {
|
||||
SNode node = new SNode();
|
||||
node.setId(id);
|
||||
node.setType("node:bean");
|
||||
node.setLayout("vbox");
|
||||
node.setPosition(new Point(Math.random() * 1024, Math.random() * 768));
|
||||
node.setSize(new Dimension(80, 80));
|
||||
node.setChildren(new ArrayList<>());
|
||||
|
||||
SCompartment compartment = new SCompartment();
|
||||
compartment.setId(id + "-comp");
|
||||
compartment.setType("compartment");
|
||||
compartment.setLayout("hbox");
|
||||
compartment.setChildren(new ArrayList<>());
|
||||
|
||||
SLabel label = new SLabel();
|
||||
label.setId(id + "-lanbel");
|
||||
label.setType("node:label");
|
||||
label.setText(labelText);
|
||||
|
||||
compartment.getChildren().add(label);
|
||||
node.getChildren().add(compartment);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static SEdge createEdge(String id, String sourceId, String targetId) {
|
||||
SEdge edge = new SEdge();
|
||||
edge.setId(id);
|
||||
edge.setType("edge:straight");
|
||||
edge.setSourceId(sourceId);
|
||||
edge.setTargetId(targetId);
|
||||
return edge;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.springframework.ide.vscode.boot.app.diagram;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.eclipse.sprotty.Dimension;
|
||||
import org.eclipse.sprotty.IDiagramServer;
|
||||
import org.eclipse.sprotty.Point;
|
||||
import org.eclipse.sprotty.SCompartment;
|
||||
import org.eclipse.sprotty.SEdge;
|
||||
import org.eclipse.sprotty.SLabel;
|
||||
import org.eclipse.sprotty.SModelRoot;
|
||||
import org.eclipse.sprotty.SNode;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import net.bytebuddy.utility.RandomString;
|
||||
|
||||
|
||||
@Component
|
||||
public class MockDiagramServerModel implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
IDiagramServer diagramServer;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("taskScheduler")
|
||||
private TaskScheduler taskScheduler;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// taskScheduler.scheduleAtFixedRate(() -> diagramServer.setModel(generateModel()), Duration.ofSeconds(5));
|
||||
diagramServer.setModel(generateModel(10));
|
||||
}
|
||||
|
||||
public static SModelRoot generateModel(int nodesNum) {
|
||||
SModelRoot graph = new SModelRoot();
|
||||
graph.setId("graph");
|
||||
graph.setType("graph");
|
||||
|
||||
SNode node0 = createBean("node0", "main", new Point(100, 100), new Dimension(120, 40));
|
||||
|
||||
graph.setChildren(new ArrayList<>());
|
||||
graph.getChildren().add(node0);
|
||||
|
||||
for (int i = 1; i < nodesNum; i++) {
|
||||
SNode node = createBean("node" + i, RandomString.make(((int) Math.round(Math.random()* 10 + 1))), new Point(Math.random() * 1024, Math.random() * 768), new Dimension(120, 40));
|
||||
SEdge edge = createEdge("edge-" + i, node0.getId(), node.getId());
|
||||
graph.getChildren().add(edge);
|
||||
graph.getChildren().add(node);
|
||||
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
private static SNode createBean(String id, String labelText, Point location, Dimension size) {
|
||||
SNode node = new SNode();
|
||||
node.setId(id);
|
||||
node.setType("node:bean");
|
||||
node.setLayout("vbox");
|
||||
node.setPosition(new Point(Math.random() * 1024, Math.random() * 768));
|
||||
node.setSize(new Dimension(80, 80));
|
||||
node.setChildren(new ArrayList<>());
|
||||
|
||||
SCompartment compartment = new SCompartment();
|
||||
compartment.setId(id + "-comp");
|
||||
compartment.setType("compartment");
|
||||
compartment.setLayout("hbox");
|
||||
compartment.setChildren(new ArrayList<>());
|
||||
|
||||
SLabel label = new SLabel();
|
||||
label.setId(id + "-lanbel");
|
||||
label.setType("node:label");
|
||||
label.setText(labelText);
|
||||
|
||||
compartment.getChildren().add(label);
|
||||
node.getChildren().add(compartment);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static SEdge createEdge(String id, String sourceId, String targetId) {
|
||||
SEdge edge = new SEdge();
|
||||
edge.setId(id);
|
||||
edge.setType("edge:straight");
|
||||
edge.setSourceId(sourceId);
|
||||
edge.setTargetId(targetId);
|
||||
return edge;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.springframework.ide.vscode.boot.app.diagram;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.sprotty.IDiagramServer;
|
||||
import org.eclipse.sprotty.IPopupModelFactory;
|
||||
import org.eclipse.sprotty.RequestPopupModelAction;
|
||||
import org.eclipse.sprotty.SGraph;
|
||||
import org.eclipse.sprotty.SLabel;
|
||||
import org.eclipse.sprotty.SModelElement;
|
||||
import org.eclipse.sprotty.SModelRoot;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class PopupModelFactory implements IPopupModelFactory {
|
||||
|
||||
@Override
|
||||
public SModelRoot createPopupModel(SModelElement element, RequestPopupModelAction request, IDiagramServer server) {
|
||||
|
||||
SGraph graph = new SGraph();
|
||||
graph.setId("popup");
|
||||
List<SModelElement> children = new ArrayList<>();
|
||||
|
||||
SLabel label = new SLabel();
|
||||
label.setType("node:label");
|
||||
label.setText("I'm a tooltip!");
|
||||
children.add(label);
|
||||
|
||||
graph.setChildren(children);
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,4 +8,4 @@ spring.main.banner-mode: off
|
||||
#logging.level.org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer=debug
|
||||
#logging.level.org.springframework.ide.vscode.boot.java.utils.SpringIndexerJava=debug
|
||||
#logging.level.org.springframework.ide.vscode.boot.app.SpringSymbolIndex=debug
|
||||
#logging.level.org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp=off
|
||||
logging.level.org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp=off
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,46 @@
|
||||
/********************************************************************************
|
||||
* 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
|
||||
********************************************************************************/
|
||||
|
||||
.sprotty-node {
|
||||
fill: #aae;
|
||||
stroke: #66b;
|
||||
stroke-width: 3;
|
||||
}
|
||||
|
||||
.sprotty-text {
|
||||
font-size: 16pt;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.sprotty-edge {
|
||||
fill: none;
|
||||
stroke: #488;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.sprotty-node.selected {
|
||||
stroke: #dd8;
|
||||
stroke-width: 6;
|
||||
}
|
||||
|
||||
.sprotty-missing {
|
||||
stroke-width: 1;
|
||||
stroke: #f00;
|
||||
fill: #f00;
|
||||
font-family: SansSerif;
|
||||
font-size: 14pt;
|
||||
text-anchor: middle;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/********************************************************************************
|
||||
* 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
|
||||
********************************************************************************/
|
||||
|
||||
.copyright {
|
||||
margin-top: 10px;
|
||||
text-align: right;
|
||||
font-size: 10px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.help {
|
||||
margin-top: 24px;
|
||||
text-align: right;
|
||||
font-size: 16px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-top: 15px;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #bbb;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>sprotty Circles Example</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/page.css">
|
||||
<!-- support Microsoft browsers -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dom4/3.0.0/dom4.js">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="row" id="sprotty-app" data-app="circlegraph">
|
||||
<div class="col-md-10">
|
||||
<h1>sprotty Circles Example</h1>
|
||||
<p>
|
||||
<button id="refresh">Refresh</button>
|
||||
<button id="scrambleNodes">Scramble nodes</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="help col-md-2">
|
||||
<a href='https://github.com/theia-ide/sprotty/wiki/Using-sprotty'>Help</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="spring-boot" class="sprotty"/>
|
||||
</div>
|
||||
<div class="copyright">
|
||||
© 2017 <a href="http://typefox.io">TypeFox GmbH</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="bundle.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.springframework.ide.vscode.boot.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.elk.alg.layered.options.LayeredMetaDataProvider;
|
||||
import org.eclipse.elk.core.RecursiveGraphLayoutEngine;
|
||||
import org.eclipse.elk.core.data.LayoutMetaDataService;
|
||||
import org.eclipse.elk.core.util.BasicProgressMonitor;
|
||||
import org.eclipse.elk.graph.ElkNode;
|
||||
import org.eclipse.sprotty.Point;
|
||||
import org.eclipse.sprotty.SModelRoot;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.app.diagram.MockDiagramServerModel;
|
||||
import org.springframework.ide.vscode.commons.sprotty.elk.ElkUtils;
|
||||
|
||||
|
||||
public class LayoutTest {
|
||||
|
||||
@Test
|
||||
public void testCreateGraph() throws Exception {
|
||||
SModelRoot modelRoot = MockDiagramServerModel.generateModel(10);
|
||||
ElkNode graph = new ElkUtils(modelRoot).graph;
|
||||
assertNotNull(graph);
|
||||
assertEquals(10, graph.getChildren().size());
|
||||
assertEquals(9, graph.getContainedEdges().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLayout() throws Exception {
|
||||
LayoutMetaDataService.getInstance().registerLayoutMetaDataProviders(new LayeredMetaDataProvider());
|
||||
|
||||
SModelRoot modelRoot = MockDiagramServerModel.generateModel(10);
|
||||
ElkNode graph = new ElkUtils(modelRoot).graph;
|
||||
|
||||
Map<String, Point> locations = new HashMap<>();
|
||||
|
||||
for (ElkNode child : graph.getChildren()) {
|
||||
locations.put(child.getIdentifier(), new Point(child.getX(), child.getY()));
|
||||
}
|
||||
|
||||
new RecursiveGraphLayoutEngine().layout(graph, new BasicProgressMonitor());
|
||||
|
||||
for (ElkNode child : graph.getChildren()) {
|
||||
assertNotEquals(locations.get(child.getIdentifier()), new Point(child.getX(), child.getY()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user