initial commit supporting converting corefx to using grpc from previous rest client
This commit is contained in:
		
							parent
							
								
									f283c747cc
								
							
						
					
					
						commit
						a593289f1b
					
				
					 147 changed files with 10372 additions and 0 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -55,3 +55,6 @@ coverage.xml | ||||||
| netns/setup.py | netns/setup.py | ||||||
| daemon/setup.py | daemon/setup.py | ||||||
| ns3/setup.py | ns3/setup.py | ||||||
|  | 
 | ||||||
|  | # ignore corefx build | ||||||
|  | corefx/target | ||||||
|  |  | ||||||
							
								
								
									
										156
									
								
								corefx/pom.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								corefx/pom.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,156 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <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> | ||||||
|  | 
 | ||||||
|  |     <groupId>com.core</groupId> | ||||||
|  |     <artifactId>corefx</artifactId> | ||||||
|  |     <version>1.0-SNAPSHOT</version> | ||||||
|  | 
 | ||||||
|  |     <properties> | ||||||
|  |         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||||
|  |         <maven.compiler.source>1.8</maven.compiler.source> | ||||||
|  |         <maven.compiler.target>1.8</maven.compiler.target> | ||||||
|  |         <jung.version>2.1.1</jung.version> | ||||||
|  |         <jackson.version>2.9.6</jackson.version> | ||||||
|  |         <grpc.version>1.20.0</grpc.version> | ||||||
|  |     </properties> | ||||||
|  | 
 | ||||||
|  |     <dependencies> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.sf.jung</groupId> | ||||||
|  |             <artifactId>jung-api</artifactId> | ||||||
|  |             <version>${jung.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.sf.jung</groupId> | ||||||
|  |             <artifactId>jung-graph-impl</artifactId> | ||||||
|  |             <version>${jung.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.sf.jung</groupId> | ||||||
|  |             <artifactId>jung-algorithms</artifactId> | ||||||
|  |             <version>${jung.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.sf.jung</groupId> | ||||||
|  |             <artifactId>jung-io</artifactId> | ||||||
|  |             <version>${jung.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>net.sf.jung</groupId> | ||||||
|  |             <artifactId>jung-visualization</artifactId> | ||||||
|  |             <version>${jung.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.fasterxml.jackson.core</groupId> | ||||||
|  |             <artifactId>jackson-core</artifactId> | ||||||
|  |             <version>${jackson.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.fasterxml.jackson.core</groupId> | ||||||
|  |             <artifactId>jackson-databind</artifactId> | ||||||
|  |             <version>${jackson.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.fasterxml.jackson.core</groupId> | ||||||
|  |             <artifactId>jackson-annotations</artifactId> | ||||||
|  |             <version>${jackson.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.squareup.okhttp3</groupId> | ||||||
|  |             <artifactId>okhttp</artifactId> | ||||||
|  |             <version>3.11.0</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.apache.logging.log4j</groupId> | ||||||
|  |             <artifactId>log4j-api</artifactId> | ||||||
|  |             <version>2.9.0</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.apache.logging.log4j</groupId> | ||||||
|  |             <artifactId>log4j-core</artifactId> | ||||||
|  |             <version>2.9.0</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>io.socket</groupId> | ||||||
|  |             <artifactId>socket.io-client</artifactId> | ||||||
|  |             <version>0.8.3</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.projectlombok</groupId> | ||||||
|  |             <artifactId>lombok</artifactId> | ||||||
|  |             <version>1.18.0</version> | ||||||
|  |             <scope>provided</scope> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>commons-net</groupId> | ||||||
|  |             <artifactId>commons-net</artifactId> | ||||||
|  |             <version>3.6</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.jfoenix</groupId> | ||||||
|  |             <artifactId>jfoenix</artifactId> | ||||||
|  |             <version>8.0.7</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>io.grpc</groupId> | ||||||
|  |             <artifactId>grpc-netty-shaded</artifactId> | ||||||
|  |             <version>${grpc.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>io.grpc</groupId> | ||||||
|  |             <artifactId>grpc-protobuf</artifactId> | ||||||
|  |             <version>${grpc.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>io.grpc</groupId> | ||||||
|  |             <artifactId>grpc-stub</artifactId> | ||||||
|  |             <version>${grpc.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.google.guava</groupId> | ||||||
|  |             <artifactId>guava</artifactId> | ||||||
|  |             <version>20.0</version> | ||||||
|  |         </dependency> | ||||||
|  |     </dependencies> | ||||||
|  | 
 | ||||||
|  |     <build> | ||||||
|  |         <extensions> | ||||||
|  |             <extension> | ||||||
|  |                 <groupId>kr.motd.maven</groupId> | ||||||
|  |                 <artifactId>os-maven-plugin</artifactId> | ||||||
|  |                 <version>1.5.0.Final</version> | ||||||
|  |             </extension> | ||||||
|  |         </extensions> | ||||||
|  |         <plugins> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>com.zenjava</groupId> | ||||||
|  |                 <artifactId>javafx-maven-plugin</artifactId> | ||||||
|  |                 <version>8.8.3</version> | ||||||
|  |                 <configuration> | ||||||
|  |                     <mainClass>com.core.Main</mainClass> | ||||||
|  |                 </configuration> | ||||||
|  |             </plugin> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.xolstice.maven.plugins</groupId> | ||||||
|  |                 <artifactId>protobuf-maven-plugin</artifactId> | ||||||
|  |                 <version>0.5.1</version> | ||||||
|  |                 <configuration> | ||||||
|  |                     <protocArtifact>com.google.protobuf:protoc:3.7.1:exe:${os.detected.classifier}</protocArtifact> | ||||||
|  |                     <pluginId>grpc-java</pluginId> | ||||||
|  |                     <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> | ||||||
|  |                 </configuration> | ||||||
|  |                 <executions> | ||||||
|  |                     <execution> | ||||||
|  |                         <goals> | ||||||
|  |                             <goal>compile</goal> | ||||||
|  |                             <goal>compile-custom</goal> | ||||||
|  |                         </goals> | ||||||
|  |                     </execution> | ||||||
|  |                 </executions> | ||||||
|  |             </plugin> | ||||||
|  |         </plugins> | ||||||
|  |     </build> | ||||||
|  | </project> | ||||||
							
								
								
									
										543
									
								
								corefx/src/main/java/com/core/Controller.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										543
									
								
								corefx/src/main/java/com/core/Controller.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,543 @@ | ||||||
|  | package com.core; | ||||||
|  | 
 | ||||||
|  | import com.core.client.ICoreClient; | ||||||
|  | import com.core.client.grpc.CoreGrpcClient; | ||||||
|  | import com.core.data.*; | ||||||
|  | import com.core.graph.NetworkGraph; | ||||||
|  | import com.core.ui.*; | ||||||
|  | import com.core.ui.dialogs.*; | ||||||
|  | import com.core.utils.ConfigUtils; | ||||||
|  | import com.core.utils.Configuration; | ||||||
|  | import com.core.utils.NodeTypeConfig; | ||||||
|  | import com.core.websocket.CoreWebSocket; | ||||||
|  | import com.jfoenix.controls.JFXDecorator; | ||||||
|  | import com.jfoenix.controls.JFXProgressBar; | ||||||
|  | import javafx.application.Application; | ||||||
|  | import javafx.application.Platform; | ||||||
|  | import javafx.concurrent.Task; | ||||||
|  | import javafx.embed.swing.SwingNode; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.fxml.Initializable; | ||||||
|  | import javafx.scene.control.CheckMenuItem; | ||||||
|  | import javafx.scene.control.MenuItem; | ||||||
|  | import javafx.scene.layout.BorderPane; | ||||||
|  | import javafx.scene.layout.StackPane; | ||||||
|  | import javafx.scene.layout.VBox; | ||||||
|  | import javafx.stage.FileChooser; | ||||||
|  | import javafx.stage.Stage; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.awt.event.ItemEvent; | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.net.URISyntaxException; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.util.*; | ||||||
|  | import java.util.concurrent.ExecutorService; | ||||||
|  | import java.util.concurrent.Executors; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class Controller implements Initializable { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private StackPane stackPane; | ||||||
|  |     @FXML private BorderPane borderPane; | ||||||
|  |     @FXML private VBox top; | ||||||
|  |     @FXML private VBox bottom; | ||||||
|  |     @FXML private SwingNode swingNode; | ||||||
|  |     @FXML private MenuItem saveXmlMenuItem; | ||||||
|  |     @FXML private JFXProgressBar progressBar; | ||||||
|  |     @FXML private CheckMenuItem throughputMenuItem; | ||||||
|  | 
 | ||||||
|  |     private final ExecutorService executorService = Executors.newSingleThreadExecutor(); | ||||||
|  |     private final Map<Integer, MobilityConfig> mobilityScripts = new HashMap<>(); | ||||||
|  |     private final Map<Integer, MobilityPlayerDialog> mobilityPlayerDialogs = new HashMap<>(); | ||||||
|  |     private Application application; | ||||||
|  |     private JFXDecorator decorator; | ||||||
|  |     private Stage window; | ||||||
|  |     private Configuration configuration; | ||||||
|  |     private Map<String, Set<String>> defaultServices = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     // core client utilities | ||||||
|  |     private ICoreClient coreClient = new CoreGrpcClient(); | ||||||
|  |     private CoreWebSocket coreWebSocket; | ||||||
|  | 
 | ||||||
|  |     // ui elements | ||||||
|  |     private NetworkGraph networkGraph = new NetworkGraph(this); | ||||||
|  |     private AnnotationToolbar annotationToolbar = new AnnotationToolbar(networkGraph); | ||||||
|  |     private NodeDetails nodeDetails = new NodeDetails(this); | ||||||
|  |     private LinkDetails linkDetails = new LinkDetails(this); | ||||||
|  |     private GraphToolbar graphToolbar = new GraphToolbar(this); | ||||||
|  | 
 | ||||||
|  |     // dialogs | ||||||
|  |     private SessionsDialog sessionsDialog = new SessionsDialog(this); | ||||||
|  |     private ServiceDialog serviceDialog = new ServiceDialog(this); | ||||||
|  |     private NodeServicesDialog nodeServicesDialog = new NodeServicesDialog(this); | ||||||
|  |     private NodeEmaneDialog nodeEmaneDialog = new NodeEmaneDialog(this); | ||||||
|  |     private NodeWlanDialog nodeWlanDialog = new NodeWlanDialog(this); | ||||||
|  |     private ConfigDialog configDialog = new ConfigDialog(this); | ||||||
|  |     private HooksDialog hooksDialog = new HooksDialog(this); | ||||||
|  |     private MobilityDialog mobilityDialog = new MobilityDialog(this); | ||||||
|  |     private ChartDialog chartDialog = new ChartDialog(this); | ||||||
|  |     private NodeTypesDialog nodeTypesDialog = new NodeTypesDialog(this); | ||||||
|  |     private BackgroundDialog backgroundDialog = new BackgroundDialog(this); | ||||||
|  |     private LocationDialog locationDialog = new LocationDialog(this); | ||||||
|  |     private GeoDialog geoDialog = new GeoDialog(this); | ||||||
|  |     private ConnectDialog connectDialog = new ConnectDialog(this); | ||||||
|  |     private GuiPreferencesDialog guiPreferencesDialog = new GuiPreferencesDialog(this); | ||||||
|  |     private NodeTypeCreateDialog nodeTypeCreateDialog = new NodeTypeCreateDialog(this); | ||||||
|  | 
 | ||||||
|  |     public void connectToCore(String address, int port) { | ||||||
|  |         coreWebSocket.stop(); | ||||||
|  | 
 | ||||||
|  |         ExecutorService executorService = Executors.newSingleThreadExecutor(); | ||||||
|  |         executorService.submit(() -> { | ||||||
|  |             try { | ||||||
|  |                 coreWebSocket.start(address, port); | ||||||
|  |                 coreClient.setConnection(address, port); | ||||||
|  |                 initialJoin(); | ||||||
|  |             } catch (IOException | URISyntaxException ex) { | ||||||
|  |                 Toast.error(String.format("Connection failure: %s", ex.getMessage()), ex); | ||||||
|  |                 Platform.runLater(() -> connectDialog.showDialog()); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void initialJoin() throws IOException { | ||||||
|  |         Map<String, List<String>> serviceGroups = coreClient.getServices(); | ||||||
|  |         logger.info("core services: {}", serviceGroups); | ||||||
|  |         nodeServicesDialog.setServices(serviceGroups); | ||||||
|  |         nodeTypeCreateDialog.setServices(serviceGroups); | ||||||
|  | 
 | ||||||
|  |         logger.info("initial core session join"); | ||||||
|  |         List<SessionOverview> sessions = coreClient.getSessions(); | ||||||
|  | 
 | ||||||
|  |         logger.info("existing sessions: {}", sessions); | ||||||
|  |         Integer sessionId; | ||||||
|  |         if (sessions.isEmpty()) { | ||||||
|  |             logger.info("creating initial session"); | ||||||
|  |             SessionOverview sessionOverview = coreClient.createSession(); | ||||||
|  |             sessionId = sessionOverview.getId(); | ||||||
|  |             Toast.info(String.format("Created Session %s", sessionId)); | ||||||
|  |         } else { | ||||||
|  |             SessionOverview sessionOverview = sessions.get(0); | ||||||
|  |             sessionId = sessionOverview.getId(); | ||||||
|  |             Toast.info(String.format("Joined Session %s", sessionId)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         joinSession(sessionId); | ||||||
|  | 
 | ||||||
|  |         // set emane models | ||||||
|  |         List<String> emaneModels = coreClient.getEmaneModels(); | ||||||
|  |         nodeEmaneDialog.setModels(emaneModels); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void joinSession(Integer sessionId) throws IOException { | ||||||
|  |         // clear graph | ||||||
|  |         networkGraph.reset(); | ||||||
|  | 
 | ||||||
|  |         // clear out any previously set information | ||||||
|  |         mobilityPlayerDialogs.clear(); | ||||||
|  |         mobilityScripts.clear(); | ||||||
|  |         mobilityDialog.setNode(null); | ||||||
|  |         Platform.runLater(() -> borderPane.setRight(null)); | ||||||
|  | 
 | ||||||
|  |         // get session to join | ||||||
|  |         Session session = coreClient.getSession(sessionId); | ||||||
|  |         SessionState sessionState = SessionState.get(session.getState()); | ||||||
|  | 
 | ||||||
|  |         // update client to use this session | ||||||
|  |         coreClient.updateSession(sessionId); | ||||||
|  |         coreClient.updateState(sessionState); | ||||||
|  | 
 | ||||||
|  |         // display all nodes | ||||||
|  |         logger.info("joining core session({}) state({}): {}", sessionId, sessionState, session); | ||||||
|  |         for (CoreNode node : session.getNodes()) { | ||||||
|  |             NodeType nodeType = NodeType.find(node.getType(), node.getModel()); | ||||||
|  |             if (nodeType == null) { | ||||||
|  |                 logger.info(String.format("failed to find node type(%s) model(%s): %s", | ||||||
|  |                         node.getType(), node.getModel(), node.getName())); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             node.setNodeType(nodeType); | ||||||
|  |             networkGraph.addNode(node); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // display all links | ||||||
|  |         for (CoreLink link : session.getLinks()) { | ||||||
|  |             if (link.getInterfaceOne() != null || link.getInterfaceTwo() != null) { | ||||||
|  |                 link.setType(LinkTypes.WIRED.getValue()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             networkGraph.addLink(link); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // refresh graph | ||||||
|  |         networkGraph.getGraphViewer().repaint(); | ||||||
|  | 
 | ||||||
|  |         // update other components for new session | ||||||
|  |         graphToolbar.setRunButton(coreClient.isRunning()); | ||||||
|  |         hooksDialog.updateHooks(); | ||||||
|  | 
 | ||||||
|  |         // update session default services | ||||||
|  |         setCoreDefaultServices(); | ||||||
|  | 
 | ||||||
|  |         // retrieve current mobility script configurations and show dialogs | ||||||
|  |         Map<Integer, MobilityConfig> mobilityConfigMap = coreClient.getMobilityConfigs(); | ||||||
|  |         mobilityScripts.putAll(mobilityConfigMap); | ||||||
|  |         showMobilityScriptDialogs(); | ||||||
|  | 
 | ||||||
|  |         Platform.runLater(() -> decorator.setTitle(String.format("CORE (Session %s)", sessionId))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean startSession() throws IOException { | ||||||
|  |         // force nodes to get latest positions | ||||||
|  |         networkGraph.updatePositions(); | ||||||
|  | 
 | ||||||
|  |         // retrieve items for creation/start | ||||||
|  |         Collection<CoreNode> nodes = networkGraph.getGraph().getVertices(); | ||||||
|  |         Collection<CoreLink> links = networkGraph.getGraph().getEdges(); | ||||||
|  |         List<Hook> hooks = hooksDialog.getHooks(); | ||||||
|  | 
 | ||||||
|  |         // start/create session | ||||||
|  |         progressBar.setVisible(true); | ||||||
|  |         boolean result = coreClient.start(nodes, links, hooks); | ||||||
|  |         progressBar.setVisible(false); | ||||||
|  |         if (result) { | ||||||
|  |             showMobilityScriptDialogs(); | ||||||
|  |             saveXmlMenuItem.setDisable(false); | ||||||
|  |         } | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean stopSession() throws IOException { | ||||||
|  |         // clear out any drawn wireless links | ||||||
|  |         List<CoreLink> wirelessLinks = networkGraph.getGraph().getEdges().stream() | ||||||
|  |                 .filter(CoreLink::isWireless) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |         wirelessLinks.forEach(networkGraph::removeWirelessLink); | ||||||
|  |         networkGraph.getGraphViewer().repaint(); | ||||||
|  | 
 | ||||||
|  |         // stop session | ||||||
|  |         progressBar.setVisible(true); | ||||||
|  |         boolean result = coreClient.stop(); | ||||||
|  |         progressBar.setVisible(false); | ||||||
|  |         if (result) { | ||||||
|  |             saveXmlMenuItem.setDisable(true); | ||||||
|  |         } | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void handleThroughputs(Throughputs throughputs) { | ||||||
|  |         for (InterfaceThroughput interfaceThroughput : throughputs.getInterfaces()) { | ||||||
|  |             int nodeId = interfaceThroughput.getNode(); | ||||||
|  |             CoreNode node = networkGraph.getVertex(nodeId); | ||||||
|  |             Collection<CoreLink> links = networkGraph.getGraph().getIncidentEdges(node); | ||||||
|  |             int interfaceId = interfaceThroughput.getNodeInterface(); | ||||||
|  |             for (CoreLink link : links) { | ||||||
|  |                 if (nodeId == link.getNodeOne()) { | ||||||
|  |                     if (interfaceId == link.getInterfaceOne().getId()) { | ||||||
|  |                         link.setThroughput(interfaceThroughput.getThroughput()); | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     if (interfaceId == link.getInterfaceTwo().getId()) { | ||||||
|  |                         link.setThroughput(interfaceThroughput.getThroughput()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         networkGraph.getGraphViewer().repaint(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setCoreDefaultServices() { | ||||||
|  |         try { | ||||||
|  |             coreClient.setDefaultServices(defaultServices); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("Error updating core default services", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void updateNodeTypes() { | ||||||
|  |         graphToolbar.setupNodeTypes(); | ||||||
|  |         setCoreDefaultServices(); | ||||||
|  |         try { | ||||||
|  |             ConfigUtils.save(configuration); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("Error saving configuration", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void deleteNode(CoreNode node) { | ||||||
|  |         networkGraph.removeNode(node); | ||||||
|  |         CoreNode mobilityNode = mobilityDialog.getNode(); | ||||||
|  |         if (mobilityNode != null && mobilityNode.getId().equals(node.getId())) { | ||||||
|  |             mobilityDialog.setNode(null); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void setWindow(Stage window) { | ||||||
|  |         this.window = window; | ||||||
|  |         sessionsDialog.setOwner(window); | ||||||
|  |         hooksDialog.setOwner(window); | ||||||
|  |         nodeServicesDialog.setOwner(window); | ||||||
|  |         serviceDialog.setOwner(window); | ||||||
|  |         nodeWlanDialog.setOwner(window); | ||||||
|  |         nodeEmaneDialog.setOwner(window); | ||||||
|  |         configDialog.setOwner(window); | ||||||
|  |         mobilityDialog.setOwner(window); | ||||||
|  |         nodeTypesDialog.setOwner(window); | ||||||
|  |         backgroundDialog.setOwner(window); | ||||||
|  |         locationDialog.setOwner(window); | ||||||
|  |         connectDialog.setOwner(window); | ||||||
|  |         guiPreferencesDialog.setOwner(window); | ||||||
|  |         nodeTypeCreateDialog.setOwner(window); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void showMobilityScriptDialogs() { | ||||||
|  |         for (Map.Entry<Integer, MobilityConfig> entry : mobilityScripts.entrySet()) { | ||||||
|  |             Integer nodeId = entry.getKey(); | ||||||
|  |             CoreNode node = networkGraph.getVertex(nodeId); | ||||||
|  |             MobilityConfig mobilityConfig = entry.getValue(); | ||||||
|  |             Platform.runLater(() -> { | ||||||
|  |                 MobilityPlayerDialog mobilityPlayerDialog = new MobilityPlayerDialog(this, node); | ||||||
|  |                 mobilityPlayerDialog.setOwner(window); | ||||||
|  |                 mobilityPlayerDialogs.put(nodeId, mobilityPlayerDialog); | ||||||
|  |                 mobilityPlayerDialog.showDialog(mobilityConfig); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onCoreMenuConnect(ActionEvent event) { | ||||||
|  |         logger.info("showing connect!"); | ||||||
|  |         connectDialog.showDialog(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onOptionsMenuNodeTypes(ActionEvent event) { | ||||||
|  |         nodeTypesDialog.showDialog(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onOptionsMenuBackground(ActionEvent event) { | ||||||
|  |         backgroundDialog.showDialog(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onOptionsMenuLocation(ActionEvent event) { | ||||||
|  |         locationDialog.showDialog(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onOptionsMenuPreferences(ActionEvent event) { | ||||||
|  |         guiPreferencesDialog.showDialog(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onHelpMenuWebsite(ActionEvent event) { | ||||||
|  |         application.getHostServices().showDocument("https://github.com/coreemu/core"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onHelpMenuDocumentation(ActionEvent event) { | ||||||
|  |         application.getHostServices().showDocument("http://coreemu.github.io/core/"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onHelpMenuMailingList(ActionEvent event) { | ||||||
|  |         application.getHostServices().showDocument("https://publists.nrl.navy.mil/mailman/listinfo/core-users"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onOpenXmlAction() { | ||||||
|  |         FileChooser fileChooser = new FileChooser(); | ||||||
|  |         fileChooser.setTitle("Open Session"); | ||||||
|  |         fileChooser.setInitialDirectory(new File(configuration.getXmlPath())); | ||||||
|  |         fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("XML", "*.xml")); | ||||||
|  |         try { | ||||||
|  |             File file = fileChooser.showOpenDialog(window); | ||||||
|  |             if (file != null) { | ||||||
|  |                 openXml(file); | ||||||
|  |             } | ||||||
|  |         } catch (IllegalArgumentException ex) { | ||||||
|  |             Toast.error(String.format("Invalid XML directory: %s", configuration.getXmlPath())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void openXml(File file) { | ||||||
|  |         logger.info("opening session xml: {}", file.getPath()); | ||||||
|  |         try { | ||||||
|  |             SessionOverview sessionOverview = coreClient.openSession(file); | ||||||
|  |             Integer sessionId = sessionOverview.getId(); | ||||||
|  |             joinSession(sessionId); | ||||||
|  |             Toast.info(String.format("Joined Session %s", sessionId)); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("Error opening session xml", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onSaveXmlAction() { | ||||||
|  |         FileChooser fileChooser = new FileChooser(); | ||||||
|  |         fileChooser.setTitle("Save Session"); | ||||||
|  |         fileChooser.setInitialFileName("session.xml"); | ||||||
|  |         fileChooser.setInitialDirectory(new File(configuration.getXmlPath())); | ||||||
|  |         fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("XML", "*.xml")); | ||||||
|  |         File file = fileChooser.showSaveDialog(window); | ||||||
|  |         if (file != null) { | ||||||
|  |             logger.info("saving session xml: {}", file.getPath()); | ||||||
|  |             try { | ||||||
|  |                 coreClient.saveSession(file); | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("Error saving session xml", ex); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onSessionMenu(ActionEvent event) { | ||||||
|  |         logger.info("sessions menu clicked"); | ||||||
|  |         try { | ||||||
|  |             sessionsDialog.showDialog(); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("Error retrieving sessions", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onSessionNodesMenu(ActionEvent event) { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onSessionHooksMenu(ActionEvent event) { | ||||||
|  |         hooksDialog.showDialog(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onSessionOptionsMenu(ActionEvent event) { | ||||||
|  |         try { | ||||||
|  |             List<ConfigGroup> configGroups = coreClient.getSessionConfig(); | ||||||
|  |             configDialog.showDialog("Session Options", configGroups, () -> { | ||||||
|  |                 List<ConfigOption> options = configDialog.getOptions(); | ||||||
|  |                 try { | ||||||
|  |                     boolean result = coreClient.setSessionConfig(options); | ||||||
|  |                     if (result) { | ||||||
|  |                         Toast.info("Session options saved"); | ||||||
|  |                     } else { | ||||||
|  |                         Toast.error("Failure to set session config"); | ||||||
|  |                     } | ||||||
|  |                 } catch (IOException ex) { | ||||||
|  |                     logger.error("error getting session config"); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error getting session config"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onTestMenuCharts(ActionEvent event) { | ||||||
|  |         chartDialog.show(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onTestMenuGeo(ActionEvent event) { | ||||||
|  |         geoDialog.showDialog(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void initialize(URL location, ResourceBundle resources) { | ||||||
|  |         coreWebSocket = new CoreWebSocket(this); | ||||||
|  |         configuration = ConfigUtils.load(); | ||||||
|  |         String address = configuration.getCoreAddress(); | ||||||
|  |         int port = configuration.getCorePort(); | ||||||
|  |         logger.info("core connection: {}:{}", address, port); | ||||||
|  |         connectDialog.setAddress(address); | ||||||
|  |         connectDialog.setPort(port); | ||||||
|  |         connectToCore(address, port); | ||||||
|  | 
 | ||||||
|  |         logger.info("controller initialize"); | ||||||
|  |         swingNode.setContent(networkGraph.getGraphViewer()); | ||||||
|  | 
 | ||||||
|  |         // update graph preferences | ||||||
|  |         networkGraph.updatePreferences(configuration); | ||||||
|  | 
 | ||||||
|  |         // set node types / default services | ||||||
|  |         graphToolbar.setupNodeTypes(); | ||||||
|  |         defaultServices = configuration.getNodeTypeConfigs().stream() | ||||||
|  |                 .collect(Collectors.toMap(NodeTypeConfig::getModel, NodeTypeConfig::getServices)); | ||||||
|  | 
 | ||||||
|  |         // set graph toolbar | ||||||
|  |         borderPane.setLeft(graphToolbar); | ||||||
|  | 
 | ||||||
|  |         // setup snackbar | ||||||
|  |         Toast.setSnackbarRoot(stackPane); | ||||||
|  | 
 | ||||||
|  |         // setup throughput menu item | ||||||
|  |         throughputMenuItem.setOnAction(event -> executorService.submit(new ChangeThroughputTask())); | ||||||
|  | 
 | ||||||
|  |         // node details | ||||||
|  |         networkGraph.getGraphViewer().getPickedVertexState().addItemListener(event -> { | ||||||
|  |             CoreNode node = (CoreNode) event.getItem(); | ||||||
|  |             logger.info("picked: {}", node.getName()); | ||||||
|  |             if (event.getStateChange() == ItemEvent.SELECTED) { | ||||||
|  |                 Platform.runLater(() -> { | ||||||
|  |                     nodeDetails.setNode(node); | ||||||
|  |                     borderPane.setRight(nodeDetails); | ||||||
|  |                 }); | ||||||
|  |             } else { | ||||||
|  |                 Platform.runLater(() -> borderPane.setRight(null)); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // edge details | ||||||
|  |         networkGraph.getGraphViewer().getPickedEdgeState().addItemListener(event -> { | ||||||
|  |             CoreLink link = (CoreLink) event.getItem(); | ||||||
|  |             logger.info("picked: {} - {}", link.getNodeOne(), link.getNodeTwo()); | ||||||
|  |             if (event.getStateChange() == ItemEvent.SELECTED) { | ||||||
|  |                 Platform.runLater(() -> { | ||||||
|  |                     linkDetails.setLink(link); | ||||||
|  |                     borderPane.setRight(linkDetails); | ||||||
|  |                 }); | ||||||
|  |             } else { | ||||||
|  |                 Platform.runLater(() -> borderPane.setRight(null)); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private class ChangeThroughputTask extends Task<Boolean> { | ||||||
|  |         @Override | ||||||
|  |         protected Boolean call() throws Exception { | ||||||
|  |             if (throughputMenuItem.isSelected()) { | ||||||
|  |                 return coreClient.startThroughput(); | ||||||
|  |             } else { | ||||||
|  |                 return coreClient.stopThroughput(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void succeeded() { | ||||||
|  |             if (getValue()) { | ||||||
|  |                 if (throughputMenuItem.isSelected()) { | ||||||
|  |                     networkGraph.setShowThroughput(true); | ||||||
|  |                 } else { | ||||||
|  |                     networkGraph.setShowThroughput(false); | ||||||
|  |                     networkGraph.getGraph().getEdges().forEach(edge -> edge.setThroughput(0)); | ||||||
|  |                     networkGraph.getGraphViewer().repaint(); | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 Toast.error("Failure changing throughput"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void failed() { | ||||||
|  |             Toast.error("Error changing throughput", new RuntimeException(getException())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								corefx/src/main/java/com/core/Main.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								corefx/src/main/java/com/core/Main.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | ||||||
|  | package com.core; | ||||||
|  | 
 | ||||||
|  | import com.core.utils.ConfigUtils; | ||||||
|  | import com.jfoenix.controls.JFXDecorator; | ||||||
|  | import com.jfoenix.svg.SVGGlyphLoader; | ||||||
|  | import javafx.application.Application; | ||||||
|  | import javafx.application.Platform; | ||||||
|  | import javafx.fxml.FXMLLoader; | ||||||
|  | import javafx.scene.Parent; | ||||||
|  | import javafx.scene.Scene; | ||||||
|  | import javafx.scene.image.Image; | ||||||
|  | import javafx.scene.image.ImageView; | ||||||
|  | import javafx.scene.text.Font; | ||||||
|  | import javafx.stage.Stage; | ||||||
|  | 
 | ||||||
|  | import java.nio.file.Path; | ||||||
|  | import java.nio.file.Paths; | ||||||
|  | 
 | ||||||
|  | public class Main extends Application { | ||||||
|  |     private static final Path LOG_FILE = Paths.get(System.getProperty("user.home"), ".core", "core.log"); | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void start(Stage window) throws Exception { | ||||||
|  |         // set core dir property for logging | ||||||
|  |         System.setProperty("core_log", LOG_FILE.toString()); | ||||||
|  | 
 | ||||||
|  |         // check for and create gui home directory | ||||||
|  |         ConfigUtils.checkHomeDirectory(); | ||||||
|  | 
 | ||||||
|  |         // load svg icons | ||||||
|  |         SVGGlyphLoader.loadGlyphsFont(getClass().getResourceAsStream("/icons/icomoon_material.svg"), | ||||||
|  |                 "icomoon.svg"); | ||||||
|  | 
 | ||||||
|  |         // load font | ||||||
|  |         Font.loadFont(getClass().getResourceAsStream("/font/roboto/Roboto-Regular.ttf"), 10); | ||||||
|  | 
 | ||||||
|  |         // load main fxml | ||||||
|  |         FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/main.fxml")); | ||||||
|  |         Parent root = loader.load(); | ||||||
|  | 
 | ||||||
|  |         // window decorator | ||||||
|  |         JFXDecorator decorator = new JFXDecorator(window, root); | ||||||
|  |         decorator.setCustomMaximize(true); | ||||||
|  |         decorator.setMaximized(true); | ||||||
|  |         decorator.setTitle("CORE"); | ||||||
|  |         Image coreIcon = new Image(getClass().getResourceAsStream("/core-icon.png")); | ||||||
|  |         decorator.setGraphic(new ImageView(coreIcon)); | ||||||
|  |         window.getIcons().add(coreIcon); | ||||||
|  | 
 | ||||||
|  |         // create scene and set as current scene within window | ||||||
|  |         Scene scene = new Scene(decorator); | ||||||
|  |         scene.getStylesheets().add(getClass().getResource("/css/main.css").toExternalForm()); | ||||||
|  |         window.setScene(scene); | ||||||
|  | 
 | ||||||
|  |         // update controller | ||||||
|  |         Controller controller = loader.getController(); | ||||||
|  |         controller.setApplication(this); | ||||||
|  |         controller.setWindow(window); | ||||||
|  |         controller.setDecorator(decorator); | ||||||
|  | 
 | ||||||
|  |         // configure window | ||||||
|  |         window.setOnCloseRequest(event -> { | ||||||
|  |             Platform.exit(); | ||||||
|  |             System.exit(0); | ||||||
|  |         }); | ||||||
|  |         window.show(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void main(String[] args) { | ||||||
|  |         launch(args); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										118
									
								
								corefx/src/main/java/com/core/client/ICoreClient.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								corefx/src/main/java/com/core/client/ICoreClient.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,118 @@ | ||||||
|  | package com.core.client; | ||||||
|  | 
 | ||||||
|  | import com.core.client.rest.ServiceFile; | ||||||
|  | import com.core.client.rest.WlanConfig; | ||||||
|  | import com.core.data.*; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Set; | ||||||
|  | 
 | ||||||
|  | public interface ICoreClient { | ||||||
|  |     void setConnection(String address, int port); | ||||||
|  | 
 | ||||||
|  |     boolean isLocalConnection(); | ||||||
|  | 
 | ||||||
|  |     Integer currentSession(); | ||||||
|  | 
 | ||||||
|  |     boolean startThroughput() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean stopThroughput() throws IOException; | ||||||
|  | 
 | ||||||
|  |     void updateSession(Integer sessionId); | ||||||
|  | 
 | ||||||
|  |     void updateState(SessionState state); | ||||||
|  | 
 | ||||||
|  |     SessionOverview createSession() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean deleteSession(Integer sessionId) throws IOException; | ||||||
|  | 
 | ||||||
|  |     List<SessionOverview> getSessions() throws IOException; | ||||||
|  | 
 | ||||||
|  |     Session getSession(Integer sessionId) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean start(Collection<CoreNode> nodes, Collection<CoreLink> links, List<Hook> hooks) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean stop() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setState(SessionState state) throws IOException; | ||||||
|  | 
 | ||||||
|  |     Map<String, List<String>> getServices() throws IOException; | ||||||
|  | 
 | ||||||
|  |     Map<String, List<String>> getDefaultServices() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setDefaultServices(Map<String, Set<String>> defaults) throws IOException; | ||||||
|  | 
 | ||||||
|  |     CoreService getService(CoreNode node, String serviceName) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setService(CoreNode node, String serviceName, CoreService service) throws IOException; | ||||||
|  | 
 | ||||||
|  |     String getServiceFile(CoreNode node, String serviceName, String fileName) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean startService(CoreNode node, String serviceName) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean stopService(CoreNode node, String serviceName) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean restartService(CoreNode node, String serviceName) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean validateService(CoreNode node, String serviceName) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setServiceFile(CoreNode node, String serviceName, ServiceFile serviceFile) throws IOException; | ||||||
|  | 
 | ||||||
|  |     List<ConfigGroup> getEmaneConfig(CoreNode node) throws IOException; | ||||||
|  | 
 | ||||||
|  |     List<String> getEmaneModels() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setEmaneConfig(CoreNode node, List<ConfigOption> options) throws IOException; | ||||||
|  | 
 | ||||||
|  |     List<ConfigGroup> getEmaneModelConfig(Integer id, String model) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setEmaneModelConfig(Integer id, String model, List<ConfigOption> options) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean isRunning(); | ||||||
|  | 
 | ||||||
|  |     void saveSession(File file) throws IOException; | ||||||
|  | 
 | ||||||
|  |     SessionOverview openSession(File file) throws IOException; | ||||||
|  | 
 | ||||||
|  |     List<ConfigGroup> getSessionConfig() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setSessionConfig(List<ConfigOption> configOptions) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean createNode(CoreNode node) throws IOException; | ||||||
|  | 
 | ||||||
|  |     String nodeCommand(CoreNode node, String command) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean editNode(CoreNode node) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean deleteNode(CoreNode node) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean createLink(CoreLink link) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean editLink(CoreLink link) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean createHook(Hook hook) throws IOException; | ||||||
|  | 
 | ||||||
|  |     List<Hook> getHooks() throws IOException; | ||||||
|  | 
 | ||||||
|  |     WlanConfig getWlanConfig(CoreNode node) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setWlanConfig(CoreNode node, WlanConfig config) throws IOException; | ||||||
|  | 
 | ||||||
|  |     String getTerminalCommand(CoreNode node) throws IOException; | ||||||
|  | 
 | ||||||
|  |     Map<Integer, MobilityConfig> getMobilityConfigs() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setMobilityConfig(CoreNode node, MobilityConfig config) throws IOException; | ||||||
|  | 
 | ||||||
|  |     MobilityConfig getMobilityConfig(CoreNode node) throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean mobilityAction(CoreNode node, String action) throws IOException; | ||||||
|  | 
 | ||||||
|  |     LocationConfig getLocationConfig() throws IOException; | ||||||
|  | 
 | ||||||
|  |     boolean setLocationConfig(LocationConfig config) throws IOException; | ||||||
|  | } | ||||||
							
								
								
									
										677
									
								
								corefx/src/main/java/com/core/client/grpc/CoreGrpcClient.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										677
									
								
								corefx/src/main/java/com/core/client/grpc/CoreGrpcClient.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,677 @@ | ||||||
|  | package com.core.client.grpc; | ||||||
|  | 
 | ||||||
|  | import com.core.client.ICoreClient; | ||||||
|  | import com.core.client.rest.ServiceFile; | ||||||
|  | import com.core.client.rest.WlanConfig; | ||||||
|  | import com.core.data.*; | ||||||
|  | import com.google.protobuf.ByteString; | ||||||
|  | import io.grpc.ManagedChannel; | ||||||
|  | import io.grpc.ManagedChannelBuilder; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.*; | ||||||
|  | 
 | ||||||
|  | public class CoreGrpcClient implements ICoreClient { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private String address; | ||||||
|  |     private int port; | ||||||
|  |     private Integer sessionId; | ||||||
|  |     private SessionState sessionState; | ||||||
|  |     private CoreApiGrpc.CoreApiBlockingStub blockingStub; | ||||||
|  |     private ManagedChannel channel; | ||||||
|  | 
 | ||||||
|  |     private CoreProto.Node nodeToProto(CoreNode node) { | ||||||
|  |         CoreProto.Position position = CoreProto.Position.newBuilder() | ||||||
|  |                 .setX(node.getPosition().getX().floatValue()) | ||||||
|  |                 .setY(node.getPosition().getY().floatValue()) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.Node.Builder builder = CoreProto.Node.newBuilder() | ||||||
|  |                 .addAllServices(node.getServices()) | ||||||
|  |                 .setType(CoreProto.NodeType.forNumber(node.getType())) | ||||||
|  |                 .setPosition(position); | ||||||
|  |         if (node.getId() != null) { | ||||||
|  |             builder.setId(node.getId()); | ||||||
|  |         } | ||||||
|  |         if (node.getName() != null) { | ||||||
|  |             builder.setName(node.getName()); | ||||||
|  |         } | ||||||
|  |         if (node.getEmane() != null) { | ||||||
|  |             builder.setEmane(node.getEmane()); | ||||||
|  |         } | ||||||
|  |         if (node.getModel() != null) { | ||||||
|  |             builder.setModel(node.getModel()); | ||||||
|  |         } | ||||||
|  |         if (node.getIcon() != null) { | ||||||
|  |             builder.setIcon(node.getIcon()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return builder.build(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private CoreProto.LinkOptions linkOptionsToProto(CoreLinkOptions options) { | ||||||
|  |         CoreProto.LinkOptions.Builder builder = CoreProto.LinkOptions.newBuilder(); | ||||||
|  |         boolean unidirectional = false; | ||||||
|  |         if (options.getUnidirectional() != null && options.getUnidirectional() == 1) { | ||||||
|  |             unidirectional = true; | ||||||
|  |         } | ||||||
|  |         if (options.getBandwidth() != null) { | ||||||
|  |             builder.setBandwidth(options.getBandwidth().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getBurst() != null) { | ||||||
|  |             builder.setBurst(options.getBurst().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getDelay() != null) { | ||||||
|  |             builder.setDelay(options.getDelay().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getDup() != null) { | ||||||
|  |             builder.setDup(options.getDup().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getJitter() != null) { | ||||||
|  |             builder.setJitter(options.getJitter().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getMburst() != null) { | ||||||
|  |             builder.setMburst(options.getMburst().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getMer() != null) { | ||||||
|  |             builder.setMer(options.getMer().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getPer() != null) { | ||||||
|  |             builder.setPer(options.getPer().floatValue()); | ||||||
|  |         } | ||||||
|  |         if (options.getKey() != null) { | ||||||
|  |             builder.setKey(options.getKey().toString()); | ||||||
|  |         } | ||||||
|  |         if (options.getOpaque() != null) { | ||||||
|  |             builder.setOpaque(options.getOpaque()); | ||||||
|  |         } | ||||||
|  |         builder.setUnidirectional(unidirectional); | ||||||
|  |         return builder.build(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private CoreProto.Interface interfaceToProto(CoreInterface coreInterface) { | ||||||
|  |         CoreProto.Interface.Builder builder = CoreProto.Interface.newBuilder(); | ||||||
|  |         if (coreInterface.getName() != null) { | ||||||
|  |             builder.setName(coreInterface.getName()); | ||||||
|  |         } | ||||||
|  |         if (coreInterface.getMac() != null) { | ||||||
|  |             builder.setMac(coreInterface.getMac()); | ||||||
|  |         } | ||||||
|  |         if (coreInterface.getIp4() != null) { | ||||||
|  |             builder.setIp4(coreInterface.getIp4()); | ||||||
|  |         } | ||||||
|  |         if (coreInterface.getIp4Mask() != null) { | ||||||
|  |             builder.setIp4Mask(coreInterface.getIp4Mask()); | ||||||
|  |         } | ||||||
|  |         if (coreInterface.getIp6() != null) { | ||||||
|  |             builder.setIp6(coreInterface.getIp6()); | ||||||
|  |         } | ||||||
|  |         if (coreInterface.getIp6Mask() != null) { | ||||||
|  |             builder.setIp6Mask(Integer.parseInt(coreInterface.getIp6Mask())); | ||||||
|  |         } | ||||||
|  |         return builder.build(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void setConnection(String address, int port) { | ||||||
|  |         this.address = address; | ||||||
|  |         this.port = port; | ||||||
|  |         logger.info("set connection: {}:{}", this.address, this.port); | ||||||
|  |         channel = ManagedChannelBuilder.forAddress(this.address, this.port).usePlaintext().build(); | ||||||
|  |         logger.info("channel: {}", channel); | ||||||
|  |         blockingStub = CoreApiGrpc.newBlockingStub(channel); | ||||||
|  |         logger.info("stub: {}", blockingStub); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isLocalConnection() { | ||||||
|  |         return address.equals("127.0.0.1") || address.equals("localhost"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Integer currentSession() { | ||||||
|  |         return sessionId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean startThroughput() throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean stopThroughput() throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void updateSession(Integer sessionId) { | ||||||
|  |         this.sessionId = sessionId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void updateState(SessionState state) { | ||||||
|  |         sessionState = state; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public SessionOverview createSession() throws IOException { | ||||||
|  |         CoreProto.CreateSessionRequest request = CoreProto.CreateSessionRequest.newBuilder().build(); | ||||||
|  |         CoreProto.CreateSessionResponse response = blockingStub.createSession(request); | ||||||
|  |         SessionOverview overview = new SessionOverview(); | ||||||
|  |         overview.setId(response.getId()); | ||||||
|  |         overview.setState(response.getStateValue()); | ||||||
|  |         overview.setNodes(0); | ||||||
|  |         return overview; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean deleteSession(Integer sessionId) throws IOException { | ||||||
|  |         CoreProto.DeleteSessionRequest request = CoreProto.DeleteSessionRequest.newBuilder().setId(sessionId).build(); | ||||||
|  |         return blockingStub.deleteSession(request).getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<SessionOverview> getSessions() throws IOException { | ||||||
|  |         CoreProto.GetSessionsRequest request = CoreProto.GetSessionsRequest.newBuilder().build(); | ||||||
|  |         CoreProto.GetSessionsResponse response = blockingStub.getSessions(request); | ||||||
|  |         List<SessionOverview> sessions = new ArrayList<>(); | ||||||
|  |         for (CoreProto.SessionSummary summary : response.getSessionsList()) { | ||||||
|  |             SessionOverview overview = new SessionOverview(); | ||||||
|  |             overview.setId(summary.getId()); | ||||||
|  |             overview.setNodes(summary.getNodes()); | ||||||
|  |             overview.setState(summary.getStateValue()); | ||||||
|  |             sessions.add(overview); | ||||||
|  |         } | ||||||
|  |         return sessions; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Session getSession(Integer sessionId) throws IOException { | ||||||
|  |         CoreProto.GetSessionRequest request = CoreProto.GetSessionRequest.newBuilder().setId(sessionId).build(); | ||||||
|  |         CoreProto.GetSessionResponse response = blockingStub.getSession(request); | ||||||
|  |         Session session = new Session(); | ||||||
|  |         for (CoreProto.Node protoNode : response.getSession().getNodesList()) { | ||||||
|  |             CoreNode node = new CoreNode(protoNode.getId()); | ||||||
|  |             node.setName(protoNode.getName()); | ||||||
|  |             node.setEmane(protoNode.getEmane()); | ||||||
|  |             node.setIcon(protoNode.getIcon()); | ||||||
|  |             node.setModel(protoNode.getModel()); | ||||||
|  |             node.setServices(new HashSet<>(protoNode.getServicesList())); | ||||||
|  |             node.getPosition().setX((double) protoNode.getPosition().getX()); | ||||||
|  |             node.getPosition().setY((double) protoNode.getPosition().getY()); | ||||||
|  |             node.getPosition().setZ((double) protoNode.getPosition().getZ()); | ||||||
|  |             node.setNodeType(NodeType.get(protoNode.getTypeValue())); | ||||||
|  |         } | ||||||
|  |         for (CoreProto.Link linkProto : response.getSession().getLinksList()) { | ||||||
|  |             CoreLink link = new CoreLink(); | ||||||
|  |             link.setNodeOne(linkProto.getNodeOne()); | ||||||
|  |             link.setNodeTwo(linkProto.getNodeOne()); | ||||||
|  |             CoreProto.Interface interfaceOneProto = linkProto.getInterfaceOne(); | ||||||
|  |             CoreInterface interfaceOne = new CoreInterface(); | ||||||
|  |             interfaceOne.setId(interfaceOneProto.getId()); | ||||||
|  |             interfaceOne.setName(interfaceOneProto.getName()); | ||||||
|  |             interfaceOne.setMac(interfaceOneProto.getMac()); | ||||||
|  |             interfaceOne.setIp4(interfaceOneProto.getIp4()); | ||||||
|  |             interfaceOne.setIp4Mask(interfaceOneProto.getIp4Mask()); | ||||||
|  |             interfaceOne.setIp6(interfaceOneProto.getIp6()); | ||||||
|  |             interfaceOne.setIp6Mask(Integer.toString(interfaceOneProto.getIp6Mask())); | ||||||
|  |             link.setInterfaceOne(interfaceOne); | ||||||
|  | 
 | ||||||
|  |             CoreProto.Interface interfaceTwoProto = linkProto.getInterfaceTwo(); | ||||||
|  |             CoreInterface interfaceTwo = new CoreInterface(); | ||||||
|  |             interfaceTwo.setId(interfaceTwoProto.getId()); | ||||||
|  |             interfaceTwo.setName(interfaceTwoProto.getName()); | ||||||
|  |             interfaceTwo.setMac(interfaceTwoProto.getMac()); | ||||||
|  |             interfaceTwo.setIp4(interfaceTwoProto.getIp4()); | ||||||
|  |             interfaceTwo.setIp4Mask(interfaceTwoProto.getIp4Mask()); | ||||||
|  |             interfaceTwo.setIp6(interfaceTwoProto.getIp6()); | ||||||
|  |             interfaceTwo.setIp6Mask(Integer.toString(interfaceTwoProto.getIp6Mask())); | ||||||
|  |             link.setInterfaceTwo(interfaceTwo); | ||||||
|  | 
 | ||||||
|  |             CoreLinkOptions options = new CoreLinkOptions(); | ||||||
|  |             CoreProto.LinkOptions protoOptions = linkProto.getOptions(); | ||||||
|  |             options.setBandwidth((double) protoOptions.getBandwidth()); | ||||||
|  |             options.setDelay((double) protoOptions.getDelay()); | ||||||
|  |             options.setDup((double) protoOptions.getDup()); | ||||||
|  |             options.setJitter((double) protoOptions.getJitter()); | ||||||
|  |             options.setPer((double) protoOptions.getPer()); | ||||||
|  |             options.setBurst((double) protoOptions.getBurst()); | ||||||
|  |             options.setKey(Integer.parseInt(protoOptions.getKey())); | ||||||
|  |             options.setMburst((double) protoOptions.getMburst()); | ||||||
|  |             options.setMer((double) protoOptions.getMer()); | ||||||
|  |             options.setOpaque(protoOptions.getOpaque()); | ||||||
|  |             options.setUnidirectional(protoOptions.getUnidirectional() ? 1 : 0); | ||||||
|  |             link.setOptions(options); | ||||||
|  |         } | ||||||
|  |         session.setState(response.getSession().getStateValue()); | ||||||
|  |         return session; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean start(Collection<CoreNode> nodes, Collection<CoreLink> links, List<Hook> hooks) throws IOException { | ||||||
|  |         boolean result = setState(SessionState.DEFINITION); | ||||||
|  |         if (!result) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         result = setState(SessionState.CONFIGURATION); | ||||||
|  |         if (!result) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (Hook hook : hooks) { | ||||||
|  |             if (!createHook(hook)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (CoreNode node : nodes) { | ||||||
|  |             // must pre-configure wlan nodes, if not already | ||||||
|  |             if (node.getNodeType().getValue() == NodeType.WLAN) { | ||||||
|  |                 WlanConfig config = getWlanConfig(node); | ||||||
|  |                 setWlanConfig(node, config); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (!createNode(node)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (CoreLink link : links) { | ||||||
|  |             if (!createLink(link)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return setState(SessionState.INSTANTIATION); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean stop() throws IOException { | ||||||
|  |         return setState(SessionState.SHUTDOWN); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setState(SessionState state) throws IOException { | ||||||
|  |         CoreProto.SetSessionStateRequest request = CoreProto.SetSessionStateRequest.newBuilder() | ||||||
|  |                 .setId(sessionId) | ||||||
|  |                 .setStateValue(state.getValue()) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.SetSessionStateResponse response = blockingStub.setSessionState(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Map<String, List<String>> getServices() throws IOException { | ||||||
|  |         CoreProto.GetServicesRequest request = CoreProto.GetServicesRequest.newBuilder().build(); | ||||||
|  |         CoreProto.GetServicesResponse response = blockingStub.getServices(request); | ||||||
|  |         Map<String, List<String>> servicesMap = new HashMap<>(); | ||||||
|  |         for (CoreProto.Service protoService : response.getServicesList()) { | ||||||
|  |             List<String> services = servicesMap.computeIfAbsent(protoService.getGroup(), x -> new ArrayList<>()); | ||||||
|  |             services.add(protoService.getName()); | ||||||
|  |         } | ||||||
|  |         return servicesMap; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Map<String, List<String>> getDefaultServices() throws IOException { | ||||||
|  |         CoreProto.GetServiceDefaultsRequest request = CoreProto.GetServiceDefaultsRequest.newBuilder().build(); | ||||||
|  |         CoreProto.GetServiceDefaultsResponse response = blockingStub.getServiceDefaults(request); | ||||||
|  |         Map<String, List<String>> servicesMap = new HashMap<>(); | ||||||
|  |         for (CoreProto.ServiceDefaults serviceDefaults : response.getDefaultsList()) { | ||||||
|  |             servicesMap.put(serviceDefaults.getNodeType(), serviceDefaults.getServicesList()); | ||||||
|  |         } | ||||||
|  |         return servicesMap; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setDefaultServices(Map<String, Set<String>> defaults) throws IOException { | ||||||
|  |         List<CoreProto.ServiceDefaults> allDefaults = new ArrayList<>(); | ||||||
|  |         for (Map.Entry<String, Set<String>> entry : defaults.entrySet()) { | ||||||
|  |             String nodeType = entry.getKey(); | ||||||
|  |             Set<String> services = entry.getValue(); | ||||||
|  |             CoreProto.ServiceDefaults serviceDefaults = CoreProto.ServiceDefaults.newBuilder() | ||||||
|  |                     .setNodeType(nodeType) | ||||||
|  |                     .addAllServices(services) | ||||||
|  |                     .build(); | ||||||
|  |             allDefaults.add(serviceDefaults); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         CoreProto.SetServiceDefaultsRequest request = CoreProto.SetServiceDefaultsRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .addAllDefaults(allDefaults) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.SetServiceDefaultsResponse response = blockingStub.setServiceDefaults(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public CoreService getService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         CoreProto.GetNodeServiceRequest request = CoreProto.GetNodeServiceRequest.newBuilder().build(); | ||||||
|  |         CoreProto.GetNodeServiceResponse response = blockingStub.getNodeService(request); | ||||||
|  |         CoreProto.NodeServiceData nodeServiceData = response.getService(); | ||||||
|  |         CoreService service = new CoreService(); | ||||||
|  |         service.setShutdown(nodeServiceData.getShutdownList()); | ||||||
|  |         service.setStartup(nodeServiceData.getStartupList()); | ||||||
|  |         service.setValidate(nodeServiceData.getValidateList()); | ||||||
|  |         service.setConfigs(nodeServiceData.getConfigsList()); | ||||||
|  |         service.setDependencies(nodeServiceData.getDependenciesList()); | ||||||
|  |         service.setDirs(nodeServiceData.getDirsList()); | ||||||
|  |         service.setExecutables(nodeServiceData.getExecutablesList()); | ||||||
|  |         service.setMeta(nodeServiceData.getMeta()); | ||||||
|  |         service.setValidationMode(nodeServiceData.getValidationMode().name()); | ||||||
|  |         service.setValidationTimer(Integer.toString(nodeServiceData.getValidationTimer())); | ||||||
|  |         return service; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setService(CoreNode node, String serviceName, CoreService service) throws IOException { | ||||||
|  |         CoreProto.SetNodeServiceRequest request = CoreProto.SetNodeServiceRequest.newBuilder() | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setService(serviceName) | ||||||
|  |                 .build(); | ||||||
|  |         request.getShutdownList().addAll(service.getShutdown()); | ||||||
|  |         request.getValidateList().addAll(service.getValidate()); | ||||||
|  |         request.getStartupList().addAll(service.getStartup()); | ||||||
|  |         return blockingStub.setNodeService(request).getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getServiceFile(CoreNode node, String serviceName, String fileName) throws IOException { | ||||||
|  |         CoreProto.GetNodeServiceFileRequest request = CoreProto.GetNodeServiceFileRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setService(serviceName) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.GetNodeServiceFileResponse response = blockingStub.getNodeServiceFile(request); | ||||||
|  |         return response.getData().toStringUtf8(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean startService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         CoreProto.ServiceActionRequest request = CoreProto.ServiceActionRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setService(serviceName) | ||||||
|  |                 .setAction(CoreProto.ServiceAction.SERVICE_START) | ||||||
|  |                 .build(); | ||||||
|  |         return blockingStub.serviceAction(request).getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean stopService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         CoreProto.ServiceActionRequest request = CoreProto.ServiceActionRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setService(serviceName) | ||||||
|  |                 .setAction(CoreProto.ServiceAction.SERVICE_STOP) | ||||||
|  |                 .build(); | ||||||
|  |         return blockingStub.serviceAction(request).getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean restartService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         CoreProto.ServiceActionRequest request = CoreProto.ServiceActionRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setService(serviceName) | ||||||
|  |                 .setAction(CoreProto.ServiceAction.SERVICE_RESTART) | ||||||
|  |                 .build(); | ||||||
|  |         return blockingStub.serviceAction(request).getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean validateService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         CoreProto.ServiceActionRequest request = CoreProto.ServiceActionRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setService(serviceName) | ||||||
|  |                 .setAction(CoreProto.ServiceAction.SERVICE_VALIDATE) | ||||||
|  |                 .build(); | ||||||
|  |         return blockingStub.serviceAction(request).getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setServiceFile(CoreNode node, String serviceName, ServiceFile serviceFile) throws IOException { | ||||||
|  |         CoreProto.SetNodeServiceFileRequest request = CoreProto.SetNodeServiceFileRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setService(serviceName) | ||||||
|  |                 .setFile(serviceFile.getName()) | ||||||
|  |                 .setData(ByteString.copyFromUtf8(serviceFile.getData())) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.SetNodeServiceFileResponse response = blockingStub.setNodeServiceFile(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<ConfigGroup> getEmaneConfig(CoreNode node) throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<String> getEmaneModels() throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setEmaneConfig(CoreNode node, List<ConfigOption> options) throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<ConfigGroup> getEmaneModelConfig(Integer id, String model) throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setEmaneModelConfig(Integer id, String model, List<ConfigOption> options) throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isRunning() { | ||||||
|  |         return sessionState == SessionState.RUNTIME; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void saveSession(File file) throws IOException { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public SessionOverview openSession(File file) throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<ConfigGroup> getSessionConfig() throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setSessionConfig(List<ConfigOption> configOptions) throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean createNode(CoreNode node) throws IOException { | ||||||
|  |         CoreProto.Node protoNode = nodeToProto(node); | ||||||
|  |         CoreProto.AddNodeRequest request = CoreProto.AddNodeRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setNode(protoNode) | ||||||
|  |                 .build(); | ||||||
|  |         blockingStub.addNode(request); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String nodeCommand(CoreNode node, String command) throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean editNode(CoreNode node) throws IOException { | ||||||
|  |         CoreProto.Position position = CoreProto.Position.newBuilder() | ||||||
|  |                 .setX(node.getPosition().getX().floatValue()) | ||||||
|  |                 .setY(node.getPosition().getY().floatValue()) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.EditNodeRequest request = CoreProto.EditNodeRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setId(node.getId()) | ||||||
|  |                 .setPosition(position) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.EditNodeResponse response = blockingStub.editNode(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean deleteNode(CoreNode node) throws IOException { | ||||||
|  |         CoreProto.DeleteNodeRequest request = CoreProto.DeleteNodeRequest.newBuilder() | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.DeleteNodeResponse response = blockingStub.deleteNode(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean createLink(CoreLink link) throws IOException { | ||||||
|  |         CoreProto.Link.Builder builder = CoreProto.Link.newBuilder() | ||||||
|  |                 .setTypeValue(link.getType()); | ||||||
|  |         if (link.getNodeOne() != null) { | ||||||
|  |             builder.setNodeOne(link.getNodeOne()); | ||||||
|  |         } | ||||||
|  |         if (link.getNodeTwo() != null) { | ||||||
|  |             builder.setNodeTwo(link.getNodeTwo()); | ||||||
|  |         } | ||||||
|  |         if (link.getInterfaceOne() != null) { | ||||||
|  |             builder.setInterfaceOne(interfaceToProto(link.getInterfaceOne())); | ||||||
|  |         } | ||||||
|  |         if (link.getInterfaceTwo() != null) { | ||||||
|  |             builder.setInterfaceTwo(interfaceToProto(link.getInterfaceTwo())); | ||||||
|  |         } | ||||||
|  |         if (link.getOptions() != null) { | ||||||
|  |             builder.setOptions(linkOptionsToProto(link.getOptions())); | ||||||
|  |         } | ||||||
|  |         CoreProto.Link protoLink = builder.build(); | ||||||
|  |         CoreProto.AddLinkRequest request = CoreProto.AddLinkRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId) | ||||||
|  |                 .setLink(protoLink) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.AddLinkResponse response = blockingStub.addLink(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean editLink(CoreLink link) throws IOException { | ||||||
|  |         CoreProto.EditLinkRequest.Builder builder = CoreProto.EditLinkRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId); | ||||||
|  |         if (link.getNodeOne() != null) { | ||||||
|  |             builder.setNodeOne(link.getNodeOne()); | ||||||
|  |         } | ||||||
|  |         if (link.getNodeTwo() != null) { | ||||||
|  |             builder.setNodeTwo(link.getNodeTwo()); | ||||||
|  |         } | ||||||
|  |         if (link.getInterfaceOne() != null) { | ||||||
|  |             builder.setInterfaceOne(link.getInterfaceOne().getId()); | ||||||
|  |         } | ||||||
|  |         if (link.getInterfaceTwo() != null) { | ||||||
|  |             builder.setInterfaceTwo(link.getInterfaceTwo().getId()); | ||||||
|  |         } | ||||||
|  |         if (link.getOptions() != null) { | ||||||
|  |             CoreProto.LinkOptions protoOptions = linkOptionsToProto(link.getOptions()); | ||||||
|  |             builder.setOptions(protoOptions); | ||||||
|  |         } | ||||||
|  |         CoreProto.EditLinkRequest request = builder.build(); | ||||||
|  |         CoreProto.EditLinkResponse response = blockingStub.editLink(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean createHook(Hook hook) throws IOException { | ||||||
|  |         CoreProto.Hook hookProto = CoreProto.Hook.newBuilder() | ||||||
|  |                 .setStateValue(hook.getState()) | ||||||
|  |                 .setData(ByteString.copyFromUtf8(hook.getData())) | ||||||
|  |                 .setFile(hook.getFile()) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.AddHookRequest request = CoreProto.AddHookRequest.newBuilder() | ||||||
|  |                 .setHook(hookProto) | ||||||
|  |                 .build(); | ||||||
|  |         CoreProto.AddHookResponse response = blockingStub.addHook(request); | ||||||
|  |         return response.getResult(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<Hook> getHooks() throws IOException { | ||||||
|  |         CoreProto.GetHooksRequest request = CoreProto.GetHooksRequest.newBuilder().setSession(sessionId).build(); | ||||||
|  |         CoreProto.GetHooksResponse response = blockingStub.getHooks(request); | ||||||
|  |         List<Hook> hooks = new ArrayList<>(); | ||||||
|  |         for (CoreProto.Hook protoHook : response.getHooksList()) { | ||||||
|  |             Hook hook = new Hook(); | ||||||
|  |             hook.setFile(protoHook.getFile()); | ||||||
|  |             hook.setData(protoHook.getData().toStringUtf8()); | ||||||
|  |             hook.setState(protoHook.getStateValue()); | ||||||
|  |             hooks.add(hook); | ||||||
|  |         } | ||||||
|  |         return hooks; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public WlanConfig getWlanConfig(CoreNode node) throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setWlanConfig(CoreNode node, WlanConfig config) throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getTerminalCommand(CoreNode node) throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Map<Integer, MobilityConfig> getMobilityConfigs() throws IOException { | ||||||
|  |         CoreProto.GetMobilityConfigsRequest request = CoreProto.GetMobilityConfigsRequest.newBuilder() | ||||||
|  |                 .setSession(sessionId).build(); | ||||||
|  |         CoreProto.GetMobilityConfigsResponse response = blockingStub.getMobilityConfigs(request); | ||||||
|  | 
 | ||||||
|  |         Map<Integer, MobilityConfig> mobilityConfigs = new HashMap<>(); | ||||||
|  |         for (Integer nodeId : response.getConfigsMap().keySet()) { | ||||||
|  |             CoreProto.GetMobilityConfigsResponse.MobilityConfig protoMobilityConfig = response.getConfigsMap() | ||||||
|  |                     .get(nodeId); | ||||||
|  |             MobilityConfig mobilityConfig = new MobilityConfig(); | ||||||
|  |             CoreProto.ConfigGroup configGroup = protoMobilityConfig.getGroups(0); | ||||||
|  |             mobilityConfigs.put(nodeId, mobilityConfig); | ||||||
|  |         } | ||||||
|  |         return mobilityConfigs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setMobilityConfig(CoreNode node, MobilityConfig config) throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public MobilityConfig getMobilityConfig(CoreNode node) throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean mobilityAction(CoreNode node, String action) throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public LocationConfig getLocationConfig() throws IOException { | ||||||
|  |         return null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setLocationConfig(LocationConfig config) throws IOException { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										415
									
								
								corefx/src/main/java/com/core/client/rest/CoreRestClient.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										415
									
								
								corefx/src/main/java/com/core/client/rest/CoreRestClient.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,415 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.client.ICoreClient; | ||||||
|  | import com.core.data.*; | ||||||
|  | import com.core.utils.WebUtils; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.*; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class CoreRestClient implements ICoreClient { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private String address; | ||||||
|  |     private int port; | ||||||
|  |     private Integer sessionId; | ||||||
|  |     private SessionState sessionState; | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void setConnection(String address, int port) { | ||||||
|  |         this.address = address; | ||||||
|  |         this.port = port; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isLocalConnection() { | ||||||
|  |         return address.equals("127.0.0.1") || address.equals("localhost"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Integer currentSession() { | ||||||
|  |         return sessionId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void updateState(SessionState state) { | ||||||
|  |         sessionState = state; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void updateSession(Integer sessionId) { | ||||||
|  |         this.sessionId = sessionId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private String getUrl(String path) { | ||||||
|  |         return String.format("http://%s:%s/%s", address, port, path); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public SessionOverview createSession() throws IOException { | ||||||
|  |         String url = getUrl("sessions"); | ||||||
|  |         return WebUtils.post(url, SessionOverview.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean deleteSession(Integer sessionId) throws IOException { | ||||||
|  |         String path = String.format("sessions/%s", sessionId); | ||||||
|  |         String url = getUrl(path); | ||||||
|  |         return WebUtils.delete(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Map<String, List<String>> getServices() throws IOException { | ||||||
|  |         String url = getUrl("services"); | ||||||
|  |         GetServices getServices = WebUtils.getJson(url, GetServices.class); | ||||||
|  |         return getServices.getGroups(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Session getSession(Integer sessionId) throws IOException { | ||||||
|  |         String path = String.format("sessions/%s", sessionId); | ||||||
|  |         String url = getUrl(path); | ||||||
|  |         return WebUtils.getJson(url, Session.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<SessionOverview> getSessions() throws IOException { | ||||||
|  |         String url = getUrl("sessions"); | ||||||
|  |         GetSessions getSessions = WebUtils.getJson(url, GetSessions.class); | ||||||
|  |         return getSessions.getSessions(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean start(Collection<CoreNode> nodes, Collection<CoreLink> links, List<Hook> hooks) throws IOException { | ||||||
|  |         boolean result = setState(SessionState.DEFINITION); | ||||||
|  |         if (!result) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         result = setState(SessionState.CONFIGURATION); | ||||||
|  |         if (!result) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (Hook hook : hooks) { | ||||||
|  |             if (!createHook(hook)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (CoreNode node : nodes) { | ||||||
|  |             // must pre-configure wlan nodes, if not already | ||||||
|  |             if (node.getNodeType().getValue() == NodeType.WLAN) { | ||||||
|  |                 WlanConfig config = getWlanConfig(node); | ||||||
|  |                 setWlanConfig(node, config); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (!createNode(node)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (CoreLink link : links) { | ||||||
|  |             if (!createLink(link)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return setState(SessionState.INSTANTIATION); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean stop() throws IOException { | ||||||
|  |         return setState(SessionState.SHUTDOWN); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setState(SessionState state) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/state", sessionId)); | ||||||
|  |         Map<String, Integer> data = new HashMap<>(); | ||||||
|  |         data.put("state", state.getValue()); | ||||||
|  |         boolean result = WebUtils.putJson(url, data); | ||||||
|  | 
 | ||||||
|  |         if (result) { | ||||||
|  |             sessionState = state; | ||||||
|  |         } | ||||||
|  |         return result; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean uploadFile(File file) throws IOException { | ||||||
|  |         String url = getUrl("upload"); | ||||||
|  |         return WebUtils.postFile(url, file); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean startThroughput() throws IOException { | ||||||
|  |         String url = getUrl("throughput/start"); | ||||||
|  |         return WebUtils.putJson(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean stopThroughput() throws IOException { | ||||||
|  |         String url = getUrl("throughput/stop"); | ||||||
|  |         return WebUtils.putJson(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Map<String, List<String>> getDefaultServices() throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/services/default", sessionId)); | ||||||
|  |         GetDefaultServices getDefaultServices = WebUtils.getJson(url, GetDefaultServices.class); | ||||||
|  |         return getDefaultServices.getDefaults(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setDefaultServices(Map<String, Set<String>> defaults) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/services/default", sessionId)); | ||||||
|  |         return WebUtils.postJson(url, defaults); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public CoreService getService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s", sessionId, node.getId(), serviceName)); | ||||||
|  |         return WebUtils.getJson(url, CoreService.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setService(CoreNode node, String serviceName, CoreService service) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s", sessionId, node.getId(), serviceName)); | ||||||
|  |         return WebUtils.putJson(url, service); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getServiceFile(CoreNode node, String serviceName, String fileName) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/file", sessionId, node.getId(), | ||||||
|  |                 serviceName)); | ||||||
|  |         Map<String, String> args = new HashMap<>(); | ||||||
|  |         args.put("file", fileName); | ||||||
|  |         return WebUtils.getJson(url, String.class, args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean startService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/start", sessionId, node.getId(), | ||||||
|  |                 serviceName)); | ||||||
|  |         return WebUtils.putJson(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean stopService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/stop", sessionId, node.getId(), | ||||||
|  |                 serviceName)); | ||||||
|  |         return WebUtils.putJson(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean restartService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/restart", sessionId, node.getId(), | ||||||
|  |                 serviceName)); | ||||||
|  |         return WebUtils.putJson(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean validateService(CoreNode node, String serviceName) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/validate", sessionId, node.getId(), | ||||||
|  |                 serviceName)); | ||||||
|  |         return WebUtils.putJson(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setServiceFile(CoreNode node, String serviceName, ServiceFile serviceFile) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/file", sessionId, node.getId(), | ||||||
|  |                 serviceName)); | ||||||
|  |         return WebUtils.putJson(url, serviceFile); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<String> getEmaneModels() throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/emane/models", sessionId)); | ||||||
|  |         GetEmaneModels getEmaneModels = WebUtils.getJson(url, GetEmaneModels.class); | ||||||
|  |         return getEmaneModels.getModels(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<ConfigGroup> getEmaneModelConfig(Integer id, String model) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/emane/model/config", sessionId)); | ||||||
|  |         Map<String, String> args = new HashMap<>(); | ||||||
|  |         args.put("node", id.toString()); | ||||||
|  |         args.put("name", model); | ||||||
|  |         GetConfig getConfig = WebUtils.getJson(url, GetConfig.class, args); | ||||||
|  |         return getConfig.getGroups(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<ConfigGroup> getEmaneConfig(CoreNode node) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/emane/config", sessionId)); | ||||||
|  |         Map<String, String> args = new HashMap<>(); | ||||||
|  |         args.put("node", node.getId().toString()); | ||||||
|  |         GetConfig getConfig = WebUtils.getJson(url, GetConfig.class, args); | ||||||
|  |         return getConfig.getGroups(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setEmaneConfig(CoreNode node, List<ConfigOption> options) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/emane/config", sessionId)); | ||||||
|  |         SetEmaneConfig setEmaneConfig = new SetEmaneConfig(); | ||||||
|  |         setEmaneConfig.setNode(node.getId()); | ||||||
|  |         setEmaneConfig.setValues(options); | ||||||
|  |         return WebUtils.putJson(url, setEmaneConfig); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setEmaneModelConfig(Integer id, String model, List<ConfigOption> options) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/emane/model/config", sessionId)); | ||||||
|  |         SetEmaneModelConfig setEmaneModelConfig = new SetEmaneModelConfig(); | ||||||
|  |         setEmaneModelConfig.setNode(id); | ||||||
|  |         setEmaneModelConfig.setName(model); | ||||||
|  |         setEmaneModelConfig.setValues(options); | ||||||
|  |         return WebUtils.putJson(url, setEmaneModelConfig); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean isRunning() { | ||||||
|  |         return sessionState == SessionState.RUNTIME; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void saveSession(File file) throws IOException { | ||||||
|  |         String path = String.format("sessions/%s/xml", sessionId); | ||||||
|  |         String url = getUrl(path); | ||||||
|  |         WebUtils.getFile(url, file); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public SessionOverview openSession(File file) throws IOException { | ||||||
|  |         String url = getUrl("sessions/xml"); | ||||||
|  |         return WebUtils.postFile(url, file, SessionOverview.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<ConfigGroup> getSessionConfig() throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/options", sessionId)); | ||||||
|  |         GetConfig getConfig = WebUtils.getJson(url, GetConfig.class); | ||||||
|  |         return getConfig.getGroups(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setSessionConfig(List<ConfigOption> configOptions) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/options", sessionId)); | ||||||
|  |         SetConfig setConfig = new SetConfig(configOptions); | ||||||
|  |         return WebUtils.putJson(url, setConfig); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public LocationConfig getLocationConfig() throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/location", sessionId)); | ||||||
|  |         return WebUtils.getJson(url, LocationConfig.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setLocationConfig(LocationConfig config) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/location", sessionId)); | ||||||
|  |         return WebUtils.putJson(url, config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String nodeCommand(CoreNode node, String command) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/command", sessionId, node.getId())); | ||||||
|  |         return WebUtils.putJson(url, command, String.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean createNode(CoreNode node) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes", sessionId)); | ||||||
|  |         return WebUtils.postJson(url, node); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean editNode(CoreNode node) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s", sessionId, node.getId())); | ||||||
|  |         return WebUtils.putJson(url, node); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean deleteNode(CoreNode node) throws IOException { | ||||||
|  |         String url = getUrl(String.format("/sessions/%s/nodes/%s", sessionId, node.getId())); | ||||||
|  |         return WebUtils.delete(url); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean createLink(CoreLink link) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/links", sessionId)); | ||||||
|  |         return WebUtils.postJson(url, link); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean editLink(CoreLink link) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/links", sessionId)); | ||||||
|  |         return WebUtils.putJson(url, link); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean createHook(Hook hook) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/hooks", sessionId)); | ||||||
|  |         return WebUtils.postJson(url, hook); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public List<Hook> getHooks() throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/hooks", sessionId)); | ||||||
|  |         GetHooks getHooks = WebUtils.getJson(url, GetHooks.class); | ||||||
|  |         return getHooks.getHooks(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public WlanConfig getWlanConfig(CoreNode node) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/wlan", sessionId, node.getId())); | ||||||
|  |         return WebUtils.getJson(url, WlanConfig.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setWlanConfig(CoreNode node, WlanConfig config) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/wlan", sessionId, node.getId())); | ||||||
|  |         return WebUtils.putJson(url, config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getTerminalCommand(CoreNode node) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/terminal", sessionId, node.getId())); | ||||||
|  |         return WebUtils.getJson(url, String.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean setMobilityConfig(CoreNode node, MobilityConfig config) throws IOException { | ||||||
|  |         boolean uploaded = uploadFile(config.getScriptFile()); | ||||||
|  |         if (!uploaded) { | ||||||
|  |             throw new IOException("failed to upload mobility script"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", sessionId, node.getId())); | ||||||
|  |         config.setFile(config.getScriptFile().getName()); | ||||||
|  |         return WebUtils.postJson(url, config); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Map<Integer, MobilityConfig> getMobilityConfigs() throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/mobility/configs", sessionId)); | ||||||
|  |         GetMobilityConfigs getMobilityConfigs = WebUtils.getJson(url, GetMobilityConfigs.class); | ||||||
|  |         return getMobilityConfigs.getConfigurations(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public MobilityConfig getMobilityConfig(CoreNode node) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", sessionId, node.getId())); | ||||||
|  |         return WebUtils.getJson(url, MobilityConfig.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean mobilityAction(CoreNode node, String action) throws IOException { | ||||||
|  |         String url = getUrl(String.format("sessions/%s/nodes/%s/mobility/%s", sessionId, node.getId(), action)); | ||||||
|  |         return WebUtils.putJson(url); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								corefx/src/main/java/com/core/client/rest/GetConfig.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								corefx/src/main/java/com/core/client/rest/GetConfig.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.data.ConfigGroup; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class GetConfig { | ||||||
|  |     private List<ConfigGroup> groups = new ArrayList<>(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,16 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @AllArgsConstructor | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class GetDefaultServices { | ||||||
|  |     private Map<String, List<String>> defaults = new HashMap<>(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,11 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class GetEmaneModels { | ||||||
|  |     private List<String> models = new ArrayList<>(); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								corefx/src/main/java/com/core/client/rest/GetHooks.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								corefx/src/main/java/com/core/client/rest/GetHooks.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.data.Hook; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class GetHooks { | ||||||
|  |     private List<Hook> hooks = new ArrayList<>(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.data.MobilityConfig; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class GetMobilityConfigs { | ||||||
|  |     private Map<Integer, MobilityConfig> configurations = new HashMap<>(); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								corefx/src/main/java/com/core/client/rest/GetServices.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								corefx/src/main/java/com/core/client/rest/GetServices.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class GetServices { | ||||||
|  |     private Map<String, List<String>> groups; | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								corefx/src/main/java/com/core/client/rest/GetSessions.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								corefx/src/main/java/com/core/client/rest/GetSessions.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.data.SessionOverview; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class GetSessions { | ||||||
|  |     private List<SessionOverview> sessions = new ArrayList<>(); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								corefx/src/main/java/com/core/client/rest/ServiceFile.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								corefx/src/main/java/com/core/client/rest/ServiceFile.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @AllArgsConstructor | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class ServiceFile { | ||||||
|  |     private String name; | ||||||
|  |     private String data; | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								corefx/src/main/java/com/core/client/rest/SetConfig.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								corefx/src/main/java/com/core/client/rest/SetConfig.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.data.ConfigOption; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @AllArgsConstructor | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class SetConfig { | ||||||
|  |     private List<ConfigOption> values = new ArrayList<>(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.data.ConfigOption; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class SetEmaneConfig { | ||||||
|  |     private Integer node; | ||||||
|  |     private List<ConfigOption> values = new ArrayList<>(); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import com.core.data.ConfigOption; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class SetEmaneModelConfig { | ||||||
|  |     private Integer node; | ||||||
|  |     private String name; | ||||||
|  |     private List<ConfigOption> values = new ArrayList<>(); | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								corefx/src/main/java/com/core/client/rest/WlanConfig.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								corefx/src/main/java/com/core/client/rest/WlanConfig.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.client.rest; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class WlanConfig { | ||||||
|  |     private String range; | ||||||
|  |     private String bandwidth; | ||||||
|  |     private String jitter; | ||||||
|  |     private String delay; | ||||||
|  |     private String error; | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								corefx/src/main/java/com/core/data/BridgeThroughput.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								corefx/src/main/java/com/core/data/BridgeThroughput.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class BridgeThroughput { | ||||||
|  |     private int node; | ||||||
|  |     private Double throughput; | ||||||
|  | } | ||||||
							
								
								
									
										40
									
								
								corefx/src/main/java/com/core/data/ConfigDataType.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								corefx/src/main/java/com/core/data/ConfigDataType.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public enum ConfigDataType { | ||||||
|  |     UINT8(1), | ||||||
|  |     UINT16(2), | ||||||
|  |     UINT32(3), | ||||||
|  |     UINT64(4), | ||||||
|  |     INT8(5), | ||||||
|  |     INT16(6), | ||||||
|  |     INT32(7), | ||||||
|  |     INT64(8), | ||||||
|  |     FLOAT(9), | ||||||
|  |     STRING(10), | ||||||
|  |     BOOL(11); | ||||||
|  | 
 | ||||||
|  |     private static final Map<Integer, ConfigDataType> LOOKUP = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     static { | ||||||
|  |         Arrays.stream(ConfigDataType.values()).forEach(x -> LOOKUP.put(x.getValue(), x)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private final int value; | ||||||
|  | 
 | ||||||
|  |     ConfigDataType(int value) { | ||||||
|  |         this.value = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getValue() { | ||||||
|  |         return value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public static ConfigDataType get(int value) { | ||||||
|  |         return LOOKUP.get(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								corefx/src/main/java/com/core/data/ConfigGroup.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								corefx/src/main/java/com/core/data/ConfigGroup.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class ConfigGroup { | ||||||
|  |     private String name; | ||||||
|  |     private List<ConfigOption> options = new ArrayList<>(); | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								corefx/src/main/java/com/core/data/ConfigOption.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								corefx/src/main/java/com/core/data/ConfigOption.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class ConfigOption { | ||||||
|  |     private String label; | ||||||
|  |     private String name; | ||||||
|  |     private String value; | ||||||
|  |     private Integer type; | ||||||
|  |     private List<String> select = new ArrayList<>(); | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								corefx/src/main/java/com/core/data/CoreEvent.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								corefx/src/main/java/com/core/data/CoreEvent.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonSetter; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class CoreEvent { | ||||||
|  |     private Integer session; | ||||||
|  |     private Integer node; | ||||||
|  |     private String name; | ||||||
|  |     private Double time; | ||||||
|  |     private EventType eventType; | ||||||
|  |     private String data; | ||||||
|  | 
 | ||||||
|  |     @JsonSetter("event_type") | ||||||
|  |     public void setEventType(int value) { | ||||||
|  |         eventType = EventType.get(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								corefx/src/main/java/com/core/data/CoreInterface.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								corefx/src/main/java/com/core/data/CoreInterface.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class CoreInterface { | ||||||
|  |     private Integer id; | ||||||
|  |     private String name; | ||||||
|  |     private String mac; | ||||||
|  |     private String ip4; | ||||||
|  |     @JsonProperty("ip4mask") | ||||||
|  |     private Integer ip4Mask; | ||||||
|  |     private String ip6; | ||||||
|  |     @JsonProperty("ip6mask") | ||||||
|  |     private String ip6Mask; | ||||||
|  | } | ||||||
							
								
								
									
										56
									
								
								corefx/src/main/java/com/core/data/CoreLink.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								corefx/src/main/java/com/core/data/CoreLink.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | @EqualsAndHashCode(onlyExplicitlyIncluded = true) | ||||||
|  | public class CoreLink { | ||||||
|  |     @EqualsAndHashCode.Include | ||||||
|  |     private Integer id; | ||||||
|  | 
 | ||||||
|  |     @JsonIgnore | ||||||
|  |     private Float weight = 1.0f; | ||||||
|  | 
 | ||||||
|  |     @JsonIgnore | ||||||
|  |     private boolean loaded = true; | ||||||
|  | 
 | ||||||
|  |     @JsonIgnore | ||||||
|  |     private double throughput; | ||||||
|  | 
 | ||||||
|  |     @JsonIgnore | ||||||
|  |     private boolean visible = true; | ||||||
|  | 
 | ||||||
|  |     @JsonProperty("message_type") | ||||||
|  |     private Integer messageType; | ||||||
|  | 
 | ||||||
|  |     private Integer type = 1; | ||||||
|  | 
 | ||||||
|  |     @JsonProperty("node_one") | ||||||
|  |     private Integer nodeOne; | ||||||
|  | 
 | ||||||
|  |     @JsonProperty("node_two") | ||||||
|  |     private Integer nodeTwo; | ||||||
|  | 
 | ||||||
|  |     @JsonProperty("interface_one") | ||||||
|  |     private CoreInterface interfaceOne; | ||||||
|  | 
 | ||||||
|  |     @JsonProperty("interface_two") | ||||||
|  |     private CoreInterface interfaceTwo; | ||||||
|  | 
 | ||||||
|  |     private CoreLinkOptions options = new CoreLinkOptions(); | ||||||
|  | 
 | ||||||
|  |     public CoreLink(Integer id) { | ||||||
|  |         this.id = id; | ||||||
|  |         this.weight = (float) id; | ||||||
|  |         this.loaded = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean isWireless() { | ||||||
|  |         return interfaceOne == null && interfaceTwo == null; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								corefx/src/main/java/com/core/data/CoreLinkOptions.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								corefx/src/main/java/com/core/data/CoreLinkOptions.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class CoreLinkOptions { | ||||||
|  |     private String opaque; | ||||||
|  |     private Integer session; | ||||||
|  |     private Double jitter; | ||||||
|  |     private Integer key; | ||||||
|  |     private Double mburst; | ||||||
|  |     private Double mer; | ||||||
|  |     private Double per; | ||||||
|  |     private Double bandwidth; | ||||||
|  |     private Double burst; | ||||||
|  |     private Double delay; | ||||||
|  |     private Double dup; | ||||||
|  |     private Integer unidirectional; | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								corefx/src/main/java/com/core/data/CoreNode.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								corefx/src/main/java/com/core/data/CoreNode.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,59 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.core.graph.RadioIcon; | ||||||
|  | import com.core.utils.IconUtils; | ||||||
|  | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
|  | import edu.uci.ics.jung.visualization.LayeredIcon; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.HashSet; | ||||||
|  | import java.util.Set; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | @EqualsAndHashCode(onlyExplicitlyIncluded = true) | ||||||
|  | public class CoreNode { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @EqualsAndHashCode.Include | ||||||
|  |     private Integer id; | ||||||
|  |     private String name; | ||||||
|  |     private Integer type; | ||||||
|  |     private String model; | ||||||
|  |     private Position position = new Position(); | ||||||
|  |     private Set<String> services = new HashSet<>(); | ||||||
|  |     private String emane; | ||||||
|  |     private String url; | ||||||
|  |     @JsonIgnore | ||||||
|  |     private NodeType nodeType; | ||||||
|  |     @JsonIgnore | ||||||
|  |     private String icon; | ||||||
|  |     @JsonIgnore | ||||||
|  |     private boolean loaded = true; | ||||||
|  |     @JsonIgnore | ||||||
|  |     private LayeredIcon graphIcon; | ||||||
|  |     @JsonIgnore | ||||||
|  |     private RadioIcon radioIcon = new RadioIcon(); | ||||||
|  | 
 | ||||||
|  |     public CoreNode(Integer id) { | ||||||
|  |         this.id = id; | ||||||
|  |         this.name = String.format("Node%s", this.id); | ||||||
|  |         this.loaded = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNodeType(NodeType nodeType) { | ||||||
|  |         type = nodeType.getValue(); | ||||||
|  |         model = nodeType.getModel(); | ||||||
|  |         icon = nodeType.getIcon(); | ||||||
|  |         if (icon.startsWith("file:")) { | ||||||
|  |             graphIcon = IconUtils.getExternalLayeredIcon(icon); | ||||||
|  |         } else { | ||||||
|  |             graphIcon = IconUtils.getLayeredIcon(icon); | ||||||
|  |         } | ||||||
|  |         graphIcon.add(radioIcon); | ||||||
|  |         this.nodeType = nodeType; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								corefx/src/main/java/com/core/data/CoreService.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								corefx/src/main/java/com/core/data/CoreService.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class CoreService { | ||||||
|  |     private List<String> executables = new ArrayList<>(); | ||||||
|  |     private List<String> dependencies = new ArrayList<>(); | ||||||
|  |     private List<String> dirs = new ArrayList<>(); | ||||||
|  |     private List<String> configs = new ArrayList<>(); | ||||||
|  |     private List<String> startup = new ArrayList<>(); | ||||||
|  |     private List<String> validate = new ArrayList<>(); | ||||||
|  |     @JsonProperty("validation_mode") | ||||||
|  |     private String validationMode; | ||||||
|  |     @JsonProperty("validation_timer") | ||||||
|  |     private String validationTimer; | ||||||
|  |     private List<String> shutdown = new ArrayList<>(); | ||||||
|  |     private String meta; | ||||||
|  | } | ||||||
							
								
								
									
										45
									
								
								corefx/src/main/java/com/core/data/EventType.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								corefx/src/main/java/com/core/data/EventType.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public enum EventType { | ||||||
|  |     NONE(0), | ||||||
|  |     DEFINITION_STATE(1), | ||||||
|  |     CONFIGURATION_STATE(2), | ||||||
|  |     INSTANTIATION_STATE(3), | ||||||
|  |     RUNTIME_STATE(4), | ||||||
|  |     DATACOLLECT_STATE(5), | ||||||
|  |     SHUTDOWN_STATE(6), | ||||||
|  |     START(7), | ||||||
|  |     STOP(8), | ||||||
|  |     PAUSE(9), | ||||||
|  |     RESTART(10), | ||||||
|  |     FILE_OPEN(11), | ||||||
|  |     FILE_SAVE(12), | ||||||
|  |     SCHEDULED(13), | ||||||
|  |     RECONFIGURE(14), | ||||||
|  |     INSTANTIATION_COMPLETE(15); | ||||||
|  | 
 | ||||||
|  |     private static final Map<Integer, EventType> LOOKUP = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     static { | ||||||
|  |         Arrays.stream(EventType.values()).forEach(x -> LOOKUP.put(x.getValue(), x)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private final int value; | ||||||
|  | 
 | ||||||
|  |     EventType(int value) { | ||||||
|  |         this.value = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getValue() { | ||||||
|  |         return value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public static EventType get(int value) { | ||||||
|  |         return LOOKUP.get(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								corefx/src/main/java/com/core/data/Hook.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								corefx/src/main/java/com/core/data/Hook.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class Hook { | ||||||
|  |     private String file; | ||||||
|  |     private Integer state; | ||||||
|  |     @JsonIgnore | ||||||
|  |     private String stateDisplay; | ||||||
|  |     private String data; | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								corefx/src/main/java/com/core/data/InterfaceThroughput.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								corefx/src/main/java/com/core/data/InterfaceThroughput.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class InterfaceThroughput { | ||||||
|  |     private int node; | ||||||
|  |     @JsonProperty("interface") | ||||||
|  |     private int nodeInterface; | ||||||
|  |     private double throughput; | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								corefx/src/main/java/com/core/data/LinkTypes.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								corefx/src/main/java/com/core/data/LinkTypes.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public enum LinkTypes { | ||||||
|  |     WIRELESS(0), | ||||||
|  |     WIRED(1); | ||||||
|  | 
 | ||||||
|  |     private static final Map<Integer, LinkTypes> LOOKUP = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     static { | ||||||
|  |         for (LinkTypes state : LinkTypes.values()) { | ||||||
|  |             LOOKUP.put(state.getValue(), state); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private final int value; | ||||||
|  | 
 | ||||||
|  |     LinkTypes(int value) { | ||||||
|  |         this.value = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getValue() { | ||||||
|  |         return this.value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static LinkTypes get(int value) { | ||||||
|  |         return LOOKUP.get(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								corefx/src/main/java/com/core/data/Location.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								corefx/src/main/java/com/core/data/Location.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class Location { | ||||||
|  |     private Double latitude = 0.0; | ||||||
|  |     private Double longitude = 0.0; | ||||||
|  |     private Double altitude = 0.0; | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								corefx/src/main/java/com/core/data/LocationConfig.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								corefx/src/main/java/com/core/data/LocationConfig.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class LocationConfig { | ||||||
|  |     private Position position = new Position(); | ||||||
|  |     private Location location = new Location(); | ||||||
|  |     private Double scale; | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								corefx/src/main/java/com/core/data/MessageFlags.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								corefx/src/main/java/com/core/data/MessageFlags.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public enum MessageFlags { | ||||||
|  |     ADD(1), | ||||||
|  |     DELETE(2), | ||||||
|  |     CRI(4), | ||||||
|  |     LOCAL(8), | ||||||
|  |     STRING(16), | ||||||
|  |     TEXT(32), | ||||||
|  |     TTY(64); | ||||||
|  | 
 | ||||||
|  |     private static final Map<Integer, MessageFlags> LOOKUP = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     static { | ||||||
|  |         for (MessageFlags state : MessageFlags.values()) { | ||||||
|  |             LOOKUP.put(state.getValue(), state); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private final int value; | ||||||
|  | 
 | ||||||
|  |     MessageFlags(int value) { | ||||||
|  |         this.value = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getValue() { | ||||||
|  |         return this.value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static MessageFlags get(int value) { | ||||||
|  |         return LOOKUP.get(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								corefx/src/main/java/com/core/data/MobilityConfig.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								corefx/src/main/java/com/core/data/MobilityConfig.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class MobilityConfig { | ||||||
|  |     private String file; | ||||||
|  |     @JsonIgnore | ||||||
|  |     private File scriptFile; | ||||||
|  |     @JsonProperty("refresh_ms") | ||||||
|  |     private Integer refresh; | ||||||
|  |     private String loop; | ||||||
|  |     private String autostart; | ||||||
|  |     private String map; | ||||||
|  |     @JsonProperty("script_start") | ||||||
|  |     private String startScript; | ||||||
|  |     @JsonProperty("script_pause") | ||||||
|  |     private String pauseScript; | ||||||
|  |     @JsonProperty("script_stop") | ||||||
|  |     private String stopScript; | ||||||
|  | } | ||||||
							
								
								
									
										86
									
								
								corefx/src/main/java/com/core/data/NodeType.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								corefx/src/main/java/com/core/data/NodeType.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.*; | ||||||
|  | import java.util.concurrent.atomic.AtomicInteger; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @EqualsAndHashCode(onlyExplicitlyIncluded = true) | ||||||
|  | public class NodeType { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final AtomicInteger idGenerator = new AtomicInteger(0); | ||||||
|  |     private static final Map<Integer, NodeType> ID_LOOKUP = new HashMap<>(); | ||||||
|  |     public static final int DEFAULT = 0; | ||||||
|  |     public static final int SWITCH = 4; | ||||||
|  |     public static final int HUB = 5; | ||||||
|  |     public static final int WLAN = 6; | ||||||
|  |     public static final int EMANE = 10; | ||||||
|  |     @EqualsAndHashCode.Include | ||||||
|  |     private final int id; | ||||||
|  |     private final int value; | ||||||
|  |     private final Set<String> services = new TreeSet<>(); | ||||||
|  |     private String display; | ||||||
|  |     private String model; | ||||||
|  |     private String icon; | ||||||
|  | 
 | ||||||
|  |     //    PHYSICAL = 1 | ||||||
|  | //    RJ45 = 7 | ||||||
|  | //    TUNNEL = 8 | ||||||
|  | //    KTUNNEL = 9 | ||||||
|  | //    EMANE = 10 | ||||||
|  | //    TAP_BRIDGE = 11 | ||||||
|  | //    PEER_TO_PEER = 12 | ||||||
|  | //    CONTROL_NET = 13 | ||||||
|  | //    EMANE_NET = 14; | ||||||
|  | 
 | ||||||
|  |     static { | ||||||
|  |         add(new NodeType(SWITCH, "lanswitch", "Switch", "/icons/switch-100.png")); | ||||||
|  |         add(new NodeType(HUB, "hub", "Hub", "/icons/hub-100.png")); | ||||||
|  |         add(new NodeType(WLAN, "wlan", "WLAN", "/icons/wlan-100.png")); | ||||||
|  |         add(new NodeType(EMANE, "wlan", "EMANE", "/icons/emane-100.png")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public NodeType(int value, String model, String display, String icon) { | ||||||
|  |         this.id = idGenerator.incrementAndGet(); | ||||||
|  |         this.value = value; | ||||||
|  |         this.model = model; | ||||||
|  |         this.display = display; | ||||||
|  |         this.icon = icon; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void add(NodeType nodeType) { | ||||||
|  |         ID_LOOKUP.put(nodeType.getId(), nodeType); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void remove(NodeType nodeType) { | ||||||
|  |         ID_LOOKUP.remove(nodeType.getId()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static NodeType get(Integer id) { | ||||||
|  |         return ID_LOOKUP.get(id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static Collection<NodeType> getAll() { | ||||||
|  |         return ID_LOOKUP.values(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static NodeType find(Integer type, String model) { | ||||||
|  |         return ID_LOOKUP.values().stream() | ||||||
|  |                 .filter(nodeType -> { | ||||||
|  |                     boolean sameType = nodeType.getValue() == type; | ||||||
|  |                     boolean sameModel; | ||||||
|  |                     if (model != null) { | ||||||
|  |                         sameModel = model.equals(nodeType.getModel()); | ||||||
|  |                     } else { | ||||||
|  |                         sameModel = nodeType.getModel() == null; | ||||||
|  |                     } | ||||||
|  |                     return sameType && sameModel; | ||||||
|  |                 }) | ||||||
|  |                 .findFirst().orElse(null); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								corefx/src/main/java/com/core/data/Position.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								corefx/src/main/java/com/core/data/Position.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class Position { | ||||||
|  |     private Double x; | ||||||
|  |     private Double y; | ||||||
|  |     private Double z; | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								corefx/src/main/java/com/core/data/Session.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								corefx/src/main/java/com/core/data/Session.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class Session { | ||||||
|  |     private Integer state; | ||||||
|  |     private List<CoreNode> nodes = new ArrayList<>(); | ||||||
|  |     private List<CoreLink> links = new ArrayList<>(); | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								corefx/src/main/java/com/core/data/SessionOverview.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								corefx/src/main/java/com/core/data/SessionOverview.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class SessionOverview { | ||||||
|  |     private Integer id; | ||||||
|  |     private Integer state; | ||||||
|  |     private Integer nodes = 0; | ||||||
|  |     private String url; | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								corefx/src/main/java/com/core/data/SessionState.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								corefx/src/main/java/com/core/data/SessionState.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public enum SessionState { | ||||||
|  |     DEFINITION(1), | ||||||
|  |     CONFIGURATION(2), | ||||||
|  |     INSTANTIATION(3), | ||||||
|  |     RUNTIME(4), | ||||||
|  |     DATA_COLLECT(5), | ||||||
|  |     SHUTDOWN(6), | ||||||
|  |     START(7), | ||||||
|  |     STOP(8), | ||||||
|  |     PAUSE(9); | ||||||
|  | 
 | ||||||
|  |     private static final Map<Integer, SessionState> LOOKUP = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     static { | ||||||
|  |         for (SessionState state : SessionState.values()) { | ||||||
|  |             LOOKUP.put(state.getValue(), state); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private final int value; | ||||||
|  | 
 | ||||||
|  |     SessionState(int value) { | ||||||
|  |         this.value = value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getValue() { | ||||||
|  |         return this.value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static SessionState get(int value) { | ||||||
|  |         return LOOKUP.get(value); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										12
									
								
								corefx/src/main/java/com/core/data/Throughputs.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								corefx/src/main/java/com/core/data/Throughputs.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | package com.core.data; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class Throughputs { | ||||||
|  |     private List<InterfaceThroughput> interfaces = new ArrayList<>(); | ||||||
|  |     private List<BridgeThroughput> bridges = new ArrayList<>(); | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								corefx/src/main/java/com/core/datavis/CoreGraph.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								corefx/src/main/java/com/core/datavis/CoreGraph.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | package com.core.datavis; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class CoreGraph { | ||||||
|  |     private String title; | ||||||
|  |     private CoreGraphAxis xAxis; | ||||||
|  |     private CoreGraphAxis yAxis; | ||||||
|  |     private GraphType graphType; | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								corefx/src/main/java/com/core/datavis/CoreGraphAxis.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								corefx/src/main/java/com/core/datavis/CoreGraphAxis.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | package com.core.datavis; | ||||||
|  | 
 | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @AllArgsConstructor | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class CoreGraphAxis { | ||||||
|  |     private String label; | ||||||
|  |     private Double lower; | ||||||
|  |     private Double upper; | ||||||
|  |     private Double tick; | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								corefx/src/main/java/com/core/datavis/CoreGraphData.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								corefx/src/main/java/com/core/datavis/CoreGraphData.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | package com.core.datavis; | ||||||
|  | 
 | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @AllArgsConstructor | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class CoreGraphData { | ||||||
|  |     private String name; | ||||||
|  |     private Double x; | ||||||
|  |     private Double y; | ||||||
|  |     private Double weight; | ||||||
|  | } | ||||||
							
								
								
									
										157
									
								
								corefx/src/main/java/com/core/datavis/CoreGraphWrapper.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								corefx/src/main/java/com/core/datavis/CoreGraphWrapper.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,157 @@ | ||||||
|  | package com.core.datavis; | ||||||
|  | 
 | ||||||
|  | import javafx.scene.chart.*; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.concurrent.atomic.AtomicInteger; | ||||||
|  | 
 | ||||||
|  | public class CoreGraphWrapper { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final GraphType graphType; | ||||||
|  |     private PieChart pieChart; | ||||||
|  |     private final Map<String, PieChart.Data> pieData = new HashMap<>(); | ||||||
|  |     private BarChart<String, Number> barChart; | ||||||
|  |     private final Map<String, XYChart.Data<String, Number>> barMap = new HashMap<>(); | ||||||
|  |     private XYChart<Number, Number> xyChart; | ||||||
|  |     private final XYChart.Series<Number, Number> series = new XYChart.Series<>(); | ||||||
|  |     private final XYChart.Series<String, Number> barSeries = new XYChart.Series<>(); | ||||||
|  |     private AtomicInteger timeValue = new AtomicInteger(0); | ||||||
|  | 
 | ||||||
|  |     public CoreGraphWrapper(CoreGraph coreGraph) { | ||||||
|  |         graphType = coreGraph.getGraphType(); | ||||||
|  |         createChart(coreGraph); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Chart getChart() { | ||||||
|  |         switch (graphType) { | ||||||
|  |             case PIE: | ||||||
|  |                 return pieChart; | ||||||
|  |             case BAR: | ||||||
|  |                 return barChart; | ||||||
|  |             default: | ||||||
|  |                 return xyChart; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void add(CoreGraphData coreGraphData) { | ||||||
|  |         switch (graphType) { | ||||||
|  |             case PIE: | ||||||
|  |             case BAR: | ||||||
|  |                 add(coreGraphData.getName(), coreGraphData.getY()); | ||||||
|  |                 break; | ||||||
|  |             case TIME: | ||||||
|  |                 add(coreGraphData.getY()); | ||||||
|  |                 break; | ||||||
|  |             case BUBBLE: | ||||||
|  |                 add(coreGraphData.getX(), coreGraphData.getY(), coreGraphData.getWeight()); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 add(coreGraphData.getX(), coreGraphData.getY()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void add(String name, double value) { | ||||||
|  |         if (GraphType.PIE == graphType) { | ||||||
|  |             PieChart.Data data = pieData.computeIfAbsent(name, x -> { | ||||||
|  |                 PieChart.Data newData = new PieChart.Data(x, value); | ||||||
|  |                 pieChart.getData().add(newData); | ||||||
|  |                 return newData; | ||||||
|  |             }); | ||||||
|  |             data.setPieValue(value); | ||||||
|  |         } else { | ||||||
|  |             XYChart.Data<String, Number> data = barMap.computeIfAbsent(name, x -> { | ||||||
|  |                 XYChart.Data<String, Number> newData = new XYChart.Data<>(name, value); | ||||||
|  |                 barSeries.getData().add(newData); | ||||||
|  |                 return newData; | ||||||
|  |             }); | ||||||
|  |             data.setYValue(value); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void add(Number y) { | ||||||
|  |         series.getData().add(new XYChart.Data<>(timeValue.getAndIncrement(), y)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void add(Number x, Number y) { | ||||||
|  |         series.getData().add(new XYChart.Data<>(x, y)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void add(Number x, Number y, Number weight) { | ||||||
|  |         series.getData().add(new XYChart.Data<>(x, y, weight)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private NumberAxis getAxis(CoreGraphAxis graphAxis) { | ||||||
|  |         return new NumberAxis(graphAxis.getLabel(), graphAxis.getLower(), | ||||||
|  |                 graphAxis.getUpper(), graphAxis.getTick()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void createChart(CoreGraph coreGraph) { | ||||||
|  |         NumberAxis xAxis; | ||||||
|  |         NumberAxis yAxis; | ||||||
|  | 
 | ||||||
|  |         switch (coreGraph.getGraphType()) { | ||||||
|  |             case AREA: | ||||||
|  |                 xAxis = getAxis(coreGraph.getXAxis()); | ||||||
|  |                 yAxis = getAxis(coreGraph.getYAxis()); | ||||||
|  |                 xyChart = new AreaChart<>(xAxis, yAxis); | ||||||
|  |                 xyChart.setTitle(coreGraph.getTitle()); | ||||||
|  |                 xyChart.setLegendVisible(false); | ||||||
|  |                 xyChart.getData().add(series); | ||||||
|  |                 break; | ||||||
|  |             case TIME: | ||||||
|  |                 xAxis = new NumberAxis(); | ||||||
|  |                 xAxis.setLabel(coreGraph.getXAxis().getLabel()); | ||||||
|  |                 xAxis.setTickUnit(1); | ||||||
|  |                 xAxis.setLowerBound(0); | ||||||
|  |                 yAxis = getAxis(coreGraph.getYAxis()); | ||||||
|  |                 xyChart = new LineChart<>(xAxis, yAxis); | ||||||
|  |                 xyChart.setTitle(coreGraph.getTitle()); | ||||||
|  |                 xyChart.setLegendVisible(false); | ||||||
|  |                 xyChart.getData().add(series); | ||||||
|  |                 break; | ||||||
|  |             case LINE: | ||||||
|  |                 xAxis = getAxis(coreGraph.getXAxis()); | ||||||
|  |                 yAxis = getAxis(coreGraph.getYAxis()); | ||||||
|  |                 xyChart = new LineChart<>(xAxis, yAxis); | ||||||
|  |                 xyChart.setTitle(coreGraph.getTitle()); | ||||||
|  |                 xyChart.setLegendVisible(false); | ||||||
|  |                 xyChart.getData().add(series); | ||||||
|  |                 break; | ||||||
|  |             case BUBBLE: | ||||||
|  |                 xAxis = getAxis(coreGraph.getXAxis()); | ||||||
|  |                 yAxis = getAxis(coreGraph.getYAxis()); | ||||||
|  |                 xyChart = new BubbleChart<>(xAxis, yAxis); | ||||||
|  |                 xyChart.setTitle(coreGraph.getTitle()); | ||||||
|  |                 xyChart.setLegendVisible(false); | ||||||
|  |                 xyChart.getData().add(series); | ||||||
|  |                 break; | ||||||
|  |             case SCATTER: | ||||||
|  |                 xAxis = getAxis(coreGraph.getXAxis()); | ||||||
|  |                 yAxis = getAxis(coreGraph.getYAxis()); | ||||||
|  |                 xyChart = new ScatterChart<>(xAxis, yAxis); | ||||||
|  |                 xyChart.setTitle(coreGraph.getTitle()); | ||||||
|  |                 xyChart.setLegendVisible(false); | ||||||
|  |                 xyChart.getData().add(series); | ||||||
|  |                 break; | ||||||
|  |             case PIE: | ||||||
|  |                 pieChart = new PieChart(); | ||||||
|  |                 pieChart.setTitle(coreGraph.getTitle()); | ||||||
|  |                 break; | ||||||
|  |             case BAR: | ||||||
|  |                 CategoryAxis categoryAxis = new CategoryAxis(); | ||||||
|  |                 categoryAxis.setLabel(coreGraph.getXAxis().getLabel()); | ||||||
|  |                 yAxis = getAxis(coreGraph.getYAxis()); | ||||||
|  |                 barChart = new BarChart<>(categoryAxis, yAxis); | ||||||
|  |                 barChart.setLegendVisible(false); | ||||||
|  |                 barChart.setTitle(coreGraph.getTitle()); | ||||||
|  |                 barChart.getData().add(barSeries); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 throw new IllegalArgumentException(String.format("unknown graph type: %s", | ||||||
|  |                         coreGraph.getGraphType())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								corefx/src/main/java/com/core/datavis/GraphType.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								corefx/src/main/java/com/core/datavis/GraphType.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | package com.core.datavis; | ||||||
|  | 
 | ||||||
|  | public enum GraphType { | ||||||
|  |     PIE, | ||||||
|  |     LINE, | ||||||
|  |     TIME, | ||||||
|  |     AREA, | ||||||
|  |     BAR, | ||||||
|  |     SCATTER, | ||||||
|  |     BUBBLE | ||||||
|  | } | ||||||
|  | @ -0,0 +1,22 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.event.EventHandler; | ||||||
|  | import javafx.scene.control.MenuItem; | ||||||
|  | 
 | ||||||
|  | abstract class AbstractNodeContextMenu extends GraphContextMenu { | ||||||
|  |     final CoreNode coreNode; | ||||||
|  | 
 | ||||||
|  |     AbstractNodeContextMenu(Controller controller, CoreNode coreNode) { | ||||||
|  |         super(controller); | ||||||
|  |         this.coreNode = coreNode; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void addMenuItem(String text, EventHandler<ActionEvent> handler) { | ||||||
|  |         MenuItem menuItem = new MenuItem(text); | ||||||
|  |         menuItem.setOnAction(handler); | ||||||
|  |         getItems().add(menuItem); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								corefx/src/main/java/com/core/graph/BackgroundPaintable.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								corefx/src/main/java/com/core/graph/BackgroundPaintable.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,51 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import edu.uci.ics.jung.visualization.Layer; | ||||||
|  | import edu.uci.ics.jung.visualization.VisualizationViewer; | ||||||
|  | 
 | ||||||
|  | import javax.imageio.ImageIO; | ||||||
|  | import javax.swing.*; | ||||||
|  | import java.awt.*; | ||||||
|  | import java.awt.geom.AffineTransform; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.nio.file.Paths; | ||||||
|  | 
 | ||||||
|  | public class BackgroundPaintable<V, E> implements VisualizationViewer.Paintable { | ||||||
|  |     private final ImageIcon imageIcon; | ||||||
|  |     private final VisualizationViewer<V, E> vv; | ||||||
|  |     private final String imagePath; | ||||||
|  | 
 | ||||||
|  |     public BackgroundPaintable(String imagePath, VisualizationViewer<V, E> vv) throws IOException { | ||||||
|  |         this.imagePath = imagePath; | ||||||
|  |         Image image = ImageIO.read(Paths.get(imagePath).toFile()); | ||||||
|  |         imageIcon = new ImageIcon(image); | ||||||
|  |         this.vv = vv; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getImage() { | ||||||
|  |         return imagePath; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void paint(Graphics g) { | ||||||
|  |         Graphics2D g2d = (Graphics2D) g; | ||||||
|  |         AffineTransform oldXform = g2d.getTransform(); | ||||||
|  |         AffineTransform lat = | ||||||
|  |                 vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).getTransform(); | ||||||
|  |         AffineTransform vat = | ||||||
|  |                 vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW).getTransform(); | ||||||
|  |         AffineTransform at = new AffineTransform(); | ||||||
|  |         at.concatenate(g2d.getTransform()); | ||||||
|  |         at.concatenate(vat); | ||||||
|  |         at.concatenate(lat); | ||||||
|  |         g2d.setTransform(at); | ||||||
|  |         g.drawImage(imageIcon.getImage(), 0, 0, | ||||||
|  |                 imageIcon.getIconWidth(), imageIcon.getIconHeight(), vv); | ||||||
|  |         g2d.setTransform(oldXform); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean useTransform() { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								corefx/src/main/java/com/core/graph/CoreAddresses.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								corefx/src/main/java/com/core/graph/CoreAddresses.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.data.CoreInterface; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.Collection; | ||||||
|  | 
 | ||||||
|  | public class CoreAddresses { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     public static final int IP4_MASK = 24; | ||||||
|  |     public static final int IP4_INDEX = (IP4_MASK / 8) - 1; | ||||||
|  | 
 | ||||||
|  |     private String ip4Base; | ||||||
|  | 
 | ||||||
|  |     public CoreAddresses(String ip4Base) { | ||||||
|  |         this.ip4Base = ip4Base; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getSubnet(Collection<CoreInterface> nodeOneInterfaces, Collection<CoreInterface> nodeTwoInterfaces) { | ||||||
|  |         int subOne = getMaxSubnet(nodeOneInterfaces); | ||||||
|  |         int subTwo = getMaxSubnet(nodeTwoInterfaces); | ||||||
|  |         logger.info("next subnet: {} - {}", subOne, subTwo); | ||||||
|  |         return Math.max(subOne, subTwo) + 1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private int getMaxSubnet(Collection<CoreInterface> coreInterfaces) { | ||||||
|  |         int sub = 0; | ||||||
|  |         for (CoreInterface coreInterface : coreInterfaces) { | ||||||
|  |             String[] values = coreInterface.getIp4().split("\\."); | ||||||
|  |             int currentSub = Integer.parseInt(values[IP4_INDEX]); | ||||||
|  |             logger.info("checking {} value {}", coreInterface.getIp4(), currentSub); | ||||||
|  |             sub = Math.max(currentSub, sub); | ||||||
|  |         } | ||||||
|  |         return sub; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getIp4Address(int sub, int id) { | ||||||
|  |         return String.format("%s.%s.%s", ip4Base, sub, id); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,57 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import edu.uci.ics.jung.visualization.RenderContext; | ||||||
|  | import edu.uci.ics.jung.visualization.VisualizationViewer; | ||||||
|  | import edu.uci.ics.jung.visualization.annotations.AnnotatingGraphMousePlugin; | ||||||
|  | import edu.uci.ics.jung.visualization.annotations.Annotation; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import javax.swing.*; | ||||||
|  | import java.awt.*; | ||||||
|  | import java.awt.event.MouseEvent; | ||||||
|  | import java.awt.geom.Point2D; | ||||||
|  | import java.awt.geom.RectangularShape; | ||||||
|  | 
 | ||||||
|  | public class CoreAnnotatingGraphMousePlugin<V, E> extends AnnotatingGraphMousePlugin<V, E> { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final Controller controller; | ||||||
|  |     private JFrame frame = new JFrame(); | ||||||
|  | 
 | ||||||
|  |     public CoreAnnotatingGraphMousePlugin(Controller controller, RenderContext<V, E> renderContext) { | ||||||
|  |         super(renderContext); | ||||||
|  |         this.controller = controller; | ||||||
|  |         frame.setVisible(false); | ||||||
|  |         frame.setAlwaysOnTop(true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void mouseReleased(MouseEvent e) { | ||||||
|  |         VisualizationViewer<V, E> vv = (VisualizationViewer) e.getSource(); | ||||||
|  |         if (e.isPopupTrigger()) { | ||||||
|  |             frame.setLocationRelativeTo(vv); | ||||||
|  |             String annotationString = JOptionPane.showInputDialog(frame, "Annotation:", | ||||||
|  |                     "Annotation Label", JOptionPane.PLAIN_MESSAGE); | ||||||
|  |             if (annotationString != null && annotationString.length() > 0) { | ||||||
|  |                 Point2D p = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(this.down); | ||||||
|  |                 Annotation<String> annotation = new Annotation(annotationString, this.layer, | ||||||
|  |                         this.annotationColor, this.fill, p); | ||||||
|  |                 this.annotationManager.add(this.layer, annotation); | ||||||
|  |             } | ||||||
|  |         } else if (e.getModifiers() == this.modifiers && this.down != null) { | ||||||
|  |             Point2D out = e.getPoint(); | ||||||
|  |             RectangularShape arect = (RectangularShape) this.rectangularShape.clone(); | ||||||
|  |             arect.setFrameFromDiagonal(this.down, out); | ||||||
|  |             Shape s = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(arect); | ||||||
|  |             Annotation<Shape> annotation = new Annotation(s, this.layer, this.annotationColor, this.fill, out); | ||||||
|  |             this.annotationManager.add(this.layer, annotation); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.down = null; | ||||||
|  |         vv.removePostRenderPaintable(this.lensPaintable); | ||||||
|  |         vv.repaint(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -0,0 +1,17 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.google.common.base.Supplier; | ||||||
|  | import edu.uci.ics.jung.visualization.RenderContext; | ||||||
|  | import edu.uci.ics.jung.visualization.control.EditingModalGraphMouse; | ||||||
|  | 
 | ||||||
|  | public class CoreEditingModalGraphMouse<V, E> extends EditingModalGraphMouse<V, E> { | ||||||
|  |     public CoreEditingModalGraphMouse(Controller controller, NetworkGraph networkGraph, | ||||||
|  |                                       RenderContext<V, E> rc, Supplier<V> vertexFactory, Supplier<E> edgeFactory) { | ||||||
|  |         super(rc, vertexFactory, edgeFactory); | ||||||
|  |         remove(annotatingPlugin); | ||||||
|  |         remove(popupEditingPlugin); | ||||||
|  |         annotatingPlugin = new CoreAnnotatingGraphMousePlugin<>(controller, rc); | ||||||
|  |         popupEditingPlugin = new CorePopupGraphMousePlugin<>(controller, networkGraph, vertexFactory, edgeFactory); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								corefx/src/main/java/com/core/graph/CoreObservableGraph.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								corefx/src/main/java/com/core/graph/CoreObservableGraph.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import edu.uci.ics.jung.graph.Graph; | ||||||
|  | import edu.uci.ics.jung.graph.ObservableGraph; | ||||||
|  | import edu.uci.ics.jung.graph.util.EdgeType; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | public class CoreObservableGraph<V, E> extends ObservableGraph<V, E> { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  | 
 | ||||||
|  |     public CoreObservableGraph(Graph<V, E> graph) { | ||||||
|  |         super(graph); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean addEdge(E e, V v1, V v2, EdgeType edgeType) { | ||||||
|  |         if (v1 == null || v2 == null) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return super.addEdge(e, v1, v2, edgeType); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public boolean addEdge(E e, V v1, V v2) { | ||||||
|  |         if (v1 == null || v2 == null) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return super.addEdge(e, v1, v2); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,78 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreLink; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.data.NodeType; | ||||||
|  | import com.google.common.base.Supplier; | ||||||
|  | import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor; | ||||||
|  | import edu.uci.ics.jung.algorithms.layout.Layout; | ||||||
|  | import edu.uci.ics.jung.visualization.control.EditingPopupGraphMousePlugin; | ||||||
|  | import javafx.application.Platform; | ||||||
|  | import javafx.scene.control.ContextMenu; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.awt.event.MouseEvent; | ||||||
|  | import java.awt.geom.Point2D; | ||||||
|  | 
 | ||||||
|  | public class CorePopupGraphMousePlugin<V, E> extends EditingPopupGraphMousePlugin<V, E> { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final Controller controller; | ||||||
|  |     private final NetworkGraph networkGraph; | ||||||
|  |     private final Layout<CoreNode, CoreLink> graphLayout; | ||||||
|  |     private final GraphElementAccessor<CoreNode, CoreLink> pickSupport; | ||||||
|  | 
 | ||||||
|  |     public CorePopupGraphMousePlugin(Controller controller, NetworkGraph networkGraph, | ||||||
|  |                                      Supplier<V> vertexFactory, Supplier<E> edgeFactory) { | ||||||
|  |         super(vertexFactory, edgeFactory); | ||||||
|  |         this.controller = controller; | ||||||
|  |         this.networkGraph = networkGraph; | ||||||
|  |         graphLayout = this.networkGraph.getGraphLayout(); | ||||||
|  |         pickSupport = this.networkGraph.getGraphViewer().getPickSupport(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected void handlePopup(MouseEvent e) { | ||||||
|  |         logger.info("showing popup!"); | ||||||
|  |         final Point2D p = e.getPoint(); | ||||||
|  | 
 | ||||||
|  |         final CoreNode node = pickSupport.getVertex(graphLayout, p.getX(), p.getY()); | ||||||
|  |         final CoreLink link = pickSupport.getEdge(graphLayout, p.getX(), p.getY()); | ||||||
|  | 
 | ||||||
|  |         final ContextMenu contextMenu; | ||||||
|  |         if (node != null) { | ||||||
|  |             contextMenu = handleNodeContext(node); | ||||||
|  |         } else if (link != null) { | ||||||
|  |             contextMenu = new LinkContextMenu(controller, link); | ||||||
|  |         } else { | ||||||
|  |             contextMenu = new ContextMenu(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!contextMenu.getItems().isEmpty()) { | ||||||
|  |             logger.info("showing context menu"); | ||||||
|  |             Platform.runLater(() -> contextMenu.show(controller.getWindow(), | ||||||
|  |                     e.getXOnScreen(), e.getYOnScreen())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private ContextMenu handleNodeContext(final CoreNode node) { | ||||||
|  |         ContextMenu contextMenu = new ContextMenu(); | ||||||
|  |         switch (node.getType()) { | ||||||
|  |             case NodeType.DEFAULT: | ||||||
|  |                 contextMenu = new NodeContextMenu(controller, node); | ||||||
|  |                 break; | ||||||
|  |             case NodeType.WLAN: | ||||||
|  |                 contextMenu = new WlanContextMenu(controller, node); | ||||||
|  |                 break; | ||||||
|  |             case NodeType.EMANE: | ||||||
|  |                 contextMenu = new EmaneContextMenu(controller, node); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 logger.warn("no context menu for node: {}", node.getType()); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return contextMenu; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,43 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import edu.uci.ics.jung.visualization.renderers.DefaultVertexLabelRenderer; | ||||||
|  | 
 | ||||||
|  | import javax.swing.*; | ||||||
|  | import javax.swing.border.EmptyBorder; | ||||||
|  | import java.awt.*; | ||||||
|  | 
 | ||||||
|  | public class CoreVertexLabelRenderer extends DefaultVertexLabelRenderer { | ||||||
|  |     private Color foregroundColor = Color.WHITE; | ||||||
|  |     private Color backgroundColor = Color.BLACK; | ||||||
|  | 
 | ||||||
|  |     CoreVertexLabelRenderer() { | ||||||
|  |         super(Color.YELLOW); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setColors(Color foregroundColor, Color backgroundColor) { | ||||||
|  |         this.foregroundColor = foregroundColor; | ||||||
|  |         this.backgroundColor = backgroundColor; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public <V> Component getVertexLabelRendererComponent(JComponent vv, Object value, Font font, boolean isSelected, V vertex) { | ||||||
|  |         super.setForeground(foregroundColor); | ||||||
|  |         if (isSelected) { | ||||||
|  |             this.setForeground(this.pickedVertexLabelColor); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         super.setBackground(backgroundColor); | ||||||
|  |         if (font != null) { | ||||||
|  |             this.setFont(font); | ||||||
|  |         } else { | ||||||
|  |             this.setFont(vv.getFont()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.setIcon(null); | ||||||
|  |         EmptyBorder padding = new EmptyBorder(5, 5, 5, 5); | ||||||
|  |         this.setBorder(padding); | ||||||
|  |         this.setValue(value); | ||||||
|  |         setFont(getFont().deriveFont(Font.BOLD)); | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								corefx/src/main/java/com/core/graph/EmaneContextMenu.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								corefx/src/main/java/com/core/graph/EmaneContextMenu.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.ui.dialogs.MobilityPlayerDialog; | ||||||
|  | 
 | ||||||
|  | class EmaneContextMenu extends AbstractNodeContextMenu { | ||||||
|  |     EmaneContextMenu(Controller controller, CoreNode coreNode) { | ||||||
|  |         super(controller, coreNode); | ||||||
|  |         setup(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setup() { | ||||||
|  |         addMenuItem("EMANE Settings", event -> controller.getNodeEmaneDialog().showDialog(coreNode)); | ||||||
|  |         if (controller.getCoreClient().isRunning()) { | ||||||
|  |             MobilityPlayerDialog mobilityPlayerDialog = controller.getMobilityPlayerDialogs().get(coreNode.getId()); | ||||||
|  |             if (mobilityPlayerDialog != null && !mobilityPlayerDialog.getStage().isShowing()) { | ||||||
|  |                 addMenuItem("Mobility Script", event -> mobilityPlayerDialog.show()); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             addMenuItem("Mobility", event -> controller.getMobilityDialog().showDialog(coreNode)); | ||||||
|  |             addMenuItem("Link MDRs", event -> controller.getNetworkGraph().linkMdrs(coreNode)); | ||||||
|  |             addMenuItem("Delete Node", event -> controller.deleteNode(coreNode)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								corefx/src/main/java/com/core/graph/GraphContextMenu.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								corefx/src/main/java/com/core/graph/GraphContextMenu.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.event.EventHandler; | ||||||
|  | import javafx.scene.control.ContextMenu; | ||||||
|  | import javafx.scene.control.MenuItem; | ||||||
|  | 
 | ||||||
|  | abstract class GraphContextMenu extends ContextMenu { | ||||||
|  |     final Controller controller; | ||||||
|  | 
 | ||||||
|  |     GraphContextMenu(Controller controller) { | ||||||
|  |         super(); | ||||||
|  |         this.controller = controller; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void addMenuItem(String text, EventHandler<ActionEvent> handler) { | ||||||
|  |         MenuItem menuItem = new MenuItem(text); | ||||||
|  |         menuItem.setOnAction(handler); | ||||||
|  |         getItems().add(menuItem); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										21
									
								
								corefx/src/main/java/com/core/graph/LinkContextMenu.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								corefx/src/main/java/com/core/graph/LinkContextMenu.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreLink; | ||||||
|  | 
 | ||||||
|  | class LinkContextMenu extends GraphContextMenu { | ||||||
|  |     final CoreLink coreLink; | ||||||
|  | 
 | ||||||
|  |     LinkContextMenu(Controller controller, CoreLink coreLink) { | ||||||
|  |         super(controller); | ||||||
|  |         this.coreLink = coreLink; | ||||||
|  |         setup(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setup() { | ||||||
|  |         if (!controller.getCoreClient().isRunning()) { | ||||||
|  |             addMenuItem("Delete Link", | ||||||
|  |                     event -> controller.getNetworkGraph().removeLink(coreLink)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										492
									
								
								corefx/src/main/java/com/core/graph/NetworkGraph.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										492
									
								
								corefx/src/main/java/com/core/graph/NetworkGraph.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,492 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.*; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.core.ui.dialogs.TerminalDialog; | ||||||
|  | import com.core.utils.Configuration; | ||||||
|  | import com.core.utils.IconUtils; | ||||||
|  | import com.google.common.base.Supplier; | ||||||
|  | import edu.uci.ics.jung.algorithms.layout.StaticLayout; | ||||||
|  | import edu.uci.ics.jung.graph.ObservableGraph; | ||||||
|  | import edu.uci.ics.jung.graph.event.GraphEvent; | ||||||
|  | import edu.uci.ics.jung.graph.event.GraphEventListener; | ||||||
|  | import edu.uci.ics.jung.graph.util.Pair; | ||||||
|  | import edu.uci.ics.jung.visualization.RenderContext; | ||||||
|  | import edu.uci.ics.jung.visualization.VisualizationViewer; | ||||||
|  | import edu.uci.ics.jung.visualization.annotations.AnnotationControls; | ||||||
|  | import edu.uci.ics.jung.visualization.control.EditingModalGraphMouse; | ||||||
|  | import edu.uci.ics.jung.visualization.control.GraphMouseListener; | ||||||
|  | import edu.uci.ics.jung.visualization.control.ModalGraphMouse; | ||||||
|  | import edu.uci.ics.jung.visualization.decorators.EdgeShape; | ||||||
|  | import edu.uci.ics.jung.visualization.renderers.Renderer; | ||||||
|  | import javafx.application.Platform; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.commons.net.util.SubnetUtils; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import javax.swing.*; | ||||||
|  | import java.awt.*; | ||||||
|  | import java.awt.event.MouseEvent; | ||||||
|  | import java.awt.geom.Ellipse2D; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.*; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.concurrent.ConcurrentHashMap; | ||||||
|  | import java.util.concurrent.TimeUnit; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class NetworkGraph { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final int EDGE_LABEL_OFFSET = -5; | ||||||
|  |     private static final int EDGE_WIDTH = 5; | ||||||
|  |     private Controller controller; | ||||||
|  |     private ObservableGraph<CoreNode, CoreLink> graph; | ||||||
|  |     private StaticLayout<CoreNode, CoreLink> graphLayout; | ||||||
|  |     private VisualizationViewer<CoreNode, CoreLink> graphViewer; | ||||||
|  |     private EditingModalGraphMouse<CoreNode, CoreLink> graphMouse; | ||||||
|  |     private AnnotationControls<CoreNode, CoreLink> annotationControls; | ||||||
|  | 
 | ||||||
|  |     private SubnetUtils subnetUtils = new SubnetUtils("10.0.0.0/24"); | ||||||
|  |     private CoreAddresses coreAddresses = new CoreAddresses("10.0"); | ||||||
|  |     private NodeType nodeType; | ||||||
|  |     private Map<Integer, CoreNode> nodeMap = new ConcurrentHashMap<>(); | ||||||
|  |     private int vertexId = 1; | ||||||
|  |     private int linkId = 1; | ||||||
|  |     private Supplier<CoreNode> vertexFactory = () -> new CoreNode(vertexId++); | ||||||
|  |     private Supplier<CoreLink> linkFactory = () -> new CoreLink(linkId++); | ||||||
|  |     private CorePopupGraphMousePlugin customPopupPlugin; | ||||||
|  |     private CoreAnnotatingGraphMousePlugin<CoreNode, CoreLink> customAnnotatingPlugin; | ||||||
|  |     private BackgroundPaintable<CoreNode, CoreLink> backgroundPaintable; | ||||||
|  |     private CoreVertexLabelRenderer nodeLabelRenderer = new CoreVertexLabelRenderer(); | ||||||
|  | 
 | ||||||
|  |     // display options | ||||||
|  |     private boolean showThroughput = false; | ||||||
|  |     private Double throughputLimit = null; | ||||||
|  |     private int throughputWidth = 10; | ||||||
|  | 
 | ||||||
|  |     public NetworkGraph(Controller controller) { | ||||||
|  |         this.controller = controller; | ||||||
|  |         graph = new CoreObservableGraph<>(new UndirectedSimpleGraph<>()); | ||||||
|  |         graph.addGraphEventListener(graphEventListener); | ||||||
|  |         graphLayout = new StaticLayout<>(graph); | ||||||
|  |         graphViewer = new VisualizationViewer<>(graphLayout); | ||||||
|  |         graphViewer.setBackground(Color.WHITE); | ||||||
|  |         graphViewer.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.S); | ||||||
|  | 
 | ||||||
|  |         RenderContext<CoreNode, CoreLink> renderContext = graphViewer.getRenderContext(); | ||||||
|  | 
 | ||||||
|  |         // node render properties | ||||||
|  |         renderContext.setVertexLabelTransformer(CoreNode::getName); | ||||||
|  |         renderContext.setVertexLabelRenderer(nodeLabelRenderer); | ||||||
|  |         renderContext.setVertexShapeTransformer(node -> { | ||||||
|  |             double offset = -(IconUtils.ICON_SIZE / 2.0); | ||||||
|  |             return new Ellipse2D.Double(offset, offset, IconUtils.ICON_SIZE, IconUtils.ICON_SIZE); | ||||||
|  |         }); | ||||||
|  |         renderContext.setVertexIconTransformer(vertex -> { | ||||||
|  |             long wirelessLinks = wirelessLinkCount(vertex); | ||||||
|  |             vertex.getRadioIcon().setWiressLinks(wirelessLinks); | ||||||
|  |             return vertex.getGraphIcon(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // link render properties | ||||||
|  |         renderContext.setEdgeLabelTransformer(edge -> { | ||||||
|  |             if (!showThroughput || edge == null) { | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |             double kbps = edge.getThroughput() / 1000.0; | ||||||
|  |             return String.format("%.2f kbps", kbps); | ||||||
|  |         }); | ||||||
|  |         renderContext.setLabelOffset(EDGE_LABEL_OFFSET); | ||||||
|  |         renderContext.setEdgeStrokeTransformer(edge -> { | ||||||
|  |             // determine edge width | ||||||
|  |             int width = EDGE_WIDTH; | ||||||
|  |             if (throughputLimit != null && edge.getThroughput() > throughputLimit) { | ||||||
|  |                 width = throughputWidth; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             LinkTypes linkType = LinkTypes.get(edge.getType()); | ||||||
|  |             if (LinkTypes.WIRELESS == linkType) { | ||||||
|  |                 float[] dash = {15.0f}; | ||||||
|  |                 return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND, | ||||||
|  |                         0, dash, 0); | ||||||
|  |             } else { | ||||||
|  |                 return new BasicStroke(width); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         renderContext.setEdgeShapeTransformer(EdgeShape.line(graph)); | ||||||
|  |         renderContext.setEdgeDrawPaintTransformer(edge -> { | ||||||
|  |             LinkTypes linkType = LinkTypes.get(edge.getType()); | ||||||
|  |             if (LinkTypes.WIRELESS == linkType) { | ||||||
|  |                 return Color.BLUE; | ||||||
|  |             } else { | ||||||
|  |                 return Color.BLACK; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         renderContext.setEdgeIncludePredicate(predicate -> predicate.element.isVisible()); | ||||||
|  | 
 | ||||||
|  |         graphViewer.setVertexToolTipTransformer(renderContext.getVertexLabelTransformer()); | ||||||
|  |         graphMouse = new CoreEditingModalGraphMouse<>(controller, this, renderContext, | ||||||
|  |                 vertexFactory, linkFactory); | ||||||
|  |         graphViewer.setGraphMouse(graphMouse); | ||||||
|  | 
 | ||||||
|  |         // mouse events | ||||||
|  |         graphViewer.addGraphMouseListener(new GraphMouseListener<CoreNode>() { | ||||||
|  |             @Override | ||||||
|  |             public void graphClicked(CoreNode node, MouseEvent mouseEvent) { | ||||||
|  |                 // double click | ||||||
|  |                 logger.info("click count: {}, running?: {}", mouseEvent.getClickCount(), | ||||||
|  |                         controller.getCoreClient().isRunning()); | ||||||
|  | 
 | ||||||
|  |                 if (mouseEvent.getClickCount() == 2 && controller.getCoreClient().isRunning()) { | ||||||
|  |                     if (controller.getCoreClient().isLocalConnection()) { | ||||||
|  |                         try { | ||||||
|  |                             String shellCommand = controller.getConfiguration().getShellCommand(); | ||||||
|  |                             String terminalCommand = controller.getCoreClient().getTerminalCommand(node); | ||||||
|  |                             terminalCommand = String.format("%s %s", shellCommand, terminalCommand); | ||||||
|  |                             logger.info("launching node terminal: {}", terminalCommand); | ||||||
|  |                             String[] commands = terminalCommand.split("\\s+"); | ||||||
|  |                             logger.info("launching node terminal: {}", Arrays.toString(commands)); | ||||||
|  |                             Process p = new ProcessBuilder(commands).start(); | ||||||
|  |                             try { | ||||||
|  |                                 if (!p.waitFor(5, TimeUnit.SECONDS)) { | ||||||
|  |                                     Toast.error("Node terminal command failed"); | ||||||
|  |                                 } | ||||||
|  |                             } catch (InterruptedException ex) { | ||||||
|  |                                 logger.error("error waiting for terminal to start", ex); | ||||||
|  |                             } | ||||||
|  |                         } catch (IOException ex) { | ||||||
|  |                             logger.error("error launching terminal", ex); | ||||||
|  |                             Toast.error("Node terminal failed to start"); | ||||||
|  |                         } | ||||||
|  |                     } else { | ||||||
|  |                         Platform.runLater(() -> { | ||||||
|  |                             TerminalDialog terminalDialog = new TerminalDialog(controller); | ||||||
|  |                             terminalDialog.setOwner(controller.getWindow()); | ||||||
|  |                             terminalDialog.showDialog(node); | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             @Override | ||||||
|  |             public void graphPressed(CoreNode node, MouseEvent mouseEvent) { | ||||||
|  |                 logger.debug("graph pressed: {} - {}", node, mouseEvent); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             @Override | ||||||
|  |             public void graphReleased(CoreNode node, MouseEvent mouseEvent) { | ||||||
|  |                 if (SwingUtilities.isLeftMouseButton(mouseEvent)) { | ||||||
|  |                     Double newX = graphLayout.getX(node); | ||||||
|  |                     Double newY = graphLayout.getY(node); | ||||||
|  |                     Double oldX = node.getPosition().getX(); | ||||||
|  |                     Double oldY = node.getPosition().getY(); | ||||||
|  |                     if (newX.equals(oldX) && newY.equals(oldY)) { | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  |                     logger.debug("graph moved node({}): {},{}", node.getName(), newX, newY); | ||||||
|  |                     node.getPosition().setX(newX); | ||||||
|  |                     node.getPosition().setY(newY); | ||||||
|  | 
 | ||||||
|  |                     // upate node when session is active | ||||||
|  |                     if (controller.getCoreClient().isRunning()) { | ||||||
|  |                         try { | ||||||
|  |                             controller.getCoreClient().editNode(node); | ||||||
|  |                         } catch (IOException ex) { | ||||||
|  |                             Toast.error("failed to update node location"); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Color convertJfxColor(String hexValue) { | ||||||
|  |         javafx.scene.paint.Color color = javafx.scene.paint.Color.web(hexValue); | ||||||
|  |         return new Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void updatePreferences(Configuration configuration) { | ||||||
|  |         Color nodeLabelColor = convertJfxColor(configuration.getNodeLabelColor()); | ||||||
|  |         Color nodeLabelBackgroundColor = convertJfxColor(configuration.getNodeLabelBackgroundColor()); | ||||||
|  |         nodeLabelRenderer.setColors(nodeLabelColor, nodeLabelBackgroundColor); | ||||||
|  |         throughputLimit = configuration.getThroughputLimit(); | ||||||
|  |         if (configuration.getThroughputWidth() != null) { | ||||||
|  |             throughputWidth = configuration.getThroughputWidth(); | ||||||
|  |         } | ||||||
|  |         graphViewer.repaint(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setBackground(String imagePath) { | ||||||
|  |         try { | ||||||
|  |             backgroundPaintable = new BackgroundPaintable<>(imagePath, graphViewer); | ||||||
|  |             graphViewer.addPreRenderPaintable(backgroundPaintable); | ||||||
|  |             graphViewer.repaint(); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error setting background", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void removeBackground() { | ||||||
|  |         if (backgroundPaintable != null) { | ||||||
|  |             graphViewer.removePreRenderPaintable(backgroundPaintable); | ||||||
|  |             graphViewer.repaint(); | ||||||
|  |             backgroundPaintable = null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setMode(ModalGraphMouse.Mode mode) { | ||||||
|  |         graphMouse.setMode(mode); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void reset() { | ||||||
|  |         logger.info("network graph reset"); | ||||||
|  |         vertexId = 1; | ||||||
|  |         linkId = 1; | ||||||
|  |         for (CoreNode node : nodeMap.values()) { | ||||||
|  |             graph.removeVertex(node); | ||||||
|  |         } | ||||||
|  |         nodeMap.clear(); | ||||||
|  |         graphViewer.repaint(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void updatePositions() { | ||||||
|  |         for (CoreNode node : graph.getVertices()) { | ||||||
|  |             Double x = graphLayout.getX(node); | ||||||
|  |             Double y = graphLayout.getY(node); | ||||||
|  |             node.getPosition().setX(x); | ||||||
|  |             node.getPosition().setY(y); | ||||||
|  |             logger.debug("updating node position node({}): {},{}", node, x, y); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public CoreNode getVertex(int id) { | ||||||
|  |         return nodeMap.get(id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private GraphEventListener<CoreNode, CoreLink> graphEventListener = graphEvent -> { | ||||||
|  |         logger.info("graph event: {}", graphEvent.getType()); | ||||||
|  |         switch (graphEvent.getType()) { | ||||||
|  |             case EDGE_ADDED: | ||||||
|  |                 handleEdgeAdded((GraphEvent.Edge<CoreNode, CoreLink>) graphEvent); | ||||||
|  |                 break; | ||||||
|  |             case EDGE_REMOVED: | ||||||
|  |                 handleEdgeRemoved((GraphEvent.Edge<CoreNode, CoreLink>) graphEvent); | ||||||
|  |                 break; | ||||||
|  |             case VERTEX_ADDED: | ||||||
|  |                 handleVertexAdded((GraphEvent.Vertex<CoreNode, CoreLink>) graphEvent); | ||||||
|  |                 break; | ||||||
|  |             case VERTEX_REMOVED: | ||||||
|  |                 handleVertexRemoved((GraphEvent.Vertex<CoreNode, CoreLink>) graphEvent); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     private void handleEdgeAdded(GraphEvent.Edge<CoreNode, CoreLink> edgeEvent) { | ||||||
|  |         CoreLink link = edgeEvent.getEdge(); | ||||||
|  |         if (!link.isLoaded()) { | ||||||
|  |             Pair<CoreNode> endpoints = graph.getEndpoints(link); | ||||||
|  | 
 | ||||||
|  |             CoreNode nodeOne = endpoints.getFirst(); | ||||||
|  |             CoreNode nodeTwo = endpoints.getSecond(); | ||||||
|  | 
 | ||||||
|  |             // create interfaces for nodes | ||||||
|  |             int sub = coreAddresses.getSubnet( | ||||||
|  |                     getInterfaces(nodeOne), | ||||||
|  |                     getInterfaces(nodeTwo) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|  |             link.setNodeOne(nodeOne.getId()); | ||||||
|  |             if (isNode(nodeOne)) { | ||||||
|  |                 int interfaceOneId = nextInterfaceId(nodeOne); | ||||||
|  |                 CoreInterface interfaceOne = createInterface(nodeOne, sub, interfaceOneId); | ||||||
|  |                 link.setInterfaceOne(interfaceOne); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             link.setNodeTwo(nodeTwo.getId()); | ||||||
|  |             if (isNode(nodeTwo)) { | ||||||
|  |                 int interfaceTwoId = nextInterfaceId(nodeTwo); | ||||||
|  |                 CoreInterface interfaceTwo = createInterface(nodeTwo, sub, interfaceTwoId); | ||||||
|  |                 link.setInterfaceTwo(interfaceTwo); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             boolean isVisible = !checkForWirelessNode(nodeOne, nodeTwo); | ||||||
|  |             link.setVisible(isVisible); | ||||||
|  | 
 | ||||||
|  |             logger.info("adding user created edge: {}", link); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<CoreInterface> getInterfaces(CoreNode node) { | ||||||
|  |         return graph.getIncidentEdges(node).stream() | ||||||
|  |                 .map(link -> { | ||||||
|  |                     if (node.getId().equals(link.getNodeOne())) { | ||||||
|  |                         return link.getInterfaceOne(); | ||||||
|  |                     } else { | ||||||
|  |                         return link.getInterfaceTwo(); | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |                 .filter(Objects::nonNull) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private int nextInterfaceId(CoreNode node) { | ||||||
|  |         Set<Integer> interfaceIds = graph.getIncidentEdges(node).stream() | ||||||
|  |                 .map(link -> { | ||||||
|  |                     if (node.getId().equals(link.getNodeOne())) { | ||||||
|  |                         return link.getInterfaceOne(); | ||||||
|  |                     } else { | ||||||
|  |                         return link.getInterfaceTwo(); | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |                 .filter(Objects::nonNull) | ||||||
|  |                 .map(CoreInterface::getId) | ||||||
|  |                 .collect(Collectors.toSet()); | ||||||
|  | 
 | ||||||
|  |         int i = 0; | ||||||
|  |         while (true) { | ||||||
|  |             if (!interfaceIds.contains(i)) { | ||||||
|  |                 return i; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             i += 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean isNode(CoreNode node) { | ||||||
|  |         return node.getType() == NodeType.DEFAULT; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private CoreInterface createInterface(CoreNode node, int sub, int interfaceId) { | ||||||
|  |         CoreInterface coreInterface = new CoreInterface(); | ||||||
|  |         coreInterface.setId(interfaceId); | ||||||
|  |         coreInterface.setName(String.format("eth%s", interfaceId)); | ||||||
|  |         String nodeOneIp4 = coreAddresses.getIp4Address(sub, node.getId()); | ||||||
|  |         coreInterface.setIp4(nodeOneIp4); | ||||||
|  |         coreInterface.setIp4Mask(CoreAddresses.IP4_MASK); | ||||||
|  |         return coreInterface; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void handleEdgeRemoved(GraphEvent.Edge<CoreNode, CoreLink> edgeEvent) { | ||||||
|  |         CoreLink link = edgeEvent.getEdge(); | ||||||
|  |         logger.info("removed edge: {}", link); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void handleVertexAdded(GraphEvent.Vertex<CoreNode, CoreLink> vertexEvent) { | ||||||
|  |         CoreNode node = vertexEvent.getVertex(); | ||||||
|  |         if (!node.isLoaded()) { | ||||||
|  |             node.setNodeType(nodeType); | ||||||
|  |             if (node.getType() == NodeType.EMANE) { | ||||||
|  |                 String emaneModel = controller.getNodeEmaneDialog().getModels().get(0); | ||||||
|  |                 node.setEmane(emaneModel); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             logger.info("adding user created node: {}", node); | ||||||
|  |             nodeMap.put(node.getId(), node); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void handleVertexRemoved(GraphEvent.Vertex<CoreNode, CoreLink> vertexEvent) { | ||||||
|  |         CoreNode node = vertexEvent.getVertex(); | ||||||
|  |         logger.info("removed vertex: {}", node); | ||||||
|  |         nodeMap.remove(node.getId()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void addNode(CoreNode node) { | ||||||
|  |         vertexId = Math.max(node.getId() + 1, node.getId()); | ||||||
|  |         double x = Math.abs(node.getPosition().getX()); | ||||||
|  |         double y = Math.abs(node.getPosition().getY()); | ||||||
|  |         logger.info("adding session node: {}", node); | ||||||
|  |         graph.addVertex(node); | ||||||
|  |         graphLayout.setLocation(node, x, y); | ||||||
|  |         nodeMap.put(node.getId(), node); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNodeLocation(CoreNode nodeData) { | ||||||
|  |         // update actual graph node | ||||||
|  |         CoreNode node = nodeMap.get(nodeData.getId()); | ||||||
|  |         node.getPosition().setX(nodeData.getPosition().getX()); | ||||||
|  |         node.getPosition().setY(nodeData.getPosition().getY()); | ||||||
|  | 
 | ||||||
|  |         // set graph node location | ||||||
|  |         double x = Math.abs(node.getPosition().getX()); | ||||||
|  |         double y = Math.abs(node.getPosition().getY()); | ||||||
|  |         graphLayout.setLocation(node, x, y); | ||||||
|  |         graphViewer.repaint(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void removeNode(CoreNode node) { | ||||||
|  |         try { | ||||||
|  |             controller.getCoreClient().deleteNode(node); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error deleting node"); | ||||||
|  |             Toast.error(String.format("Error deleting node: %s", node.getName())); | ||||||
|  |         } | ||||||
|  |         graphViewer.getPickedVertexState().pick(node, false); | ||||||
|  |         graph.removeVertex(node); | ||||||
|  |         graphViewer.repaint(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean isWirelessNode(CoreNode node) { | ||||||
|  |         return node.getType() == NodeType.EMANE || node.getType() == NodeType.WLAN; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean checkForWirelessNode(CoreNode nodeOne, CoreNode nodeTwo) { | ||||||
|  |         boolean result = isWirelessNode(nodeOne); | ||||||
|  |         return result || isWirelessNode(nodeTwo); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private long wirelessLinkCount(CoreNode node) { | ||||||
|  |         return graph.getNeighbors(node).stream() | ||||||
|  |                 .filter(this::isWirelessNode) | ||||||
|  |                 .count(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void addLink(CoreLink link) { | ||||||
|  |         logger.info("adding session link: {}", link); | ||||||
|  |         link.setId(linkId++); | ||||||
|  |         CoreNode nodeOne = nodeMap.get(link.getNodeOne()); | ||||||
|  |         CoreNode nodeTwo = nodeMap.get(link.getNodeTwo()); | ||||||
|  | 
 | ||||||
|  |         boolean isVisible = !checkForWirelessNode(nodeOne, nodeTwo); | ||||||
|  |         link.setVisible(isVisible); | ||||||
|  | 
 | ||||||
|  |         graph.addEdge(link, nodeOne, nodeTwo); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void removeWirelessLink(CoreLink link) { | ||||||
|  |         logger.info("deleting link: {}", link); | ||||||
|  |         CoreNode nodeOne = nodeMap.get(link.getNodeOne()); | ||||||
|  |         CoreNode nodeTwo = nodeMap.get(link.getNodeTwo()); | ||||||
|  | 
 | ||||||
|  |         CoreLink existingLink = graph.findEdge(nodeOne, nodeTwo); | ||||||
|  |         if (existingLink != null) { | ||||||
|  |             graph.removeEdge(existingLink); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void removeLink(CoreLink link) { | ||||||
|  |         graphViewer.getPickedEdgeState().pick(link, false); | ||||||
|  |         graph.removeEdge(link); | ||||||
|  |         graphViewer.repaint(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void linkMdrs(CoreNode node) { | ||||||
|  |         for (CoreNode currentNode : graph.getVertices()) { | ||||||
|  |             if (!"mdr".equals(currentNode.getModel())) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // only links mdrs we have not already linked | ||||||
|  |             Collection<CoreLink> links = graph.findEdgeSet(node, currentNode); | ||||||
|  |             if (links.isEmpty()) { | ||||||
|  |                 CoreLink link = linkFactory.get(); | ||||||
|  |                 graph.addEdge(link, currentNode, node); | ||||||
|  |                 graphViewer.repaint(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										116
									
								
								corefx/src/main/java/com/core/graph/NodeContextMenu.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								corefx/src/main/java/com/core/graph/NodeContextMenu.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,116 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import javafx.scene.control.Menu; | ||||||
|  | import javafx.scene.control.MenuItem; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.Set; | ||||||
|  | 
 | ||||||
|  | class NodeContextMenu extends AbstractNodeContextMenu { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  | 
 | ||||||
|  |     NodeContextMenu(Controller controller, CoreNode coreNode) { | ||||||
|  |         super(controller, coreNode); | ||||||
|  |         setup(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private MenuItem createStartItem(String service) { | ||||||
|  |         MenuItem menuItem = new MenuItem("Start"); | ||||||
|  |         menuItem.setOnAction(event -> { | ||||||
|  |             try { | ||||||
|  |                 boolean result = controller.getCoreClient().startService(coreNode, service); | ||||||
|  |                 if (result) { | ||||||
|  |                     Toast.success("Started " + service); | ||||||
|  |                 } else { | ||||||
|  |                     Toast.error("Failure to start " + service); | ||||||
|  |                 } | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("Error starting " + service, ex); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         return menuItem; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private MenuItem createStopItem(String service) { | ||||||
|  |         MenuItem menuItem = new MenuItem("Stop"); | ||||||
|  |         menuItem.setOnAction(event -> { | ||||||
|  |             try { | ||||||
|  |                 boolean result = controller.getCoreClient().stopService(coreNode, service); | ||||||
|  |                 if (result) { | ||||||
|  |                     Toast.success("Stopped " + service); | ||||||
|  |                 } else { | ||||||
|  |                     Toast.error("Failure to stop " + service); | ||||||
|  |                 } | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("Error stopping " + service, ex); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         return menuItem; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private MenuItem createRestartItem(String service) { | ||||||
|  |         MenuItem menuItem = new MenuItem("Restart"); | ||||||
|  |         menuItem.setOnAction(event -> { | ||||||
|  |             try { | ||||||
|  |                 boolean result = controller.getCoreClient().restartService(coreNode, service); | ||||||
|  |                 if (result) { | ||||||
|  |                     Toast.success("Restarted " + service); | ||||||
|  |                 } else { | ||||||
|  |                     Toast.error("Failure to restart " + service); | ||||||
|  |                 } | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("Error restarting " + service, ex); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         return menuItem; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private MenuItem createValidateItem(String service) { | ||||||
|  |         MenuItem menuItem = new MenuItem("Validate"); | ||||||
|  |         menuItem.setOnAction(event -> { | ||||||
|  |             try { | ||||||
|  |                 boolean result = controller.getCoreClient().validateService(coreNode, service); | ||||||
|  |                 if (result) { | ||||||
|  |                     Toast.success("Validated " + service); | ||||||
|  |                 } else { | ||||||
|  |                     Toast.error("Validation failed for " + service); | ||||||
|  |                 } | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("Error validating " + service, ex); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         return menuItem; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setup() { | ||||||
|  |         if (controller.getCoreClient().isRunning()) { | ||||||
|  |             Set<String> services = coreNode.getServices(); | ||||||
|  |             if (services.isEmpty()) { | ||||||
|  |                 services = controller.getDefaultServices().getOrDefault(coreNode.getModel(), Collections.emptySet()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (!services.isEmpty()) { | ||||||
|  |                 Menu menu = new Menu("Manage Services"); | ||||||
|  |                 for (String service : services) { | ||||||
|  |                     Menu serviceMenu = new Menu(service); | ||||||
|  |                     MenuItem startItem = createStartItem(service); | ||||||
|  |                     MenuItem stopItem = createStopItem(service); | ||||||
|  |                     MenuItem restartItem = createRestartItem(service); | ||||||
|  |                     MenuItem validateItem = createValidateItem(service); | ||||||
|  |                     serviceMenu.getItems().addAll(startItem, stopItem, restartItem, validateItem); | ||||||
|  |                     menu.getItems().add(serviceMenu); | ||||||
|  |                 } | ||||||
|  |                 getItems().add(menu); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             addMenuItem("Services", event -> controller.getNodeServicesDialog().showDialog(coreNode)); | ||||||
|  |             addMenuItem("Delete Node", event -> controller.deleteNode(coreNode)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								corefx/src/main/java/com/core/graph/RadioIcon.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								corefx/src/main/java/com/core/graph/RadioIcon.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.utils.IconUtils; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | import javax.swing.*; | ||||||
|  | import java.awt.*; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class RadioIcon implements Icon { | ||||||
|  |     private long wiressLinks = 0; | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public int getIconHeight() { | ||||||
|  |         return IconUtils.ICON_SIZE; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public int getIconWidth() { | ||||||
|  |         return IconUtils.ICON_SIZE; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void paintIcon(Component c, Graphics g, int x, int y) { | ||||||
|  |         g.setColor(Color.black); | ||||||
|  |         for (int i = 0; i < wiressLinks; i++) { | ||||||
|  |             g.fillOval(x, y, 10, 10); | ||||||
|  |             x += 15; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import edu.uci.ics.jung.graph.UndirectedSparseGraph; | ||||||
|  | import edu.uci.ics.jung.graph.util.EdgeType; | ||||||
|  | import edu.uci.ics.jung.graph.util.Pair; | ||||||
|  | 
 | ||||||
|  | public class UndirectedSimpleGraph<V, E> extends UndirectedSparseGraph<V, E> { | ||||||
|  |     @Override | ||||||
|  |     public boolean addEdge(E edge, Pair<? extends V> endpoints, EdgeType edgeType) { | ||||||
|  |         Pair<V> newEndpoints = getValidatedEndpoints(edge, endpoints); | ||||||
|  |         if (newEndpoints == null) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         V first = newEndpoints.getFirst(); | ||||||
|  |         V second = newEndpoints.getSecond(); | ||||||
|  | 
 | ||||||
|  |         if (first.equals(second)) { | ||||||
|  |             return false; | ||||||
|  |         } else { | ||||||
|  |             return super.addEdge(edge, endpoints, edgeType); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								corefx/src/main/java/com/core/graph/WlanContextMenu.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								corefx/src/main/java/com/core/graph/WlanContextMenu.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | package com.core.graph; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.ui.dialogs.MobilityPlayerDialog; | ||||||
|  | 
 | ||||||
|  | class WlanContextMenu extends AbstractNodeContextMenu { | ||||||
|  |     WlanContextMenu(Controller controller, CoreNode coreNode) { | ||||||
|  |         super(controller, coreNode); | ||||||
|  |         setup(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setup() { | ||||||
|  |         addMenuItem("WLAN Settings", event -> controller.getNodeWlanDialog().showDialog(coreNode)); | ||||||
|  |         if (controller.getCoreClient().isRunning()) { | ||||||
|  |             MobilityPlayerDialog mobilityPlayerDialog = controller.getMobilityPlayerDialogs().get(coreNode.getId()); | ||||||
|  |             if (mobilityPlayerDialog != null && !mobilityPlayerDialog.getStage().isShowing()) { | ||||||
|  |                 addMenuItem("Mobility Script", event -> mobilityPlayerDialog.show()); | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             addMenuItem("Mobility", event -> controller.getMobilityDialog().showDialog(coreNode)); | ||||||
|  |             addMenuItem("Link MDRs", event -> controller.getNetworkGraph().linkMdrs(coreNode)); | ||||||
|  |             addMenuItem("Delete Node", event -> controller.deleteNode(coreNode)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										104
									
								
								corefx/src/main/java/com/core/ui/AnnotationToolbar.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								corefx/src/main/java/com/core/ui/AnnotationToolbar.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,104 @@ | ||||||
|  | package com.core.ui; | ||||||
|  | 
 | ||||||
|  | import com.core.graph.NetworkGraph; | ||||||
|  | import com.core.utils.FxmlUtils; | ||||||
|  | import com.jfoenix.controls.JFXColorPicker; | ||||||
|  | import com.jfoenix.controls.JFXComboBox; | ||||||
|  | import com.jfoenix.controls.JFXToggleButton; | ||||||
|  | import edu.uci.ics.jung.visualization.annotations.Annotation; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.layout.GridPane; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.awt.*; | ||||||
|  | import java.awt.geom.Ellipse2D; | ||||||
|  | import java.awt.geom.RectangularShape; | ||||||
|  | import java.awt.geom.RoundRectangle2D; | ||||||
|  | 
 | ||||||
|  | public class AnnotationToolbar extends GridPane { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final String RECTANGLE = "Rectangle"; | ||||||
|  |     private static final String ROUND_RECTANGLE = "RoundRectangle"; | ||||||
|  |     private static final String ELLIPSE = "Ellipse"; | ||||||
|  |     private static final String UPPER_LAYER = "Upper"; | ||||||
|  |     private static final String LOWER_LAYER = "Lower"; | ||||||
|  |     private NetworkGraph graph; | ||||||
|  |     @FXML private JFXComboBox<String> shapeCombo; | ||||||
|  |     @FXML private JFXColorPicker colorPicker; | ||||||
|  |     @FXML private JFXComboBox<String> layerCombo; | ||||||
|  |     @FXML private JFXToggleButton fillToggle; | ||||||
|  | 
 | ||||||
|  |     public AnnotationToolbar(NetworkGraph graph) { | ||||||
|  |         this.graph = graph; | ||||||
|  |         FxmlUtils.loadRootController(this, "/fxml/annotation_toolbar.fxml"); | ||||||
|  | 
 | ||||||
|  |         // setup annotation shape combo | ||||||
|  |         shapeCombo.getItems().addAll(RECTANGLE, ROUND_RECTANGLE, ELLIPSE); | ||||||
|  |         shapeCombo.setOnAction(this::shapeChange); | ||||||
|  |         shapeCombo.getSelectionModel().selectFirst(); | ||||||
|  | 
 | ||||||
|  |         // setup annotation layer combo | ||||||
|  |         layerCombo.getItems().addAll(LOWER_LAYER, UPPER_LAYER); | ||||||
|  |         layerCombo.setOnAction(this::layerChange); | ||||||
|  |         layerCombo.getSelectionModel().selectFirst(); | ||||||
|  | 
 | ||||||
|  |         // setup annotation color picker | ||||||
|  |         colorPicker.setOnAction(this::colorChange); | ||||||
|  |         colorPicker.setValue(javafx.scene.paint.Color.AQUA); | ||||||
|  |         colorPicker.fireEvent(new ActionEvent()); | ||||||
|  | 
 | ||||||
|  |         // setup annotation toggle fill | ||||||
|  |         fillToggle.setOnAction(this::fillChange); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void fillChange(ActionEvent event) { | ||||||
|  |         boolean selected = fillToggle.isSelected(); | ||||||
|  |         graph.getGraphMouse().getAnnotatingPlugin().setFill(selected); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void colorChange(ActionEvent event) { | ||||||
|  |         javafx.scene.paint.Color fxColor = colorPicker.getValue(); | ||||||
|  |         java.awt.Color color = new java.awt.Color( | ||||||
|  |                 (float) fxColor.getRed(), | ||||||
|  |                 (float) fxColor.getGreen(), | ||||||
|  |                 (float) fxColor.getBlue(), | ||||||
|  |                 (float) fxColor.getOpacity() | ||||||
|  |         ); | ||||||
|  |         logger.info("color selected: {}", fxColor); | ||||||
|  |         graph.getGraphMouse().getAnnotatingPlugin().setAnnotationColor(color); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void layerChange(ActionEvent event) { | ||||||
|  |         String selected = layerCombo.getSelectionModel().getSelectedItem(); | ||||||
|  |         logger.info("annotation layer selected: {}", selected); | ||||||
|  |         Annotation.Layer layer; | ||||||
|  |         if (LOWER_LAYER.equals(selected)) { | ||||||
|  |             layer = Annotation.Layer.LOWER; | ||||||
|  |         } else { | ||||||
|  |             layer = Annotation.Layer.UPPER; | ||||||
|  |         } | ||||||
|  |         graph.getGraphMouse().getAnnotatingPlugin().setLayer(layer); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void shapeChange(ActionEvent event) { | ||||||
|  |         String selected = shapeCombo.getSelectionModel().getSelectedItem(); | ||||||
|  |         logger.info("annotation shape selected: {}", selected); | ||||||
|  |         RectangularShape shape = new Rectangle(); | ||||||
|  |         switch (selected) { | ||||||
|  |             case RECTANGLE: | ||||||
|  |                 shape = new Rectangle(); | ||||||
|  |                 break; | ||||||
|  |             case ROUND_RECTANGLE: | ||||||
|  |                 shape = new RoundRectangle2D.Double(0, 0, 0, 0, 50.0, 50.0); | ||||||
|  |                 break; | ||||||
|  |             case ELLIPSE: | ||||||
|  |                 shape = new Ellipse2D.Double(); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 Toast.error("Unknown annotation shape " + selected); | ||||||
|  |         } | ||||||
|  |         graph.getGraphMouse().getAnnotatingPlugin().setRectangularShape(shape); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										297
									
								
								corefx/src/main/java/com/core/ui/GraphToolbar.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										297
									
								
								corefx/src/main/java/com/core/ui/GraphToolbar.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,297 @@ | ||||||
|  | package com.core.ui; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.NodeType; | ||||||
|  | import com.core.utils.FxmlUtils; | ||||||
|  | import com.core.utils.IconUtils; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXListView; | ||||||
|  | import com.jfoenix.controls.JFXPopup; | ||||||
|  | import com.jfoenix.svg.SVGGlyph; | ||||||
|  | import edu.uci.ics.jung.visualization.control.ModalGraphMouse; | ||||||
|  | import javafx.application.Platform; | ||||||
|  | import javafx.css.PseudoClass; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.control.ComboBox; | ||||||
|  | import javafx.scene.control.Label; | ||||||
|  | import javafx.scene.control.Tooltip; | ||||||
|  | import javafx.scene.image.ImageView; | ||||||
|  | import javafx.scene.layout.VBox; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.Comparator; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public class GraphToolbar extends VBox { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final int ICON_SIZE = 40; | ||||||
|  |     private static final int NODES_ICON_SIZE = 20; | ||||||
|  |     private static final PseudoClass START_CLASS = PseudoClass.getPseudoClass("start"); | ||||||
|  |     private static final PseudoClass STOP_CLASS = PseudoClass.getPseudoClass("stop"); | ||||||
|  |     private static final PseudoClass SELECTED_CLASS = PseudoClass.getPseudoClass("selected"); | ||||||
|  |     private final Controller controller; | ||||||
|  |     private final Map<Integer, Label> labelMap = new HashMap<>(); | ||||||
|  |     private SVGGlyph startIcon; | ||||||
|  |     private SVGGlyph stopIcon; | ||||||
|  |     private JFXListView<Label> nodesList = new JFXListView<>(); | ||||||
|  |     private JFXListView<Label> devicesList = new JFXListView<>(); | ||||||
|  |     private JFXButton selectedEditButton; | ||||||
|  |     private NodeType selectedNodeType; | ||||||
|  |     private boolean isEditing = false; | ||||||
|  |     @FXML private JFXButton runButton; | ||||||
|  |     @FXML private JFXButton pickingButton; | ||||||
|  |     @FXML private JFXButton drawingButton; | ||||||
|  |     @FXML private ComboBox<String> graphModeCombo; | ||||||
|  |     @FXML private JFXButton nodesButton; | ||||||
|  |     @FXML private JFXButton devicesButton; | ||||||
|  | 
 | ||||||
|  |     public GraphToolbar(Controller controller) { | ||||||
|  |         this.controller = controller; | ||||||
|  |         FxmlUtils.loadRootController(this, "/fxml/graph_toolbar.fxml"); | ||||||
|  | 
 | ||||||
|  |         startIcon = IconUtils.get("play_circle_filled"); | ||||||
|  |         startIcon.setSize(ICON_SIZE); | ||||||
|  |         stopIcon = IconUtils.get("stop"); | ||||||
|  |         stopIcon.setSize(ICON_SIZE); | ||||||
|  | 
 | ||||||
|  |         setupPickingButton(); | ||||||
|  |         setupDrawingButton(); | ||||||
|  |         setupNodesButton(); | ||||||
|  |         setupDevicesButton(); | ||||||
|  | 
 | ||||||
|  |         // initial state | ||||||
|  |         setSelected(true, pickingButton); | ||||||
|  |         controller.getNetworkGraph().setMode(ModalGraphMouse.Mode.PICKING); | ||||||
|  |         runButton.setGraphic(startIcon); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setupPickingButton() { | ||||||
|  |         SVGGlyph pickingIcon = IconUtils.get("call_made"); | ||||||
|  |         pickingIcon.setSize(ICON_SIZE); | ||||||
|  |         pickingButton.setGraphic(pickingIcon); | ||||||
|  |         pickingButton.setTooltip(new Tooltip("Pick/Move Nodes")); | ||||||
|  |         pickingButton.setOnAction(event -> { | ||||||
|  |             controller.getNetworkGraph().setMode(ModalGraphMouse.Mode.PICKING); | ||||||
|  |             controller.getBottom().getChildren().remove(controller.getAnnotationToolbar()); | ||||||
|  |             controller.getBorderPane().setRight(null); | ||||||
|  |             setSelected(true, pickingButton); | ||||||
|  |             setSelected(false, drawingButton, selectedEditButton); | ||||||
|  |             isEditing = false; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setEditMode() { | ||||||
|  |         controller.getNetworkGraph().setMode(ModalGraphMouse.Mode.EDITING); | ||||||
|  |         controller.getBottom().getChildren().remove(controller.getAnnotationToolbar()); | ||||||
|  |         controller.getBorderPane().setRight(null); | ||||||
|  |         if (selectedEditButton != null) { | ||||||
|  |             setSelected(true, selectedEditButton); | ||||||
|  |         } | ||||||
|  |         setSelected(false, drawingButton, pickingButton); | ||||||
|  |         isEditing = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setupDrawingButton() { | ||||||
|  |         SVGGlyph pencilIcon = IconUtils.get("brush"); | ||||||
|  |         pencilIcon.setSize(ICON_SIZE); | ||||||
|  |         drawingButton.setGraphic(pencilIcon); | ||||||
|  |         drawingButton.setTooltip(new Tooltip("Annotate Graph")); | ||||||
|  |         drawingButton.setOnAction(event -> { | ||||||
|  |             controller.getNetworkGraph().setMode(ModalGraphMouse.Mode.ANNOTATING); | ||||||
|  |             controller.getBottom().getChildren().add(controller.getAnnotationToolbar()); | ||||||
|  |             controller.getBorderPane().setRight(null); | ||||||
|  |             setSelected(true, drawingButton); | ||||||
|  |             setSelected(false, pickingButton, selectedEditButton); | ||||||
|  |             isEditing = false; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setupNodeTypes() { | ||||||
|  |         // clear existing configuration | ||||||
|  |         labelMap.clear(); | ||||||
|  |         nodesList.getItems().clear(); | ||||||
|  |         devicesList.getItems().clear(); | ||||||
|  | 
 | ||||||
|  |         for (NodeType nodeType : NodeType.getAll()) { | ||||||
|  |             ImageView icon = new ImageView(nodeType.getIcon()); | ||||||
|  |             icon.setFitWidth(NODES_ICON_SIZE); | ||||||
|  |             icon.setFitHeight(NODES_ICON_SIZE); | ||||||
|  |             Label label = new Label(nodeType.getDisplay(), icon); | ||||||
|  |             label.setUserData(nodeType.getId()); | ||||||
|  |             labelMap.put(nodeType.getId(), label); | ||||||
|  | 
 | ||||||
|  |             if (nodeType.getValue() == NodeType.DEFAULT) { | ||||||
|  |                 nodesList.getItems().add(label); | ||||||
|  |             } else { | ||||||
|  |                 devicesList.getItems().add(label); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Comparator<Label> comparator = Comparator.comparing(Label::getText); | ||||||
|  |         nodesList.getItems().sort(comparator); | ||||||
|  |         devicesList.getItems().sort(comparator); | ||||||
|  | 
 | ||||||
|  |         // initial node | ||||||
|  |         nodesList.getSelectionModel().selectFirst(); | ||||||
|  |         Label selectedNodeLabel = nodesList.getSelectionModel().getSelectedItem(); | ||||||
|  |         selectedNodeType = NodeType.get((int) selectedNodeLabel.getUserData()); | ||||||
|  |         selectedEditButton = nodesButton; | ||||||
|  |         controller.getNetworkGraph().setNodeType(selectedNodeType); | ||||||
|  |         updateButtonValues(nodesButton, selectedNodeLabel); | ||||||
|  | 
 | ||||||
|  |         // initial device | ||||||
|  |         updateButtonValues(devicesButton, devicesList.getItems().get(0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void updateButtonValues(JFXButton button, Label label) { | ||||||
|  |         ImageView icon = new ImageView(((ImageView) label.getGraphic()).getImage()); | ||||||
|  |         icon.setFitHeight(ICON_SIZE); | ||||||
|  |         icon.setFitWidth(ICON_SIZE); | ||||||
|  |         button.setGraphic(icon); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setSelectedEditButton(JFXButton button) { | ||||||
|  |         JFXButton previous = selectedEditButton; | ||||||
|  |         selectedEditButton = button; | ||||||
|  |         if (isEditing) { | ||||||
|  |             if (previous != null) { | ||||||
|  |                 setSelected(false, previous); | ||||||
|  |             } | ||||||
|  |             setSelected(true, selectedEditButton); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setupNodesButton() { | ||||||
|  |         nodesButton.setTooltip(new Tooltip("Network Nodes (host, pc, etc)")); | ||||||
|  |         nodesList.setOnMouseClicked(event -> { | ||||||
|  |             Label selectedLabel = nodesList.getSelectionModel().getSelectedItem(); | ||||||
|  |             if (selectedLabel == null) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             updateButtonValues(nodesButton, selectedLabel); | ||||||
|  |             selectedNodeType = NodeType.get((int) selectedLabel.getUserData()); | ||||||
|  |             logger.info("selected node type: {}", selectedNodeType); | ||||||
|  |             setSelectedEditButton(nodesButton); | ||||||
|  |             devicesList.getSelectionModel().clearSelection(); | ||||||
|  |             controller.getNetworkGraph().setNodeType(selectedNodeType); | ||||||
|  |             logger.info("node selected: {} - type: {}", selectedLabel, selectedNodeType); | ||||||
|  |             setEditMode(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         JFXPopup popup = new JFXPopup(nodesList); | ||||||
|  |         nodesButton.setOnAction(event -> popup.show(nodesButton, JFXPopup.PopupVPosition.TOP, | ||||||
|  |                 JFXPopup.PopupHPosition.LEFT, nodesButton.getWidth(), 0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setupDevicesButton() { | ||||||
|  |         devicesButton.setTooltip(new Tooltip("Device Nodes (WLAN, EMANE, Switch, etc)")); | ||||||
|  |         devicesList.setOnMouseClicked(event -> { | ||||||
|  |             Label selectedLabel = devicesList.getSelectionModel().getSelectedItem(); | ||||||
|  |             if (selectedLabel == null) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             updateButtonValues(devicesButton, selectedLabel); | ||||||
|  |             selectedNodeType = NodeType.get((int) selectedLabel.getUserData()); | ||||||
|  |             logger.info("selected node type: {}", selectedNodeType); | ||||||
|  |             controller.getNetworkGraph().setNodeType(selectedNodeType); | ||||||
|  |             setSelectedEditButton(devicesButton); | ||||||
|  |             nodesList.getSelectionModel().clearSelection(); | ||||||
|  |             logger.info("device selected: {} - type: {}", selectedLabel, selectedNodeType); | ||||||
|  |             setEditMode(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         JFXPopup popup = new JFXPopup(devicesList); | ||||||
|  |         devicesButton.setOnAction(event -> popup.show(devicesButton, JFXPopup.PopupVPosition.TOP, | ||||||
|  |                 JFXPopup.PopupHPosition.LEFT, devicesButton.getWidth(), 0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onRunButtonAction(ActionEvent event) { | ||||||
|  |         if (runButton.getGraphic() == startIcon) { | ||||||
|  |             startSession(); | ||||||
|  |         } else { | ||||||
|  |             stopSession(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void updateNodeType(int id, String uri) { | ||||||
|  |         Label label = labelMap.get(id); | ||||||
|  |         ImageView icon = new ImageView(uri); | ||||||
|  |         icon.setFitWidth(NODES_ICON_SIZE); | ||||||
|  |         icon.setFitHeight(NODES_ICON_SIZE); | ||||||
|  |         label.setGraphic(icon); | ||||||
|  | 
 | ||||||
|  |         if (selectedNodeType.getId() == id) { | ||||||
|  |             updateButtonValues(nodesButton, label); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setSelected(boolean isSelected, JFXButton... others) { | ||||||
|  |         Arrays.stream(others) | ||||||
|  |                 .forEach(x -> x.pseudoClassStateChanged(SELECTED_CLASS, isSelected)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void startSession() { | ||||||
|  |         runButton.setDisable(true); | ||||||
|  |         new Thread(() -> { | ||||||
|  |             try { | ||||||
|  |                 boolean result = controller.startSession(); | ||||||
|  |                 if (result) { | ||||||
|  |                     Toast.success("Session Started"); | ||||||
|  |                     setRunButton(true); | ||||||
|  |                 } | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("Failure Starting Session", ex); | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void stopSession() { | ||||||
|  |         runButton.setDisable(true); | ||||||
|  |         new Thread(() -> { | ||||||
|  |             try { | ||||||
|  |                 boolean result = controller.stopSession(); | ||||||
|  |                 if (result) { | ||||||
|  |                     Toast.success("Session Stopped"); | ||||||
|  |                     setRunButton(false); | ||||||
|  |                 } | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("Failure Stopping Session", ex); | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setRunButton(boolean isRunning) { | ||||||
|  |         if (isRunning) { | ||||||
|  |             Platform.runLater(() -> { | ||||||
|  |                 pickingButton.fire(); | ||||||
|  |                 devicesButton.setDisable(true); | ||||||
|  |                 nodesButton.setDisable(true); | ||||||
|  |                 runButton.pseudoClassStateChanged(START_CLASS, false); | ||||||
|  |                 runButton.pseudoClassStateChanged(STOP_CLASS, true); | ||||||
|  |                 if (runButton.getGraphic() != stopIcon) { | ||||||
|  |                     runButton.setGraphic(stopIcon); | ||||||
|  |                 } | ||||||
|  |                 runButton.setDisable(false); | ||||||
|  |             }); | ||||||
|  |         } else { | ||||||
|  |             Platform.runLater(() -> { | ||||||
|  |                 devicesButton.setDisable(false); | ||||||
|  |                 nodesButton.setDisable(false); | ||||||
|  |                 runButton.pseudoClassStateChanged(START_CLASS, true); | ||||||
|  |                 runButton.pseudoClassStateChanged(STOP_CLASS, false); | ||||||
|  |                 if (runButton.getGraphic() != startIcon) { | ||||||
|  |                     runButton.setGraphic(startIcon); | ||||||
|  |                 } | ||||||
|  |                 runButton.setDisable(false); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										178
									
								
								corefx/src/main/java/com/core/ui/LinkDetails.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								corefx/src/main/java/com/core/ui/LinkDetails.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,178 @@ | ||||||
|  | package com.core.ui; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.client.ICoreClient; | ||||||
|  | import com.core.data.CoreInterface; | ||||||
|  | import com.core.data.CoreLink; | ||||||
|  | import com.core.data.CoreLinkOptions; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.graph.NetworkGraph; | ||||||
|  | import com.core.ui.textfields.DoubleFilter; | ||||||
|  | import com.core.utils.FxmlUtils; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.event.EventHandler; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.geometry.Insets; | ||||||
|  | import javafx.geometry.Orientation; | ||||||
|  | import javafx.scene.control.Label; | ||||||
|  | import javafx.scene.control.ScrollPane; | ||||||
|  | import javafx.scene.control.Separator; | ||||||
|  | import javafx.scene.control.TextFormatter; | ||||||
|  | import javafx.scene.layout.GridPane; | ||||||
|  | import javafx.util.converter.DoubleStringConverter; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | public class LinkDetails extends ScrollPane { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final int START_INDEX = 1; | ||||||
|  |     private final Controller controller; | ||||||
|  |     private int index = START_INDEX; | ||||||
|  |     @FXML private GridPane gridPane; | ||||||
|  | 
 | ||||||
|  |     public LinkDetails(Controller controller) { | ||||||
|  |         this.controller = controller; | ||||||
|  |         FxmlUtils.loadRootController(this, "/fxml/link_details.fxml"); | ||||||
|  |         setPrefWidth(400); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setLink(CoreLink link) { | ||||||
|  |         NetworkGraph graph = controller.getNetworkGraph(); | ||||||
|  |         ICoreClient coreClient = controller.getCoreClient(); | ||||||
|  | 
 | ||||||
|  |         clear(); | ||||||
|  | 
 | ||||||
|  |         addSeparator(); | ||||||
|  |         CoreNode nodeOne = graph.getVertex(link.getNodeOne()); | ||||||
|  |         CoreInterface interfaceOne = link.getInterfaceOne(); | ||||||
|  |         addLabel(nodeOne.getName()); | ||||||
|  |         if (interfaceOne != null) { | ||||||
|  |             addInterface(interfaceOne); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         addSeparator(); | ||||||
|  |         CoreNode nodeTwo = graph.getVertex(link.getNodeTwo()); | ||||||
|  |         CoreInterface interfaceTwo = link.getInterfaceTwo(); | ||||||
|  |         addLabel(nodeTwo.getName()); | ||||||
|  |         if (interfaceTwo != null) { | ||||||
|  |             addInterface(interfaceTwo); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         addSeparator(); | ||||||
|  |         addLabel("Properties"); | ||||||
|  |         JFXTextField bandwidthField = addRow("Bandwidth (bps)", link.getOptions().getBandwidth()); | ||||||
|  |         JFXTextField delayField = addRow("Delay (us)", link.getOptions().getDelay()); | ||||||
|  |         JFXTextField jitterField = addRow("Jitter (us)", link.getOptions().getJitter()); | ||||||
|  |         JFXTextField lossField = addRow("Loss (%)", link.getOptions().getPer()); | ||||||
|  |         JFXTextField dupsField = addRow("Duplicate (%)", link.getOptions().getDup()); | ||||||
|  |         addButton("Update", event -> { | ||||||
|  |             CoreLinkOptions options = link.getOptions(); | ||||||
|  |             options.setBandwidth(getDouble(bandwidthField)); | ||||||
|  |             options.setDelay(getDouble(delayField)); | ||||||
|  |             options.setJitter(getDouble(jitterField)); | ||||||
|  |             options.setPer(getDouble(lossField)); | ||||||
|  |             options.setDup(getDouble(dupsField)); | ||||||
|  | 
 | ||||||
|  |             if (coreClient.isRunning()) { | ||||||
|  |                 try { | ||||||
|  |                     coreClient.editLink(link); | ||||||
|  |                     Toast.info("Link updated!"); | ||||||
|  |                 } catch (IOException ex) { | ||||||
|  |                     Toast.error("Failure to update link", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Double getDouble(JFXTextField textField) { | ||||||
|  |         if (textField.getText() == null) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         Double value = null; | ||||||
|  |         try { | ||||||
|  |             logger.info("double field text: {}", textField.getText()); | ||||||
|  |             value = Double.parseDouble(textField.getText()); | ||||||
|  |         } catch (NumberFormatException ex) { | ||||||
|  |             logger.error("error getting double value", ex); | ||||||
|  |         } | ||||||
|  |         return value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addButton(String text, EventHandler<ActionEvent> handler) { | ||||||
|  |         JFXButton button = new JFXButton(text); | ||||||
|  |         button.getStyleClass().add("core-button"); | ||||||
|  |         button.setMaxWidth(Double.MAX_VALUE); | ||||||
|  |         button.setOnAction(handler); | ||||||
|  |         gridPane.add(button, 0, index++, 2, 1); | ||||||
|  |         GridPane.setMargin(button, new Insets(10, 0, 0, 0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addLabel(String text) { | ||||||
|  |         Label label = new Label(text); | ||||||
|  |         label.getStyleClass().add("details-label"); | ||||||
|  |         gridPane.add(label, 0, index++, 2, 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addSeparator() { | ||||||
|  |         Separator separator = new Separator(Orientation.HORIZONTAL); | ||||||
|  |         gridPane.add(separator, 0, index++, 2, 1); | ||||||
|  |         GridPane.setMargin(separator, new Insets(10, 0, 0, 0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addInterface(CoreInterface coreInterface) { | ||||||
|  |         addRow("Interface", coreInterface.getName(), true); | ||||||
|  |         if (coreInterface.getMac() != null) { | ||||||
|  |             addRow("MAC", coreInterface.getMac(), true); | ||||||
|  |         } | ||||||
|  |         addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask()); | ||||||
|  |         addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addRow(String labelText, String value, boolean disabled) { | ||||||
|  |         Label label = new Label(labelText); | ||||||
|  |         JFXTextField textField = new JFXTextField(value); | ||||||
|  |         textField.setDisable(disabled); | ||||||
|  |         gridPane.addRow(index++, label, textField); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private JFXTextField addRow(String labelText, Double value) { | ||||||
|  |         Label label = new Label(labelText); | ||||||
|  |         String doubleString = null; | ||||||
|  |         if (value != null) { | ||||||
|  |             doubleString = value.toString(); | ||||||
|  |         } | ||||||
|  |         JFXTextField textField = new JFXTextField(); | ||||||
|  |         TextFormatter<Double> formatter = new TextFormatter<>( | ||||||
|  |                 new DoubleStringConverter(), null, new DoubleFilter()); | ||||||
|  |         textField.setTextFormatter(formatter); | ||||||
|  |         textField.setText(doubleString); | ||||||
|  |         gridPane.addRow(index++, label, textField); | ||||||
|  |         return textField; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addIp4Address(String ip, Integer mask) { | ||||||
|  |         if (ip == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         addRow("IP4", String.format("%s/%s", ip, mask), true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addIp6Address(String ip, String mask) { | ||||||
|  |         if (ip == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         addRow("IP6", String.format("%s/%s", ip, mask), true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void clear() { | ||||||
|  |         if (gridPane.getChildren().size() > START_INDEX) { | ||||||
|  |             gridPane.getChildren().remove(START_INDEX, gridPane.getChildren().size()); | ||||||
|  |         } | ||||||
|  |         index = START_INDEX; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										181
									
								
								corefx/src/main/java/com/core/ui/NodeDetails.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								corefx/src/main/java/com/core/ui/NodeDetails.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,181 @@ | ||||||
|  | package com.core.ui; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreInterface; | ||||||
|  | import com.core.data.CoreLink; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.data.NodeType; | ||||||
|  | import com.core.utils.FxmlUtils; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXListView; | ||||||
|  | import com.jfoenix.controls.JFXScrollPane; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.event.EventHandler; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.geometry.Insets; | ||||||
|  | import javafx.geometry.Orientation; | ||||||
|  | import javafx.scene.control.Label; | ||||||
|  | import javafx.scene.control.ScrollPane; | ||||||
|  | import javafx.scene.control.Separator; | ||||||
|  | import javafx.scene.layout.GridPane; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.Set; | ||||||
|  | 
 | ||||||
|  | public class NodeDetails extends ScrollPane { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final int START_INDEX = 1; | ||||||
|  |     private final Controller controller; | ||||||
|  |     @FXML private Label title; | ||||||
|  |     @FXML private ScrollPane scrollPane; | ||||||
|  |     @FXML private GridPane gridPane; | ||||||
|  |     private int index = START_INDEX; | ||||||
|  | 
 | ||||||
|  |     public NodeDetails(Controller controller) { | ||||||
|  |         this.controller = controller; | ||||||
|  |         FxmlUtils.loadRootController(this, "/fxml/node_details.fxml"); | ||||||
|  |         setPrefWidth(400); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setNode(CoreNode node) { | ||||||
|  |         clear(); | ||||||
|  |         title.setText(node.getName()); | ||||||
|  | 
 | ||||||
|  |         addSeparator(); | ||||||
|  |         addLabel("Properties"); | ||||||
|  |         if (node.getType() == NodeType.DEFAULT) { | ||||||
|  |             addRow("Model", node.getModel(), true); | ||||||
|  |         } else { | ||||||
|  |             addRow("Type", node.getNodeType().getDisplay(), true); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (node.getEmane() != null) { | ||||||
|  |             addRow("EMANE", node.getEmane(), true); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         addSeparator(); | ||||||
|  |         addLabel("Position"); | ||||||
|  |         if (node.getPosition().getX() != null) { | ||||||
|  |             addRow("X", node.getPosition().getX().toString(), true); | ||||||
|  |         } | ||||||
|  |         if (node.getPosition().getY() != null) { | ||||||
|  |             addRow("Y", node.getPosition().getY().toString(), true); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         addSeparator(); | ||||||
|  |         addLabel("Interfaces"); | ||||||
|  |         for (CoreLink link : controller.getNetworkGraph().getGraph().getIncidentEdges(node)) { | ||||||
|  |             CoreNode linkedNode; | ||||||
|  |             CoreInterface coreInterface; | ||||||
|  |             if (node.getId().equals(link.getNodeOne())) { | ||||||
|  |                 coreInterface = link.getInterfaceOne(); | ||||||
|  |                 linkedNode = controller.getNetworkGraph().getNodeMap().get(link.getNodeTwo()); | ||||||
|  |             } else { | ||||||
|  |                 coreInterface = link.getInterfaceTwo(); | ||||||
|  |                 linkedNode = controller.getNetworkGraph().getNodeMap().get(link.getNodeOne()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (coreInterface == null) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             addSeparator(); | ||||||
|  |             if (linkedNode.getType() == NodeType.EMANE) { | ||||||
|  |                 String emaneModel = linkedNode.getEmane(); | ||||||
|  |                 String linkedLabel = String.format("%s - %s", linkedNode.getName(), emaneModel); | ||||||
|  |                 addButton(linkedLabel, event -> controller.getNodeEmaneDialog() | ||||||
|  |                         .displayEmaneModelConfig(linkedNode.getId(), emaneModel)); | ||||||
|  |                 String nodeLabel = String.format("%s - %s", node.getName(), emaneModel); | ||||||
|  |                 addButton(nodeLabel, event -> controller.getNodeEmaneDialog() | ||||||
|  |                         .displayEmaneModelConfig(node.getId(), emaneModel)); | ||||||
|  |                 String interfaceLabel = String.format("%s - %s", coreInterface.getName(), emaneModel); | ||||||
|  |                 Integer interfaceId = 1000 * node.getId() + coreInterface.getId(); | ||||||
|  |                 addButton(interfaceLabel, event -> controller.getNodeEmaneDialog() | ||||||
|  |                         .displayEmaneModelConfig(interfaceId, emaneModel)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (linkedNode.getType() == NodeType.WLAN) { | ||||||
|  |                 addButton(linkedNode.getName(), event -> controller.getNodeWlanDialog().showDialog(linkedNode)); | ||||||
|  |             } | ||||||
|  |             addInterface(coreInterface, linkedNode); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // display custom or default node services | ||||||
|  |         Set<String> services = node.getServices(); | ||||||
|  |         if (services.isEmpty()) { | ||||||
|  |             services = controller.getDefaultServices().getOrDefault(node.getModel(), Collections.emptySet()); | ||||||
|  |         } | ||||||
|  |         if (!services.isEmpty()) { | ||||||
|  |             addSeparator(); | ||||||
|  |             addLabel("Services"); | ||||||
|  |             JFXListView<String> listView = new JFXListView<>(); | ||||||
|  |             listView.setMouseTransparent(true); | ||||||
|  |             listView.setFocusTraversable(false); | ||||||
|  |             listView.getItems().setAll(services); | ||||||
|  |             gridPane.add(listView, 0, index++, 2, 1); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         JFXScrollPane.smoothScrolling(scrollPane); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addButton(String text, EventHandler<ActionEvent> handler) { | ||||||
|  |         JFXButton emaneButton = new JFXButton(text); | ||||||
|  |         emaneButton.getStyleClass().add("core-button"); | ||||||
|  |         emaneButton.setMaxWidth(Double.MAX_VALUE); | ||||||
|  |         emaneButton.setOnAction(handler); | ||||||
|  |         gridPane.add(emaneButton, 0, index++, 2, 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addLabel(String text) { | ||||||
|  |         Label label = new Label(text); | ||||||
|  |         label.getStyleClass().add("details-label"); | ||||||
|  |         gridPane.add(label, 0, index++, 2, 1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addSeparator() { | ||||||
|  |         Separator separator = new Separator(Orientation.HORIZONTAL); | ||||||
|  |         gridPane.add(separator, 0, index++, 2, 1); | ||||||
|  |         GridPane.setMargin(separator, new Insets(10, 0, 0, 0)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addInterface(CoreInterface coreInterface, CoreNode linkedNode) { | ||||||
|  |         addRow("Linked To", linkedNode.getName(), true); | ||||||
|  |         addRow("Interface", coreInterface.getName(), true); | ||||||
|  |         if (coreInterface.getMac() != null) { | ||||||
|  |             addRow("MAC", coreInterface.getMac(), true); | ||||||
|  |         } | ||||||
|  |         addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask()); | ||||||
|  |         addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addRow(String labelText, String value, boolean disabled) { | ||||||
|  |         Label label = new Label(labelText); | ||||||
|  |         JFXTextField textField = new JFXTextField(value); | ||||||
|  |         textField.setDisable(disabled); | ||||||
|  |         gridPane.addRow(index++, label, textField); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addIp4Address(String ip, Integer mask) { | ||||||
|  |         if (ip == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         addRow("IP4", String.format("%s/%s", ip, mask), true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addIp6Address(String ip, String mask) { | ||||||
|  |         if (ip == null) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         addRow("IP6", String.format("%s/%s", ip, mask), true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void clear() { | ||||||
|  |         if (gridPane.getChildren().size() > START_INDEX) { | ||||||
|  |             gridPane.getChildren().remove(START_INDEX, gridPane.getChildren().size()); | ||||||
|  |         } | ||||||
|  |         index = START_INDEX; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								corefx/src/main/java/com/core/ui/ServiceItem.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								corefx/src/main/java/com/core/ui/ServiceItem.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | package com.core.ui; | ||||||
|  | 
 | ||||||
|  | import com.jfoenix.controls.JFXCheckBox; | ||||||
|  | import lombok.Data; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class ServiceItem { | ||||||
|  |     private String service; | ||||||
|  |     private JFXCheckBox checkBox; | ||||||
|  | 
 | ||||||
|  |     public ServiceItem(String service) { | ||||||
|  |         this.service = service; | ||||||
|  |         checkBox = new JFXCheckBox(service); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								corefx/src/main/java/com/core/ui/Toast.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								corefx/src/main/java/com/core/ui/Toast.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | package com.core.ui; | ||||||
|  | 
 | ||||||
|  | import com.jfoenix.controls.JFXSnackbar; | ||||||
|  | import javafx.scene.layout.StackPane; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | public final class Toast { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final long TIMEOUT = 3000; | ||||||
|  |     private static JFXSnackbar snackbar; | ||||||
|  | 
 | ||||||
|  |     private Toast() { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void setSnackbarRoot(StackPane stackPane) { | ||||||
|  |         snackbar = new JFXSnackbar(stackPane); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static void toast(String message, String className) { | ||||||
|  |         JFXSnackbar.SnackbarEvent snackbarEvent = new JFXSnackbar.SnackbarEvent(message, | ||||||
|  |                 className, null, TIMEOUT, false, null); | ||||||
|  |         snackbar.enqueue(snackbarEvent); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void info(String message) { | ||||||
|  |         toast(message, "toast-info"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void success(String message) { | ||||||
|  |         toast(message, "toast-success"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void warning(String message) { | ||||||
|  |         toast(message, "toast-warning"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void error(String message) { | ||||||
|  |         error(message, null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void error(String message, Exception ex) { | ||||||
|  |         if (ex != null) { | ||||||
|  |             logger.error(message, ex); | ||||||
|  |         } | ||||||
|  |         JFXSnackbar.SnackbarEvent snackbarEvent = new JFXSnackbar.SnackbarEvent(message, | ||||||
|  |                 "toast-error", "X", TIMEOUT, true, event -> snackbar.close()); | ||||||
|  |         snackbar.close(); | ||||||
|  |         snackbar.enqueue(snackbarEvent); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,86 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreLink; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.graph.BackgroundPaintable; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.image.Image; | ||||||
|  | import javafx.scene.image.ImageView; | ||||||
|  | import javafx.scene.layout.HBox; | ||||||
|  | import javafx.stage.FileChooser; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.nio.file.Paths; | ||||||
|  | 
 | ||||||
|  | public class BackgroundDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private ImageView imageView; | ||||||
|  |     @FXML private JFXTextField fileTextField; | ||||||
|  |     @FXML private JFXButton fileButton; | ||||||
|  |     private JFXButton saveButton; | ||||||
|  |     private JFXButton clearButton; | ||||||
|  | 
 | ||||||
|  |     public BackgroundDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/background_dialog.fxml"); | ||||||
|  |         setTitle("Background Configuration"); | ||||||
|  |         saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(this::saveAction); | ||||||
|  | 
 | ||||||
|  |         clearButton = createButton("Clear"); | ||||||
|  |         clearButton.setOnAction(this::clearAction); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         HBox parent = (HBox) imageView.getParent(); | ||||||
|  |         imageView.fitHeightProperty().bind(parent.heightProperty()); | ||||||
|  | 
 | ||||||
|  |         fileButton.setOnAction(this::fileAction); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void fileAction(ActionEvent event) { | ||||||
|  |         FileChooser fileChooser = new FileChooser(); | ||||||
|  |         fileChooser.setTitle("Select Background"); | ||||||
|  |         fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); | ||||||
|  |         fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("PNG", "*.png")); | ||||||
|  |         File file = fileChooser.showOpenDialog(getStage()); | ||||||
|  |         if (file != null) { | ||||||
|  |             String uri = file.toURI().toString(); | ||||||
|  |             imageView.setImage(new Image(uri)); | ||||||
|  |             fileTextField.setText(file.getPath()); | ||||||
|  |             saveButton.setDisable(false); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void saveAction(ActionEvent event) { | ||||||
|  |         getController().getNetworkGraph().setBackground(fileTextField.getText()); | ||||||
|  |         close(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void clearAction(ActionEvent event) { | ||||||
|  |         getController().getNetworkGraph().removeBackground(); | ||||||
|  |         close(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         BackgroundPaintable<CoreNode, CoreLink> backgroundPaintable = getController().getNetworkGraph() | ||||||
|  |                 .getBackgroundPaintable(); | ||||||
|  |         saveButton.setDisable(true); | ||||||
|  |         fileTextField.setText(null); | ||||||
|  |         imageView.setImage(null); | ||||||
|  |         if (backgroundPaintable == null) { | ||||||
|  |             clearButton.setDisable(true); | ||||||
|  |         } else { | ||||||
|  |             String imagePath = backgroundPaintable.getImage(); | ||||||
|  |             fileTextField.setText(imagePath); | ||||||
|  |             imageView.setImage(new Image(Paths.get(imagePath).toUri().toString())); | ||||||
|  |             clearButton.setDisable(false); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										217
									
								
								corefx/src/main/java/com/core/ui/dialogs/ChartDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								corefx/src/main/java/com/core/ui/dialogs/ChartDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,217 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.datavis.*; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXComboBox; | ||||||
|  | import javafx.application.Platform; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.chart.Chart; | ||||||
|  | import javafx.scene.layout.Pane; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Random; | ||||||
|  | import java.util.concurrent.atomic.AtomicBoolean; | ||||||
|  | 
 | ||||||
|  | public class ChartDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final AtomicBoolean running = new AtomicBoolean(false); | ||||||
|  |     private final Random numbers = new Random(); | ||||||
|  |     private final List<String> chartNames = Arrays.asList("Name 1", "Name 2", "Name 3", "Name 4", "Name 5"); | ||||||
|  |     @FXML private JFXComboBox<String> chartCombo; | ||||||
|  |     @FXML private Pane chartPane; | ||||||
|  |     @FXML private JFXButton stopButton; | ||||||
|  |     private CoreGraph coreGraph; | ||||||
|  | 
 | ||||||
|  |     public ChartDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/chart_dialog.fxml"); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         coreGraph = new CoreGraph(); | ||||||
|  |         coreGraph.setTitle("My Graph"); | ||||||
|  |         coreGraph.setXAxis(new CoreGraphAxis("X Label", 0.0, 100.0, 1.0)); | ||||||
|  |         coreGraph.setYAxis(new CoreGraphAxis("Y Label", 0.0, 100.0, 1.0)); | ||||||
|  | 
 | ||||||
|  |         chartCombo.getItems().addAll("pie", "line", "area", "bar", "scatter", "bubble", "time"); | ||||||
|  |         chartCombo.getSelectionModel().selectedItemProperty().addListener((ov, prev, curr) -> { | ||||||
|  |             if (curr == null) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             running.set(false); | ||||||
|  |             switch (curr) { | ||||||
|  |                 case "pie": | ||||||
|  |                     pieChart(); | ||||||
|  |                     break; | ||||||
|  |                 case "line": | ||||||
|  |                     lineChart(); | ||||||
|  |                     break; | ||||||
|  |                 case "area": | ||||||
|  |                     areaChart(); | ||||||
|  |                     break; | ||||||
|  |                 case "bar": | ||||||
|  |                     barChart(); | ||||||
|  |                     break; | ||||||
|  |                 case "scatter": | ||||||
|  |                     scatterChart(); | ||||||
|  |                     break; | ||||||
|  |                 case "bubble": | ||||||
|  |                     bubbleChart(); | ||||||
|  |                     break; | ||||||
|  |                 case "time": | ||||||
|  |                     timeChart(); | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         stopButton.setOnAction(event -> running.set(false)); | ||||||
|  |         chartCombo.getSelectionModel().selectFirst(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void timeChart() { | ||||||
|  |         coreGraph.setGraphType(GraphType.TIME); | ||||||
|  |         CoreGraphWrapper graphWrapper = new CoreGraphWrapper(coreGraph); | ||||||
|  |         setChart(graphWrapper.getChart()); | ||||||
|  | 
 | ||||||
|  |         new Thread(() -> { | ||||||
|  |             while (running.get()) { | ||||||
|  |                 try { | ||||||
|  |                     double y = numbers.nextInt(100); | ||||||
|  |                     Platform.runLater(() -> graphWrapper.add(new CoreGraphData(null, null, y, null))); | ||||||
|  |                     Thread.sleep(1000); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     logger.error("error adding data", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void bubbleChart() { | ||||||
|  |         coreGraph.setGraphType(GraphType.BUBBLE); | ||||||
|  |         CoreGraphWrapper graphWrapper = new CoreGraphWrapper(coreGraph); | ||||||
|  |         setChart(graphWrapper.getChart()); | ||||||
|  | 
 | ||||||
|  |         new Thread(() -> { | ||||||
|  |             while (running.get()) { | ||||||
|  |                 try { | ||||||
|  |                     double x = numbers.nextInt(100); | ||||||
|  |                     double y = numbers.nextInt(100); | ||||||
|  |                     double weight = numbers.nextInt(10); | ||||||
|  |                     Platform.runLater(() -> graphWrapper.add(new CoreGraphData(null, x, y, weight))); | ||||||
|  |                     Thread.sleep(1000); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     logger.error("error adding data", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void scatterChart() { | ||||||
|  |         coreGraph.setGraphType(GraphType.SCATTER); | ||||||
|  |         CoreGraphWrapper graphWrapper = new CoreGraphWrapper(coreGraph); | ||||||
|  |         setChart(graphWrapper.getChart()); | ||||||
|  | 
 | ||||||
|  |         new Thread(() -> { | ||||||
|  |             while (running.get()) { | ||||||
|  |                 try { | ||||||
|  |                     double x = numbers.nextInt(100); | ||||||
|  |                     double y = numbers.nextInt(100); | ||||||
|  |                     Platform.runLater(() -> graphWrapper.add(new CoreGraphData(null, x, y, null))); | ||||||
|  |                     Thread.sleep(1000); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     logger.error("error adding data", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void areaChart() { | ||||||
|  |         coreGraph.setGraphType(GraphType.AREA); | ||||||
|  |         CoreGraphWrapper graphWrapper = new CoreGraphWrapper(coreGraph); | ||||||
|  |         setChart(graphWrapper.getChart()); | ||||||
|  | 
 | ||||||
|  |         new Thread(() -> { | ||||||
|  |             while (running.get()) { | ||||||
|  |                 try { | ||||||
|  |                     double x = numbers.nextInt(100); | ||||||
|  |                     double y = numbers.nextInt(100); | ||||||
|  |                     Platform.runLater(() -> graphWrapper.add(new CoreGraphData(null, x, y, null))); | ||||||
|  |                     Thread.sleep(1000); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     logger.error("error adding data", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setChart(Chart chart) { | ||||||
|  |         chart.prefHeightProperty().bind(chartPane.heightProperty()); | ||||||
|  |         chart.prefWidthProperty().bind(chartPane.widthProperty()); | ||||||
|  |         chartPane.getChildren().clear(); | ||||||
|  |         chartPane.getChildren().add(chart); | ||||||
|  |         running.set(true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void lineChart() { | ||||||
|  |         coreGraph.setGraphType(GraphType.LINE); | ||||||
|  |         CoreGraphWrapper graphWrapper = new CoreGraphWrapper(coreGraph); | ||||||
|  |         setChart(graphWrapper.getChart()); | ||||||
|  | 
 | ||||||
|  |         new Thread(() -> { | ||||||
|  |             while (running.get()) { | ||||||
|  |                 try { | ||||||
|  |                     double x = numbers.nextInt(100); | ||||||
|  |                     double y = numbers.nextInt(100); | ||||||
|  |                     Platform.runLater(() -> graphWrapper.add(new CoreGraphData(null, x, y, null))); | ||||||
|  |                     Thread.sleep(1000); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     logger.error("error adding data", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void pieChart() { | ||||||
|  |         coreGraph.setGraphType(GraphType.PIE); | ||||||
|  |         CoreGraphWrapper graphWrapper = new CoreGraphWrapper(coreGraph); | ||||||
|  |         setChart(graphWrapper.getChart()); | ||||||
|  |         new Thread(() -> { | ||||||
|  |             while (running.get()) { | ||||||
|  |                 try { | ||||||
|  |                     String name = chartNames.get(numbers.nextInt(chartNames.size())); | ||||||
|  |                     double y = numbers.nextInt(100); | ||||||
|  |                     Platform.runLater(() -> graphWrapper.add(new CoreGraphData(name, null, y, null))); | ||||||
|  |                     Thread.sleep(1000); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     logger.error("error adding data", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void barChart() { | ||||||
|  |         coreGraph.setGraphType(GraphType.BAR); | ||||||
|  |         CoreGraphWrapper graphWrapper = new CoreGraphWrapper(coreGraph); | ||||||
|  |         setChart(graphWrapper.getChart()); | ||||||
|  |         new Thread(() -> { | ||||||
|  |             while (running.get()) { | ||||||
|  |                 try { | ||||||
|  |                     String name = chartNames.get(numbers.nextInt(chartNames.size())); | ||||||
|  |                     Integer y = numbers.nextInt(100); | ||||||
|  |                     Platform.runLater(() -> graphWrapper.add(name, y)); | ||||||
|  |                     Thread.sleep(1000); | ||||||
|  |                 } catch (Exception ex) { | ||||||
|  |                     logger.error("error adding data", ex); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }).start(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         chartCombo.getSelectionModel().selectFirst(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										91
									
								
								corefx/src/main/java/com/core/ui/dialogs/ConfigDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								corefx/src/main/java/com/core/ui/dialogs/ConfigDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,91 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.ConfigGroup; | ||||||
|  | import com.core.data.ConfigOption; | ||||||
|  | import com.core.ui.config.ConfigItemUtils; | ||||||
|  | import com.core.ui.config.IConfigItem; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXScrollPane; | ||||||
|  | import com.jfoenix.controls.JFXTabPane; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.geometry.Insets; | ||||||
|  | import javafx.scene.Node; | ||||||
|  | import javafx.scene.control.ScrollPane; | ||||||
|  | import javafx.scene.control.Tab; | ||||||
|  | import javafx.scene.layout.ColumnConstraints; | ||||||
|  | import javafx.scene.layout.GridPane; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | public class ConfigDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private List<IConfigItem> configItems = new ArrayList<>(); | ||||||
|  |     private JFXButton saveButton; | ||||||
|  |     @FXML private JFXTabPane tabPane; | ||||||
|  | 
 | ||||||
|  |     public ConfigDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/config_dialog.fxml"); | ||||||
|  |         saveButton = createButton("Save"); | ||||||
|  |         addCancelButton(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<ConfigOption> getOptions() { | ||||||
|  |         return configItems.stream().map(IConfigItem::getOption).collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setDisabled(boolean isDisabled) { | ||||||
|  |         saveButton.setDisable(isDisabled); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(String title, List<ConfigGroup> configGroups, Runnable runnable) { | ||||||
|  |         setTitle(title); | ||||||
|  |         boolean sessionRunning = getCoreClient().isRunning(); | ||||||
|  |         setDisabled(sessionRunning); | ||||||
|  | 
 | ||||||
|  |         configItems.clear(); | ||||||
|  |         tabPane.getTabs().clear(); | ||||||
|  |         for (ConfigGroup group : configGroups) { | ||||||
|  |             String groupName = group.getName(); | ||||||
|  |             Tab tab = new Tab(groupName); | ||||||
|  |             ScrollPane scrollPane = new ScrollPane(); | ||||||
|  |             scrollPane.setFitToWidth(true); | ||||||
|  |             tab.setContent(scrollPane); | ||||||
|  |             GridPane gridPane = new GridPane(); | ||||||
|  |             gridPane.setPadding(new Insets(10)); | ||||||
|  |             scrollPane.setContent(gridPane); | ||||||
|  |             gridPane.setPrefWidth(Double.MAX_VALUE); | ||||||
|  |             ColumnConstraints labelConstraints = new ColumnConstraints(10); | ||||||
|  |             labelConstraints.setPercentWidth(50); | ||||||
|  |             ColumnConstraints valueConstraints = new ColumnConstraints(10); | ||||||
|  |             valueConstraints.setPercentWidth(50); | ||||||
|  |             gridPane.getColumnConstraints().addAll(labelConstraints, valueConstraints); | ||||||
|  |             gridPane.setHgap(10); | ||||||
|  |             gridPane.setVgap(10); | ||||||
|  |             int index = 0; | ||||||
|  |             tabPane.getTabs().add(tab); | ||||||
|  | 
 | ||||||
|  |             for (ConfigOption option : group.getOptions()) { | ||||||
|  |                 IConfigItem configItem = ConfigItemUtils.get(getStage(), option); | ||||||
|  |                 Node node = configItem.getNode(); | ||||||
|  |                 node.setDisable(sessionRunning); | ||||||
|  |                 gridPane.addRow(index, configItem.getLabel(), node); | ||||||
|  |                 configItems.add(configItem); | ||||||
|  |                 index += 1; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             JFXScrollPane.smoothScrolling(scrollPane); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             runnable.run(); | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								corefx/src/main/java/com/core/ui/dialogs/ConnectDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								corefx/src/main/java/com/core/ui/dialogs/ConnectDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class ConnectDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private String address; | ||||||
|  |     private int port; | ||||||
|  |     private JFXButton saveButton; | ||||||
|  |     @FXML JFXTextField addressTextField; | ||||||
|  |     @FXML JFXTextField portTextField; | ||||||
|  | 
 | ||||||
|  |     public ConnectDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/connect_dialog.fxml"); | ||||||
|  |         saveButton = createButton("Connect"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             address = addressTextField.getText(); | ||||||
|  |             port = Integer.parseInt(portTextField.getText()); | ||||||
|  |             controller.connectToCore(address, port); | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  |         setTitle("CORE Connection"); | ||||||
|  |         getStage().sizeToScene(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         addressTextField.setText(address); | ||||||
|  |         portTextField.setText(Integer.toString(port)); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.client.ICoreClient; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXDialog; | ||||||
|  | import com.jfoenix.controls.JFXDialogLayout; | ||||||
|  | import javafx.fxml.FXMLLoader; | ||||||
|  | import javafx.scene.Parent; | ||||||
|  | import javafx.scene.text.Text; | ||||||
|  | import javafx.stage.Stage; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class CoreFoenixDialog extends JFXDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final Controller controller; | ||||||
|  |     private final JFXDialog dialog; | ||||||
|  |     private final JFXDialogLayout dialogLayout = new JFXDialogLayout(); | ||||||
|  |     private final Text heading = new Text(); | ||||||
|  | 
 | ||||||
|  |     public CoreFoenixDialog(Controller controller, String fxmlPath) { | ||||||
|  |         this.controller = controller; | ||||||
|  | 
 | ||||||
|  |         FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath)); | ||||||
|  |         loader.setController(this); | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             Parent parent = loader.load(); | ||||||
|  |             dialogLayout.setBody(parent); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error loading fxml: {}", fxmlPath, ex); | ||||||
|  |             throw new RuntimeException(ex); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         dialogLayout.setHeading(heading); | ||||||
|  |         dialog = new JFXDialog(controller.getStackPane(), dialogLayout, DialogTransition.CENTER); | ||||||
|  |         dialogLayout.setPrefWidth(800); | ||||||
|  |         dialogLayout.setPrefHeight(600); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setOwner(Stage window) { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ICoreClient getCoreClient() { | ||||||
|  |         return controller.getCoreClient(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public JFXButton createButton(String text) { | ||||||
|  |         JFXButton button = new JFXButton(text); | ||||||
|  |         button.getStyleClass().add("core-button"); | ||||||
|  |         return button; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										28
									
								
								corefx/src/main/java/com/core/ui/dialogs/GeoDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								corefx/src/main/java/com/core/ui/dialogs/GeoDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.web.WebView; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | public class GeoDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private WebView webView; | ||||||
|  |     @FXML JFXButton button; | ||||||
|  | 
 | ||||||
|  |     public GeoDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/geo_dialog.fxml"); | ||||||
|  |         setTitle("Geo Display"); | ||||||
|  |         addCancelButton(); | ||||||
|  |         webView.getEngine().load(getClass().getResource("/html/geo.html").toExternalForm()); | ||||||
|  |         button.setOnAction(event -> { | ||||||
|  |             webView.getEngine().executeScript("randomMarker();"); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,80 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.core.utils.ConfigUtils; | ||||||
|  | import com.core.utils.Configuration; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXColorPicker; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.event.EventHandler; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.paint.Color; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | public class GuiPreferencesDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private JFXTextField xmlFilePathTextField; | ||||||
|  |     @FXML private JFXTextField mobilityFilePathTextField; | ||||||
|  |     @FXML private JFXTextField shellCommandTextField; | ||||||
|  |     @FXML private JFXTextField iconPathTextField; | ||||||
|  |     @FXML private JFXColorPicker nodeLabelColorPicker; | ||||||
|  |     @FXML private JFXColorPicker nodeLabelBackgroundColorPicker; | ||||||
|  |     @FXML private JFXTextField throughputLimitTextField; | ||||||
|  |     @FXML private JFXTextField throughputWidthTextField; | ||||||
|  |     @FXML private JFXButton saveButton; | ||||||
|  | 
 | ||||||
|  |     public GuiPreferencesDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/gui_preferences.fxml"); | ||||||
|  |         setTitle("GUI Preferences"); | ||||||
|  |         saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(onSave); | ||||||
|  |         addCancelButton(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private EventHandler<ActionEvent> onSave = event -> { | ||||||
|  |         Configuration configuration = getController().getConfiguration(); | ||||||
|  |         configuration.setXmlPath(xmlFilePathTextField.getText()); | ||||||
|  |         configuration.setMobilityPath(mobilityFilePathTextField.getText()); | ||||||
|  |         configuration.setShellCommand(shellCommandTextField.getText()); | ||||||
|  |         configuration.setIconPath(iconPathTextField.getText()); | ||||||
|  |         configuration.setNodeLabelColor(nodeLabelColorPicker.getValue().toString()); | ||||||
|  |         configuration.setNodeLabelBackgroundColor(nodeLabelBackgroundColorPicker.getValue().toString()); | ||||||
|  |         configuration.setThroughputLimit(Double.parseDouble(throughputLimitTextField.getText())); | ||||||
|  |         configuration.setThroughputWidth(Integer.parseInt(throughputWidthTextField.getText())); | ||||||
|  |         getController().getNetworkGraph().updatePreferences(configuration); | ||||||
|  |         try { | ||||||
|  |             ConfigUtils.save(configuration); | ||||||
|  |             Toast.success("Updated preferences"); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("Failure to update preferences", ex); | ||||||
|  |         } | ||||||
|  |         close(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         Configuration configuration = getController().getConfiguration(); | ||||||
|  |         xmlFilePathTextField.setText(configuration.getXmlPath()); | ||||||
|  |         mobilityFilePathTextField.setText(configuration.getMobilityPath()); | ||||||
|  |         shellCommandTextField.setText(configuration.getShellCommand()); | ||||||
|  |         iconPathTextField.setText(configuration.getIconPath()); | ||||||
|  |         nodeLabelColorPicker.setValue(Color.web(configuration.getNodeLabelColor())); | ||||||
|  |         nodeLabelBackgroundColorPicker.setValue(Color.web(configuration.getNodeLabelBackgroundColor())); | ||||||
|  |         String throughputLimit = null; | ||||||
|  |         if (configuration.getThroughputLimit() != null) { | ||||||
|  |             throughputLimit = configuration.getThroughputLimit().toString(); | ||||||
|  |         } | ||||||
|  |         throughputLimitTextField.setText(throughputLimit); | ||||||
|  | 
 | ||||||
|  |         String throughputWidth = null; | ||||||
|  |         if (configuration.getThroughputWidth() != null) { | ||||||
|  |             throughputWidth = configuration.getThroughputWidth().toString(); | ||||||
|  |         } | ||||||
|  |         throughputWidthTextField.setText(throughputWidth); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								corefx/src/main/java/com/core/ui/dialogs/HookDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								corefx/src/main/java/com/core/ui/dialogs/HookDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.Hook; | ||||||
|  | import com.core.data.SessionState; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXComboBox; | ||||||
|  | import com.jfoenix.controls.JFXTextArea; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | public class HookDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final String DEFAULT_DATA = "#!/bin/sh\n" + | ||||||
|  |             "# session hook script; write commands here to execute\n" + | ||||||
|  |             "# on the host at the specified state\n"; | ||||||
|  |     @FXML private JFXComboBox<String> stateCombo; | ||||||
|  |     @FXML private JFXTextField fileTextField; | ||||||
|  |     @FXML private JFXTextArea fileData; | ||||||
|  |     private JFXButton saveButton; | ||||||
|  | 
 | ||||||
|  |     public HookDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/hook_dialog.fxml"); | ||||||
|  |         setTitle("Hook"); | ||||||
|  |         saveButton = createButton("Save"); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         stateCombo.getItems() | ||||||
|  |                 .addAll(Arrays.stream(SessionState.values()).map(Enum::name).sorted().collect(Collectors.toList())); | ||||||
|  |         stateCombo.getSelectionModel().select(SessionState.RUNTIME.name()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Hook getHook() { | ||||||
|  |         Hook hook = new Hook(); | ||||||
|  |         hook.setFile(fileTextField.getText()); | ||||||
|  |         hook.setData(fileData.getText()); | ||||||
|  |         SessionState state = SessionState.valueOf(stateCombo.getSelectionModel().getSelectedItem()); | ||||||
|  |         hook.setState(state.getValue()); | ||||||
|  |         hook.setStateDisplay(state.name()); | ||||||
|  |         return hook; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showEditDialog(Hook hook, Runnable editHandler, Runnable cancelHandler) { | ||||||
|  |         fileData.setText(hook.getData()); | ||||||
|  |         stateCombo.getSelectionModel().select(hook.getState()); | ||||||
|  |         fileTextField.setText(hook.getFile()); | ||||||
|  |         fileTextField.setDisable(true); | ||||||
|  | 
 | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             logger.info("create hook"); | ||||||
|  |             editHandler.run(); | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(String fileName, Runnable saveHandler, Runnable cancelHandler) { | ||||||
|  |         fileData.setText(DEFAULT_DATA); | ||||||
|  |         stateCombo.getSelectionModel().select(SessionState.RUNTIME.name()); | ||||||
|  |         fileTextField.setText(fileName); | ||||||
|  |         fileTextField.setDisable(false); | ||||||
|  | 
 | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             logger.info("create hook"); | ||||||
|  |             saveHandler.run(); | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										117
									
								
								corefx/src/main/java/com/core/ui/dialogs/HooksDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								corefx/src/main/java/com/core/ui/dialogs/HooksDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,117 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.Hook; | ||||||
|  | import com.core.data.SessionState; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.control.TableColumn; | ||||||
|  | import javafx.scene.control.TableView; | ||||||
|  | import javafx.scene.control.cell.PropertyValueFactory; | ||||||
|  | import javafx.stage.Stage; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | public class HooksDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private HookDialog hookDialog; | ||||||
|  |     private int fileCount = 0; | ||||||
|  |     @FXML private TableView<Hook> hooksTable; | ||||||
|  |     @FXML private TableColumn<Hook, Integer> fileColumn; | ||||||
|  |     @FXML private TableColumn<Hook, Integer> stateColumn; | ||||||
|  | 
 | ||||||
|  |     public HooksDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/hooks_dialog.fxml"); | ||||||
|  |         hookDialog = new HookDialog(controller); | ||||||
|  | 
 | ||||||
|  |         setTitle("Hooks"); | ||||||
|  | 
 | ||||||
|  |         JFXButton createButton = createButton("Create"); | ||||||
|  |         createButton.setOnAction(event -> { | ||||||
|  |             logger.info("showing create hook"); | ||||||
|  |             hookDialog.showDialog(nextFile(), saveHandler, cancelHandler); | ||||||
|  |         }); | ||||||
|  |         JFXButton editButton = createButton("Edit"); | ||||||
|  |         editButton.setDisable(true); | ||||||
|  |         editButton.setOnAction(event -> { | ||||||
|  |             logger.info("edit hook"); | ||||||
|  |             Hook hook = hooksTable.getSelectionModel().getSelectedItem(); | ||||||
|  |             hookDialog.showEditDialog(hook, editHandler, cancelHandler); | ||||||
|  |         }); | ||||||
|  |         JFXButton deleteButton = createButton("Delete"); | ||||||
|  |         deleteButton.setDisable(true); | ||||||
|  |         deleteButton.setOnAction(event -> { | ||||||
|  |             logger.info("delete hook"); | ||||||
|  |             Hook hook = hooksTable.getSelectionModel().getSelectedItem(); | ||||||
|  |             hooksTable.getItems().remove(hook); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         hooksTable.getSelectionModel().selectedItemProperty().addListener((ov, old, current) -> { | ||||||
|  |             boolean hasNoSelection = current == null; | ||||||
|  |             editButton.setDisable(hasNoSelection); | ||||||
|  |             deleteButton.setDisable(hasNoSelection); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         fileColumn.setCellValueFactory(new PropertyValueFactory<>("file")); | ||||||
|  |         stateColumn.setCellValueFactory(new PropertyValueFactory<>("stateDisplay")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void setOwner(Stage window) { | ||||||
|  |         super.setOwner(window); | ||||||
|  |         hookDialog.setOwner(window); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private Runnable saveHandler = () -> { | ||||||
|  |         Hook hook = hookDialog.getHook(); | ||||||
|  |         hooksTable.getItems().addAll(hook); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     private Runnable editHandler = () -> { | ||||||
|  |         Hook hook = hooksTable.getSelectionModel().getSelectedItem(); | ||||||
|  |         Hook update = hookDialog.getHook(); | ||||||
|  |         SessionState state = SessionState.valueOf(update.getStateDisplay()); | ||||||
|  |         hook.setState(state.getValue()); | ||||||
|  |         hook.setData(update.getData()); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     private Runnable cancelHandler = this::showDialog; | ||||||
|  | 
 | ||||||
|  |     private String nextFile() { | ||||||
|  |         return String.format("file%s.sh", ++fileCount); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Hook> getHooks() { | ||||||
|  |         return hooksTable.getItems(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void updateHooks() { | ||||||
|  |         logger.info("updating hooks"); | ||||||
|  |         hooksTable.getItems().clear(); | ||||||
|  | 
 | ||||||
|  |         // update hooks | ||||||
|  |         try { | ||||||
|  |             List<Hook> hooks = getCoreClient().getHooks(); | ||||||
|  |             for (Hook hook : hooks) { | ||||||
|  |                 SessionState state = SessionState.get(hook.getState()); | ||||||
|  |                 hook.setStateDisplay(state.name()); | ||||||
|  |                 hooksTable.getItems().add(hook); | ||||||
|  |             } | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error getting current hooks", ex); | ||||||
|  |             Toast.error("Error getting current hooks"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         // clear current selection | ||||||
|  |         hooksTable.getSelectionModel().clearSelection(); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								corefx/src/main/java/com/core/ui/dialogs/LocationDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								corefx/src/main/java/com/core/ui/dialogs/LocationDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.LocationConfig; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import com.jfoenix.validation.DoubleValidator; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | public class LocationDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private JFXTextField scaleTextField; | ||||||
|  |     @FXML private JFXTextField xTextField; | ||||||
|  |     @FXML private JFXTextField yTextField; | ||||||
|  |     @FXML private JFXTextField latTextField; | ||||||
|  |     @FXML private JFXTextField lonTextField; | ||||||
|  |     @FXML private JFXTextField altTextField; | ||||||
|  |     private JFXButton saveButton; | ||||||
|  | 
 | ||||||
|  |     public LocationDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/location_dialog.fxml"); | ||||||
|  |         setTitle("Location Configuration"); | ||||||
|  |         saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             boolean result = scaleTextField.validate(); | ||||||
|  |             if (!result) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             LocationConfig config = new LocationConfig(); | ||||||
|  |             config.setScale(getDouble(scaleTextField)); | ||||||
|  |             config.getPosition().setX(getDouble(xTextField)); | ||||||
|  |             config.getPosition().setY(getDouble(yTextField)); | ||||||
|  |             config.getLocation().setLatitude(getDouble(latTextField)); | ||||||
|  |             config.getLocation().setLongitude(getDouble(lonTextField)); | ||||||
|  |             config.getLocation().setAltitude(getDouble(altTextField)); | ||||||
|  |             try { | ||||||
|  |                 getCoreClient().setLocationConfig(config); | ||||||
|  |                 close(); | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("error setting location config", ex); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         DoubleValidator validator = new DoubleValidator(); | ||||||
|  |         scaleTextField.getValidators().add(validator); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Double getDouble(JFXTextField textField) { | ||||||
|  |         return Double.parseDouble(textField.getText()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         try { | ||||||
|  |             LocationConfig config = getCoreClient().getLocationConfig(); | ||||||
|  |             scaleTextField.setText(config.getScale().toString()); | ||||||
|  |             xTextField.setText(config.getPosition().getX().toString()); | ||||||
|  |             yTextField.setText(config.getPosition().getY().toString()); | ||||||
|  |             latTextField.setText(config.getLocation().getLatitude().toString()); | ||||||
|  |             lonTextField.setText(config.getLocation().getLongitude().toString()); | ||||||
|  |             altTextField.setText(config.getLocation().getAltitude().toString()); | ||||||
|  |             show(); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("error getting location config", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										113
									
								
								corefx/src/main/java/com/core/ui/dialogs/MobilityDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								corefx/src/main/java/com/core/ui/dialogs/MobilityDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,113 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.data.MobilityConfig; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import com.jfoenix.controls.JFXToggleButton; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.layout.GridPane; | ||||||
|  | import javafx.stage.FileChooser; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class MobilityDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private JFXTextField fileTextField; | ||||||
|  |     @FXML private JFXTextField refreshTextField; | ||||||
|  |     @FXML private JFXToggleButton loopToggleButton; | ||||||
|  |     @FXML private JFXTextField nodeMappingTextField; | ||||||
|  |     @FXML private JFXTextField autoStartTextField; | ||||||
|  |     @FXML private JFXTextField startTextField; | ||||||
|  |     @FXML private JFXTextField pauseTextField; | ||||||
|  |     @FXML private JFXTextField stopTextField; | ||||||
|  |     private CoreNode node; | ||||||
|  | 
 | ||||||
|  |     public MobilityDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/mobility_dialog.fxml"); | ||||||
|  |         setTitle("Mobility Script"); | ||||||
|  | 
 | ||||||
|  |         JFXButton saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             MobilityConfig mobilityConfig = new MobilityConfig(); | ||||||
|  |             mobilityConfig.setFile(fileTextField.getText()); | ||||||
|  |             mobilityConfig.setScriptFile(new File(mobilityConfig.getFile())); | ||||||
|  |             mobilityConfig.setAutostart(autoStartTextField.getText()); | ||||||
|  |             String loop = loopToggleButton.isSelected() ? "1" : ""; | ||||||
|  |             mobilityConfig.setLoop(loop); | ||||||
|  |             mobilityConfig.setRefresh(Integer.parseInt(refreshTextField.getText())); | ||||||
|  |             mobilityConfig.setMap(nodeMappingTextField.getText()); | ||||||
|  |             mobilityConfig.setStartScript(startTextField.getText()); | ||||||
|  |             mobilityConfig.setPauseScript(pauseTextField.getText()); | ||||||
|  |             mobilityConfig.setStopScript(stopTextField.getText()); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 boolean result = controller.getCoreClient().setMobilityConfig(node, mobilityConfig); | ||||||
|  |                 if (result) { | ||||||
|  |                     getController().getMobilityScripts().put(node.getId(), mobilityConfig); | ||||||
|  |                     Toast.info(String.format("Set mobility configuration for %s", node.getName())); | ||||||
|  |                 } else { | ||||||
|  |                     Toast.error(String.format("Error setting mobility configuration for %s", node.getName())); | ||||||
|  |                 } | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 Toast.error("error setting mobility configuration", ex); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @FXML | ||||||
|  |     private void onSelectAction(ActionEvent event) { | ||||||
|  |         JFXButton button = (JFXButton) event.getSource(); | ||||||
|  |         GridPane gridPane = (GridPane) button.getParent(); | ||||||
|  |         JFXTextField textField = (JFXTextField) gridPane.getChildren().get(0); | ||||||
|  | 
 | ||||||
|  |         FileChooser fileChooser = new FileChooser(); | ||||||
|  |         fileChooser.setTitle("Select File"); | ||||||
|  |         String mobilityPath = getController().getConfiguration().getMobilityPath(); | ||||||
|  |         fileChooser.setInitialDirectory(new File(mobilityPath)); | ||||||
|  |         fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Mobility", | ||||||
|  |                 "*.scen")); | ||||||
|  |         try { | ||||||
|  |             File file = fileChooser.showOpenDialog(getController().getWindow()); | ||||||
|  |             if (file != null) { | ||||||
|  |                 logger.info("opening session xml: {}", file.getPath()); | ||||||
|  |                 textField.setText(file.getPath()); | ||||||
|  |             } | ||||||
|  |         } catch (IllegalArgumentException ex) { | ||||||
|  |             Toast.error(String.format("Invalid mobility directory: %s", | ||||||
|  |                     getController().getConfiguration().getMobilityPath())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(CoreNode node) { | ||||||
|  |         this.node = node; | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             MobilityConfig mobilityConfig = getController().getCoreClient().getMobilityConfig(this.node); | ||||||
|  |             fileTextField.setText(mobilityConfig.getFile()); | ||||||
|  |             autoStartTextField.setText(mobilityConfig.getAutostart()); | ||||||
|  |             boolean loop = "1".equals(mobilityConfig.getLoop()); | ||||||
|  |             loopToggleButton.setSelected(loop); | ||||||
|  |             refreshTextField.setText(mobilityConfig.getRefresh().toString()); | ||||||
|  |             nodeMappingTextField.setText(mobilityConfig.getMap()); | ||||||
|  |             startTextField.setText(mobilityConfig.getStartScript()); | ||||||
|  |             pauseTextField.setText(mobilityConfig.getPauseScript()); | ||||||
|  |             stopTextField.setText(mobilityConfig.getStopScript()); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("error getting mobility config", ex); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,89 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.data.MobilityConfig; | ||||||
|  | import com.core.data.SessionState; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.core.utils.IconUtils; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXProgressBar; | ||||||
|  | import javafx.animation.KeyFrame; | ||||||
|  | import javafx.animation.KeyValue; | ||||||
|  | import javafx.animation.Timeline; | ||||||
|  | import javafx.application.Platform; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.control.Label; | ||||||
|  | import javafx.stage.Modality; | ||||||
|  | import javafx.util.Duration; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class MobilityPlayerDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final int ICON_SIZE = 20; | ||||||
|  |     private static final String ICON_FILL = "white"; | ||||||
|  |     @FXML private Label label; | ||||||
|  |     @FXML private JFXButton playButton; | ||||||
|  |     @FXML private JFXButton pauseButton; | ||||||
|  |     @FXML private JFXButton stopButton; | ||||||
|  |     @FXML private JFXProgressBar progressBar; | ||||||
|  |     private final CoreNode node; | ||||||
|  |     private MobilityConfig mobilityConfig; | ||||||
|  | 
 | ||||||
|  |     public MobilityPlayerDialog(Controller controller, CoreNode node) { | ||||||
|  |         super(controller, "/fxml/mobility_player.fxml", Modality.NONE); | ||||||
|  |         this.node = node; | ||||||
|  | 
 | ||||||
|  |         playButton.setGraphic(IconUtils.get("play_arrow", ICON_SIZE, ICON_FILL)); | ||||||
|  |         playButton.setOnAction(event -> action("start")); | ||||||
|  |         pauseButton.setGraphic(IconUtils.get("pause", ICON_SIZE, ICON_FILL)); | ||||||
|  |         pauseButton.setOnAction(event -> action("pause")); | ||||||
|  |         stopButton.setGraphic(IconUtils.get("stop", ICON_SIZE, ICON_FILL)); | ||||||
|  |         stopButton.setOnAction(event -> action("stop")); | ||||||
|  | 
 | ||||||
|  |         addCancelButton(); | ||||||
|  |         setTitle(String.format("%s Mobility Script", node.getName())); | ||||||
|  |         getStage().sizeToScene(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void event(SessionState state, Integer start, Integer end) { | ||||||
|  |         Platform.runLater(() -> { | ||||||
|  |             playButton.setDisable(false); | ||||||
|  |             stopButton.setDisable(false); | ||||||
|  | 
 | ||||||
|  |             switch (state) { | ||||||
|  |                 case START: | ||||||
|  |                     playButton.setDisable(true); | ||||||
|  |                     progressBar.setProgress(0); | ||||||
|  |                     Timeline timeline = new Timeline(); | ||||||
|  |                     KeyValue keyValue = new KeyValue(progressBar.progressProperty(), 1.0); | ||||||
|  |                     KeyFrame keyFrame = new KeyFrame(new Duration(end * 1000), keyValue); | ||||||
|  |                     timeline.getKeyFrames().add(keyFrame); | ||||||
|  |                     timeline.play(); | ||||||
|  |                     break; | ||||||
|  |                 case STOP: | ||||||
|  |                     stopButton.setDisable(true); | ||||||
|  |                     break; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void action(String action) { | ||||||
|  |         try { | ||||||
|  |             getCoreClient().mobilityAction(node, action); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error(String.format("mobility error: %s", action), ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(MobilityConfig mobilityConfig) { | ||||||
|  |         this.label.setText(mobilityConfig.getFile()); | ||||||
|  |         this.mobilityConfig = mobilityConfig; | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										103
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeEmaneDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeEmaneDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.ConfigGroup; | ||||||
|  | import com.core.data.ConfigOption; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXComboBox; | ||||||
|  | import javafx.event.ActionEvent; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | public class NodeEmaneDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final JFXButton saveButton; | ||||||
|  |     private CoreNode coreNode; | ||||||
|  |     @FXML private JFXComboBox<String> modelCombo; | ||||||
|  |     @FXML private JFXButton modelButton; | ||||||
|  |     @FXML private JFXButton emaneButton; | ||||||
|  | 
 | ||||||
|  |     public NodeEmaneDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/node_emane_dialog.fxml"); | ||||||
|  | 
 | ||||||
|  |         saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             String model = modelCombo.getSelectionModel().getSelectedItem(); | ||||||
|  |             coreNode.setEmane(model); | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         emaneButton.setOnAction(this::emaneButtonHandler); | ||||||
|  |         modelButton.setOnAction(this::emaneModelButtonHandler); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setModels(List<String> models) { | ||||||
|  |         models.sort(String::compareTo); | ||||||
|  |         modelCombo.getItems().setAll(models); | ||||||
|  |         modelCombo.getSelectionModel().selectFirst(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<String> getModels() { | ||||||
|  |         return modelCombo.getItems(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void emaneButtonHandler(ActionEvent event) { | ||||||
|  |         try { | ||||||
|  |             List<ConfigGroup> configGroups = getCoreClient().getEmaneConfig(coreNode); | ||||||
|  |             logger.debug("emane model config: {}", configGroups); | ||||||
|  |             String title = String.format("%s EMANE Config", coreNode.getName()); | ||||||
|  |             getController().getConfigDialog().showDialog(title, configGroups, () -> { | ||||||
|  |                 List<ConfigOption> options = getController().getConfigDialog().getOptions(); | ||||||
|  |                 try { | ||||||
|  |                     getCoreClient().setEmaneConfig(coreNode, options); | ||||||
|  |                 } catch (IOException ex) { | ||||||
|  |                     logger.error("set emane config error", ex); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("error getting emane model config", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void emaneModelButtonHandler(ActionEvent event) { | ||||||
|  |         String model = modelCombo.getSelectionModel().getSelectedItem(); | ||||||
|  |         displayEmaneModelConfig(coreNode.getId(), model); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void displayEmaneModelConfig(Integer id, String model) { | ||||||
|  |         try { | ||||||
|  |             List<ConfigGroup> configGroups = getCoreClient().getEmaneModelConfig(id, model); | ||||||
|  |             logger.debug("emane model config: {}", configGroups); | ||||||
|  |             String title = String.format("EMANE(%s) %s Config", id, model); | ||||||
|  |             getController().getConfigDialog().showDialog(title, configGroups, () -> { | ||||||
|  |                 List<ConfigOption> options = getController().getConfigDialog().getOptions(); | ||||||
|  |                 try { | ||||||
|  |                     getCoreClient().setEmaneModelConfig(id, model, options); | ||||||
|  |                 } catch (IOException ex) { | ||||||
|  |                     Toast.error("set emane model config error", ex); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             Toast.error("error getting emane model config", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setDisabled(boolean isDisabled) { | ||||||
|  |         saveButton.setDisable(isDisabled); | ||||||
|  |         modelCombo.setDisable(isDisabled); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(CoreNode node) { | ||||||
|  |         coreNode = node; | ||||||
|  |         setTitle(String.format("%s - EMANE", node.getName())); | ||||||
|  |         setDisabled(getCoreClient().isRunning()); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										148
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeServicesDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeServicesDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,148 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.ui.ServiceItem; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXListView; | ||||||
|  | import com.jfoenix.controls.JFXScrollPane; | ||||||
|  | import javafx.collections.FXCollections; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.control.ScrollPane; | ||||||
|  | import javafx.scene.layout.GridPane; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.*; | ||||||
|  | 
 | ||||||
|  | public class NodeServicesDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final Map<String, List<ServiceItem>> serviceItemGroups = new HashMap<>(); | ||||||
|  |     private final Map<String, ServiceItem> serviceItemMap = new HashMap<>(); | ||||||
|  |     private CoreNode node; | ||||||
|  |     private int index = 0; | ||||||
|  |     @FXML private GridPane gridPane; | ||||||
|  |     @FXML private ScrollPane scrollPane; | ||||||
|  |     @FXML private JFXListView<String> groupListView; | ||||||
|  |     @FXML private JFXListView<String> activeListView; | ||||||
|  |     @FXML private JFXButton removeButton; | ||||||
|  |     @FXML private JFXButton editButton; | ||||||
|  | 
 | ||||||
|  |     public NodeServicesDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/node_services_dialog.fxml"); | ||||||
|  | 
 | ||||||
|  |         JFXButton saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             for (List<ServiceItem> items : serviceItemGroups.values()) { | ||||||
|  |                 for (ServiceItem item : items) { | ||||||
|  |                     if (item.getCheckBox().isSelected()) { | ||||||
|  |                         logger.info("setting service for node({}): {}", node.getName(), item.getService()); | ||||||
|  |                         node.getServices().add(item.getService()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         groupListView.getSelectionModel().selectedItemProperty().addListener((ov, previous, current) -> { | ||||||
|  |             if (current == null) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             updateItems(current); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         activeListView.getSelectionModel().selectedItemProperty().addListener((ov, previous, current) -> { | ||||||
|  |             boolean isDisabled = current == null; | ||||||
|  |             removeButton.setDisable(isDisabled); | ||||||
|  |             editButton.setDisable(isDisabled); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         removeButton.setOnAction(event -> { | ||||||
|  |             String service = activeListView.getSelectionModel().getSelectedItem(); | ||||||
|  |             activeListView.getItems().remove(service); | ||||||
|  |             ServiceItem serviceItem = serviceItemMap.get(service); | ||||||
|  |             serviceItem.getCheckBox().setSelected(false); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         editButton.setOnAction(event -> { | ||||||
|  |             String service = activeListView.getSelectionModel().getSelectedItem(); | ||||||
|  |             getController().getServiceDialog().showDialog(node, service); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setServices(Map<String, List<String>> serviceGroups) { | ||||||
|  |         serviceItemGroups.clear(); | ||||||
|  | 
 | ||||||
|  |         serviceGroups.keySet().stream() | ||||||
|  |                 .sorted() | ||||||
|  |                 .forEach(group -> { | ||||||
|  |                     groupListView.getItems().add(group); | ||||||
|  |                     serviceGroups.get(group).stream() | ||||||
|  |                             .sorted() | ||||||
|  |                             .forEach(service -> { | ||||||
|  |                                 ServiceItem serviceItem = new ServiceItem(service); | ||||||
|  |                                 List<ServiceItem> items = serviceItemGroups.computeIfAbsent( | ||||||
|  |                                         group, k -> new ArrayList<>()); | ||||||
|  |                                 items.add(serviceItem); | ||||||
|  | 
 | ||||||
|  |                                 if (serviceItem.getCheckBox().isSelected()) { | ||||||
|  |                                     activeListView.getItems().add(serviceItem.getService()); | ||||||
|  |                                 } | ||||||
|  | 
 | ||||||
|  |                                 serviceItem.getCheckBox().setOnAction(event -> { | ||||||
|  |                                     if (serviceItem.getCheckBox().isSelected()) { | ||||||
|  |                                         activeListView.getItems().add(service); | ||||||
|  |                                         FXCollections.sort(activeListView.getItems()); | ||||||
|  |                                     } else { | ||||||
|  |                                         activeListView.getItems().remove(service); | ||||||
|  |                                     } | ||||||
|  |                                 }); | ||||||
|  | 
 | ||||||
|  |                                 serviceItemMap.put(service, serviceItem); | ||||||
|  |                             }); | ||||||
|  |                 }); | ||||||
|  |         groupListView.getSelectionModel().selectFirst(); | ||||||
|  |         JFXScrollPane.smoothScrolling(scrollPane); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void updateItems(String group) { | ||||||
|  |         logger.debug("updating services for group: {}", group); | ||||||
|  |         clearAvailableServices(); | ||||||
|  |         List<ServiceItem> items = serviceItemGroups.get(group); | ||||||
|  |         for (ServiceItem item : items) { | ||||||
|  |             gridPane.addRow(index++, item.getCheckBox()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void clearAvailableServices() { | ||||||
|  |         gridPane.getChildren().clear(); | ||||||
|  |         index = 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(CoreNode node) { | ||||||
|  |         this.node = node; | ||||||
|  |         setTitle(String.format("%s - Services", node.getName())); | ||||||
|  |         groupListView.getSelectionModel().selectFirst(); | ||||||
|  |         activeListView.getItems().clear(); | ||||||
|  | 
 | ||||||
|  |         Set<String> nodeServices = node.getServices(); | ||||||
|  |         if (nodeServices.isEmpty()) { | ||||||
|  |             nodeServices = getController().getDefaultServices().get(node.getModel()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         for (List<ServiceItem> items : serviceItemGroups.values()) { | ||||||
|  |             for (ServiceItem item : items) { | ||||||
|  |                 boolean selected = nodeServices.contains(item.getService()); | ||||||
|  |                 item.getCheckBox().setSelected(selected); | ||||||
|  |                 if (item.getCheckBox().isSelected()) { | ||||||
|  |                     activeListView.getItems().add(item.getService()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         FXCollections.sort(activeListView.getItems()); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,74 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.NodeType; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXListView; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.control.SelectionMode; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class NodeTypeCreateDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private JFXListView<String> servicesListView; | ||||||
|  |     @FXML private JFXTextField modelTextField; | ||||||
|  |     @FXML private JFXTextField displayTextField; | ||||||
|  |     private Runnable onCreateHandler; | ||||||
|  | 
 | ||||||
|  |     public NodeTypeCreateDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/node_type_create_dialog.fxml"); | ||||||
|  |         setTitle("Create Node Configuration"); | ||||||
|  | 
 | ||||||
|  |         JFXButton saveButton = createButton("Create"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             onCreateHandler.run(); | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         servicesListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); | ||||||
|  |         displayTextField.focusedProperty().addListener((obs, prev, current) -> { | ||||||
|  |             if (!current) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             String model = modelTextField.getText(); | ||||||
|  |             if (!model.isEmpty()) { | ||||||
|  |                 displayTextField.setText(model.substring(0, 1).toUpperCase() + model.substring(1)); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public NodeType getCreatedNodeType() { | ||||||
|  |         NodeType nodeType = new NodeType(NodeType.DEFAULT, modelTextField.getText(), displayTextField.getText(), | ||||||
|  |                 "/icons/host-100.png"); | ||||||
|  |         nodeType.getServices().addAll(servicesListView.getSelectionModel().getSelectedItems()); | ||||||
|  |         return nodeType; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setServices(Map<String, List<String>> serviceGroups) { | ||||||
|  |         List<String> services = new ArrayList<>(); | ||||||
|  |         for (List<String> groupServices : serviceGroups.values()) { | ||||||
|  |             services.addAll(groupServices); | ||||||
|  |         } | ||||||
|  |         services.sort(String::compareTo); | ||||||
|  |         servicesListView.getItems().setAll(services); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public void showDialog(Runnable runnable) { | ||||||
|  |         onCreateHandler = runnable; | ||||||
|  |         modelTextField.setText(""); | ||||||
|  |         displayTextField.setText(""); | ||||||
|  |         servicesListView.getSelectionModel().clearSelection(); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										136
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeTypesDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeTypesDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,136 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.data.NodeType; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.core.utils.NodeTypeConfig; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXListView; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.image.Image; | ||||||
|  | import javafx.scene.image.ImageView; | ||||||
|  | import javafx.stage.FileChooser; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.File; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.Set; | ||||||
|  | 
 | ||||||
|  | public class NodeTypesDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final Map<String, NodeType> nodeTypeMap = new HashMap<>(); | ||||||
|  |     private NodeType selectedNodeType; | ||||||
|  |     @FXML private JFXListView<String> listView; | ||||||
|  |     @FXML private JFXTextField modelTextField; | ||||||
|  |     @FXML private JFXTextField displayTextField; | ||||||
|  |     @FXML private JFXTextField iconTextField; | ||||||
|  |     @FXML private JFXButton iconButton; | ||||||
|  |     @FXML private ImageView iconImage; | ||||||
|  |     @FXML private JFXButton saveButton; | ||||||
|  |     @FXML private JFXButton addButton; | ||||||
|  |     @FXML private JFXButton deleteButton; | ||||||
|  |     @FXML private JFXListView<String> nodeServicesListView; | ||||||
|  | 
 | ||||||
|  |     public NodeTypesDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/node_types_dialog.fxml"); | ||||||
|  |         setTitle("Node Configuration"); | ||||||
|  |         JFXButton closeButton = createButton("Close"); | ||||||
|  |         closeButton.setOnAction(event -> close()); | ||||||
|  | 
 | ||||||
|  |         listView.getSelectionModel().selectedItemProperty().addListener((ov, prev, current) -> { | ||||||
|  |             if (current == null) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             NodeType nodeType = nodeTypeMap.get(current); | ||||||
|  |             modelTextField.setText(nodeType.getModel()); | ||||||
|  |             displayTextField.setText(nodeType.getDisplay()); | ||||||
|  |             iconTextField.setText(nodeType.getIcon()); | ||||||
|  |             iconImage.setImage(new Image(nodeType.getIcon())); | ||||||
|  |             selectedNodeType = nodeType; | ||||||
|  |             Set<String> services = nodeType.getServices(); | ||||||
|  |             nodeServicesListView.getItems().setAll(services); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         iconButton.setOnAction(event -> { | ||||||
|  |             FileChooser fileChooser = new FileChooser(); | ||||||
|  |             fileChooser.setTitle("Select Icon"); | ||||||
|  |             fileChooser.setInitialDirectory(new File(getController().getConfiguration().getIconPath())); | ||||||
|  |             fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("PNG", "*.png")); | ||||||
|  |             File file = fileChooser.showOpenDialog(controller.getWindow()); | ||||||
|  |             if (file != null) { | ||||||
|  |                 String uri = file.toURI().toString(); | ||||||
|  |                 iconImage.setImage(new Image(uri)); | ||||||
|  |                 iconTextField.setText(uri); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             String iconPath = iconTextField.getText(); | ||||||
|  |             selectedNodeType.setIcon(iconPath); | ||||||
|  |             for (CoreNode node : controller.getNetworkGraph().getGraph().getVertices()) { | ||||||
|  |                 if (selectedNodeType != node.getNodeType()) { | ||||||
|  |                     continue; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 node.setNodeType(selectedNodeType); | ||||||
|  |             } | ||||||
|  |             controller.getNetworkGraph().getGraphViewer().repaint(); | ||||||
|  |             controller.getGraphToolbar().updateNodeType(selectedNodeType.getId(), iconPath); | ||||||
|  |             Toast.info(String.format("Node %s Updated", selectedNodeType.getDisplay())); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         deleteButton.setOnAction(event -> { | ||||||
|  |             String display = listView.getSelectionModel().getSelectedItem(); | ||||||
|  |             NodeType nodeType = nodeTypeMap.get(display); | ||||||
|  |             NodeType.remove(nodeType); | ||||||
|  |             listView.getItems().remove(display); | ||||||
|  |             NodeTypeConfig nodeTypeConfig = createNodeTypeConfig(nodeType); | ||||||
|  |             getController().getDefaultServices().remove(nodeTypeConfig.getModel()); | ||||||
|  |             getController().getConfiguration().getNodeTypeConfigs().remove(nodeTypeConfig); | ||||||
|  |             getController().updateNodeTypes(); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         addButton.setOnAction(event -> { | ||||||
|  |             NodeTypeCreateDialog nodeTypeCreateDialog = getController().getNodeTypeCreateDialog(); | ||||||
|  |             nodeTypeCreateDialog.showDialog(() -> { | ||||||
|  |                 NodeType nodeType = nodeTypeCreateDialog.getCreatedNodeType(); | ||||||
|  |                 NodeType.add(nodeType); | ||||||
|  |                 nodeTypeMap.put(nodeType.getDisplay(), nodeType); | ||||||
|  |                 listView.getItems().add(nodeType.getDisplay()); | ||||||
|  |                 NodeTypeConfig nodeTypeConfig = createNodeTypeConfig(nodeType); | ||||||
|  |                 getController().getDefaultServices().put(nodeTypeConfig.getModel(), nodeTypeConfig.getServices()); | ||||||
|  |                 getController().getConfiguration().getNodeTypeConfigs().add(nodeTypeConfig); | ||||||
|  |                 getController().updateNodeTypes(); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private NodeTypeConfig createNodeTypeConfig(NodeType nodeType) { | ||||||
|  |         return new NodeTypeConfig( | ||||||
|  |                 nodeType.getModel(), | ||||||
|  |                 nodeType.getDisplay(), | ||||||
|  |                 nodeType.getIcon(), | ||||||
|  |                 nodeType.getServices() | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() { | ||||||
|  |         listView.getItems().clear(); | ||||||
|  |         nodeTypeMap.clear(); | ||||||
|  |         for (NodeType nodeType : NodeType.getAll()) { | ||||||
|  |             if (nodeType.getValue() != NodeType.DEFAULT) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             nodeTypeMap.put(nodeType.getDisplay(), nodeType); | ||||||
|  |             listView.getItems().add(nodeType.getDisplay()); | ||||||
|  |         } | ||||||
|  |         listView.getSelectionModel().selectFirst(); | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										76
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeWlanDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								corefx/src/main/java/com/core/ui/dialogs/NodeWlanDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.client.rest.WlanConfig; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | public class NodeWlanDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final JFXButton saveButton; | ||||||
|  |     private CoreNode coreNode; | ||||||
|  |     @FXML private JFXTextField rangeTextField; | ||||||
|  |     @FXML private JFXTextField bandwidthTextField; | ||||||
|  |     @FXML private JFXTextField delayTextField; | ||||||
|  |     @FXML private JFXTextField lossTextField; | ||||||
|  |     @FXML private JFXTextField jitterTextField; | ||||||
|  | 
 | ||||||
|  |     public NodeWlanDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/wlan_dialog.fxml"); | ||||||
|  | 
 | ||||||
|  |         saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             try { | ||||||
|  |                 WlanConfig config = new WlanConfig(); | ||||||
|  |                 config.setRange(rangeTextField.getText()); | ||||||
|  |                 config.setBandwidth(bandwidthTextField.getText()); | ||||||
|  |                 config.setJitter(jitterTextField.getText()); | ||||||
|  |                 config.setDelay(delayTextField.getText()); | ||||||
|  |                 config.setError(lossTextField.getText()); | ||||||
|  |                 getCoreClient().setWlanConfig(coreNode, config); | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 logger.error("error setting wlan config", ex); | ||||||
|  |                 Toast.error("Error setting wlan config"); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void setDisabled(boolean isDisabled) { | ||||||
|  |         rangeTextField.setDisable(isDisabled); | ||||||
|  |         bandwidthTextField.setDisable(isDisabled); | ||||||
|  |         jitterTextField.setDisable(isDisabled); | ||||||
|  |         delayTextField.setDisable(isDisabled); | ||||||
|  |         lossTextField.setDisable(isDisabled); | ||||||
|  |         saveButton.setDisable(isDisabled); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(CoreNode node) { | ||||||
|  |         coreNode = node; | ||||||
|  |         setTitle(String.format("%s - WLAN", node.getName())); | ||||||
|  |         setDisabled(getCoreClient().isRunning()); | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             WlanConfig wlanConfig = getCoreClient().getWlanConfig(coreNode); | ||||||
|  |             rangeTextField.setText(wlanConfig.getRange()); | ||||||
|  |             bandwidthTextField.setText(wlanConfig.getBandwidth()); | ||||||
|  |             jitterTextField.setText(wlanConfig.getJitter()); | ||||||
|  |             delayTextField.setText(wlanConfig.getDelay()); | ||||||
|  |             lossTextField.setText(wlanConfig.getError()); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error getting wlan config", ex); | ||||||
|  |             Toast.error("Error getting wlan config"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										119
									
								
								corefx/src/main/java/com/core/ui/dialogs/ServiceDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								corefx/src/main/java/com/core/ui/dialogs/ServiceDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,119 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.client.rest.ServiceFile; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.data.CoreService; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXComboBox; | ||||||
|  | import com.jfoenix.controls.JFXTextArea; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | public class ServiceDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private CoreNode coreNode; | ||||||
|  |     private CoreService coreService; | ||||||
|  |     private String serviceName; | ||||||
|  |     @FXML private JFXComboBox<String> executablesComboBox; | ||||||
|  |     @FXML private JFXComboBox<String> dependenciesComboBox; | ||||||
|  |     @FXML private JFXTextField validationModeTextField; | ||||||
|  |     @FXML private JFXTextField validationTimerTextField; | ||||||
|  |     @FXML private JFXComboBox<String> directoriesComboBox; | ||||||
|  |     @FXML private JFXComboBox<String> filesComboBox; | ||||||
|  |     @FXML private JFXTextArea fileTextArea; | ||||||
|  |     @FXML private JFXTextArea startupTextArea; | ||||||
|  |     @FXML private JFXTextArea validateTextArea; | ||||||
|  |     @FXML private JFXTextArea shutdownTextArea; | ||||||
|  | 
 | ||||||
|  |     public ServiceDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/service_dialog.fxml"); | ||||||
|  | 
 | ||||||
|  |         JFXButton saveButton = createButton("Save"); | ||||||
|  |         saveButton.setOnAction(event -> { | ||||||
|  |             // retrieve service data | ||||||
|  |             coreService.setStartup(textToList(startupTextArea.getText())); | ||||||
|  |             coreService.setValidate(textToList(validateTextArea.getText())); | ||||||
|  |             coreService.setShutdown(textToList(shutdownTextArea.getText())); | ||||||
|  | 
 | ||||||
|  |             // service file data | ||||||
|  |             String fileName = filesComboBox.getSelectionModel().getSelectedItem(); | ||||||
|  |             String data = fileTextArea.getText(); | ||||||
|  |             ServiceFile serviceFile = new ServiceFile(fileName, data); | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 getCoreClient().setService(coreNode, serviceName, coreService); | ||||||
|  |                 getCoreClient().setServiceFile(coreNode, serviceName, serviceFile); | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 logger.error("error setting node service", ex); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             close(); | ||||||
|  |         }); | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         filesComboBox.valueProperty().addListener((ov, previous, current) -> { | ||||||
|  |             if (current == null) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 String file = controller.getCoreClient().getServiceFile(coreNode, serviceName, current); | ||||||
|  |                 fileTextArea.setText(file); | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 logger.error("error getting file data", ex); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private List<String> textToList(String text) { | ||||||
|  |         return Arrays.stream(text.split("\\n")) | ||||||
|  |                 .filter(x -> !x.isEmpty()) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(CoreNode node, String service) { | ||||||
|  |         setTitle(String.format("%s - %s", node.getName(), service)); | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             coreNode = node; | ||||||
|  | 
 | ||||||
|  |             // node must exist to get file data | ||||||
|  |             getCoreClient().createNode(node); | ||||||
|  | 
 | ||||||
|  |             coreService = getCoreClient().getService(node, service); | ||||||
|  |             logger.info("service dialog: {}", coreService); | ||||||
|  |             serviceName = service; | ||||||
|  | 
 | ||||||
|  |             directoriesComboBox.getItems().setAll(coreService.getDirs()); | ||||||
|  |             directoriesComboBox.getSelectionModel().selectFirst(); | ||||||
|  | 
 | ||||||
|  |             executablesComboBox.getItems().setAll(coreService.getExecutables()); | ||||||
|  |             executablesComboBox.getSelectionModel().selectFirst(); | ||||||
|  | 
 | ||||||
|  |             dependenciesComboBox.getItems().setAll(coreService.getDependencies()); | ||||||
|  |             dependenciesComboBox.getSelectionModel().selectFirst(); | ||||||
|  | 
 | ||||||
|  |             validationModeTextField.setText(coreService.getValidationMode()); | ||||||
|  |             validationTimerTextField.setText(coreService.getValidationTimer()); | ||||||
|  | 
 | ||||||
|  |             filesComboBox.getItems().setAll(coreService.getConfigs()); | ||||||
|  |             filesComboBox.getSelectionModel().selectFirst(); | ||||||
|  | 
 | ||||||
|  |             startupTextArea.setText(String.join("\n", coreService.getStartup())); | ||||||
|  |             validateTextArea.setText(String.join("\n", coreService.getValidate())); | ||||||
|  |             shutdownTextArea.setText(String.join("\n", coreService.getShutdown())); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error getting service data", ex); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										177
									
								
								corefx/src/main/java/com/core/ui/dialogs/SessionsDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								corefx/src/main/java/com/core/ui/dialogs/SessionsDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,177 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.SessionOverview; | ||||||
|  | import com.core.data.SessionState; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import javafx.concurrent.Task; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.control.TableColumn; | ||||||
|  | import javafx.scene.control.TableView; | ||||||
|  | import javafx.scene.control.cell.PropertyValueFactory; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.concurrent.ExecutorService; | ||||||
|  | import java.util.concurrent.Executors; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | public class SessionsDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private TableView<SessionRow> sessionsTable; | ||||||
|  |     @FXML private TableColumn<SessionRow, Integer> sessionIdColumn; | ||||||
|  |     @FXML private TableColumn<SessionRow, String> stateColumn; | ||||||
|  |     @FXML private TableColumn<SessionRow, Integer> nodeCountColumn; | ||||||
|  |     private final ExecutorService executorService = Executors.newSingleThreadExecutor(); | ||||||
|  | 
 | ||||||
|  |     public SessionsDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/sessions_dialog.fxml"); | ||||||
|  |         setTitle("Sessions"); | ||||||
|  | 
 | ||||||
|  |         // add dialog buttons | ||||||
|  |         JFXButton createButton = createButton("New"); | ||||||
|  |         createButton.setOnAction(event -> { | ||||||
|  |             logger.info("creating new session"); | ||||||
|  |             executorService.submit(new CreateSessionTask()); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         JFXButton deleteButton = createButton("Delete"); | ||||||
|  |         deleteButton.setDisable(true); | ||||||
|  |         deleteButton.setOnAction(event -> { | ||||||
|  |             SessionRow row = sessionsTable.getSelectionModel().getSelectedItem(); | ||||||
|  |             Integer sessionId = row.getId(); | ||||||
|  |             logger.info("deleting session: {}", sessionId); | ||||||
|  |             executorService.submit(new DeleteSessionTask(row, sessionId)); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         JFXButton joinButton = createButton("Join"); | ||||||
|  |         joinButton.setDisable(true); | ||||||
|  |         joinButton.setOnAction(event -> { | ||||||
|  |             SessionRow row = sessionsTable.getSelectionModel().getSelectedItem(); | ||||||
|  |             Integer sessionId = row.getId(); | ||||||
|  |             logger.info("joining session: {}", sessionId); | ||||||
|  |             executorService.submit(new JoinSessionTask(sessionId)); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         addCancelButton(); | ||||||
|  | 
 | ||||||
|  |         // update table cell factories | ||||||
|  |         sessionIdColumn.setCellValueFactory(new PropertyValueFactory<>("id")); | ||||||
|  |         stateColumn.setCellValueFactory(new PropertyValueFactory<>("state")); | ||||||
|  |         nodeCountColumn.setCellValueFactory(new PropertyValueFactory<>("nodes")); | ||||||
|  | 
 | ||||||
|  |         // handle table row selection | ||||||
|  |         sessionsTable.getSelectionModel().selectedItemProperty().addListener((ov, prev, current) -> { | ||||||
|  |             if (current != null) { | ||||||
|  |                 boolean isCurrentSession = current.getId().equals(controller.getCoreClient().currentSession()); | ||||||
|  |                 deleteButton.setDisable(isCurrentSession); | ||||||
|  |                 joinButton.setDisable(isCurrentSession); | ||||||
|  |             } else { | ||||||
|  |                 deleteButton.setDisable(true); | ||||||
|  |                 joinButton.setDisable(true); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private class CreateSessionTask extends Task<Integer> { | ||||||
|  |         @Override | ||||||
|  |         protected Integer call() throws Exception { | ||||||
|  |             SessionOverview sessionOverview = getCoreClient().createSession(); | ||||||
|  |             Integer sessionId = sessionOverview.getId(); | ||||||
|  |             getController().joinSession(sessionId); | ||||||
|  |             return sessionId; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void succeeded() { | ||||||
|  |             Toast.success(String.format("Created Session %s", getValue())); | ||||||
|  |             close(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void failed() { | ||||||
|  |             Toast.error("Error creating new session", new RuntimeException(getException())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private class JoinSessionTask extends Task<Void> { | ||||||
|  |         private Integer sessionId; | ||||||
|  | 
 | ||||||
|  |         JoinSessionTask(Integer sessionId) { | ||||||
|  |             this.sessionId = sessionId; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected Void call() throws Exception { | ||||||
|  |             getController().joinSession(sessionId); | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void succeeded() { | ||||||
|  |             Toast.info(String.format("Joined Session %s", sessionId)); | ||||||
|  |             close(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void failed() { | ||||||
|  |             Toast.error(String.format("Error joining session: %s", sessionId), new RuntimeException(getException())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private class DeleteSessionTask extends Task<Boolean> { | ||||||
|  |         private SessionRow row; | ||||||
|  |         private Integer sessionId; | ||||||
|  | 
 | ||||||
|  |         DeleteSessionTask(SessionRow row, Integer sessionId) { | ||||||
|  |             this.row = row; | ||||||
|  |             this.sessionId = sessionId; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected Boolean call() throws Exception { | ||||||
|  |             return getCoreClient().deleteSession(sessionId); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void succeeded() { | ||||||
|  |             if (getValue()) { | ||||||
|  |                 sessionsTable.getItems().remove(row); | ||||||
|  |                 sessionsTable.getSelectionModel().clearSelection(); | ||||||
|  |                 Toast.info(String.format("Deleted Session %s", sessionId)); | ||||||
|  |             } else { | ||||||
|  |                 Toast.error(String.format("Failure to delete session %s", sessionId)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void failed() { | ||||||
|  |             Toast.error(String.format("Error deleting session: %s", sessionId), new RuntimeException(getException())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Data | ||||||
|  |     protected class SessionRow { | ||||||
|  |         private Integer id; | ||||||
|  |         private String state; | ||||||
|  |         private Integer nodes; | ||||||
|  | 
 | ||||||
|  |         SessionRow(SessionOverview sessionOverview) { | ||||||
|  |             id = sessionOverview.getId(); | ||||||
|  |             state = SessionState.get(sessionOverview.getState()).name(); | ||||||
|  |             nodes = sessionOverview.getNodes(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() throws IOException { | ||||||
|  |         List<SessionOverview> sessions = getCoreClient().getSessions(); | ||||||
|  |         List<SessionRow> rows = sessions.stream().map(SessionRow::new).collect(Collectors.toList()); | ||||||
|  |         sessionsTable.getSelectionModel().clearSelection(); | ||||||
|  |         sessionsTable.getItems().setAll(rows); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,70 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.SessionOverview; | ||||||
|  | import com.core.data.SessionState; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.scene.control.TableColumn; | ||||||
|  | import javafx.scene.control.TableView; | ||||||
|  | import javafx.scene.control.cell.PropertyValueFactory; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | public class SessionsFoenixDialog extends CoreFoenixDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     @FXML private TableView<SessionRow> sessionsTable; | ||||||
|  |     @FXML private TableColumn<SessionRow, Integer> sessionIdColumn; | ||||||
|  |     @FXML private TableColumn<SessionRow, String> stateColumn; | ||||||
|  |     @FXML private TableColumn<SessionRow, Integer> nodeCountColumn; | ||||||
|  | 
 | ||||||
|  |     public SessionsFoenixDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/sessions_dialog.fxml"); | ||||||
|  |         getHeading().setText("Sessions"); | ||||||
|  |         JFXButton joinButton = createButton("Join"); | ||||||
|  |         joinButton.setOnAction(event -> { | ||||||
|  |             SessionRow row = sessionsTable.getSelectionModel().getSelectedItem(); | ||||||
|  |             logger.info("selected session: {}", row); | ||||||
|  |             try { | ||||||
|  |                 getController().joinSession(row.getId()); | ||||||
|  |                 Toast.info(String.format("Joined Session %s", row.getId())); | ||||||
|  |             } catch (IOException ex) { | ||||||
|  |                 logger.error("error joining session: {}", row.getId()); | ||||||
|  |             } | ||||||
|  |             getDialog().close(); | ||||||
|  |         }); | ||||||
|  |         getDialogLayout().setActions(joinButton); | ||||||
|  | 
 | ||||||
|  |         sessionIdColumn.setCellValueFactory(new PropertyValueFactory<>("id")); | ||||||
|  |         stateColumn.setCellValueFactory(new PropertyValueFactory<>("state")); | ||||||
|  |         nodeCountColumn.setCellValueFactory(new PropertyValueFactory<>("nodes")); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Data | ||||||
|  |     protected class SessionRow { | ||||||
|  |         private Integer id; | ||||||
|  |         private String state; | ||||||
|  |         private Integer nodes; | ||||||
|  | 
 | ||||||
|  |         public SessionRow(SessionOverview sessionOverview) { | ||||||
|  |             id = sessionOverview.getId(); | ||||||
|  |             state = SessionState.get(sessionOverview.getState()).name(); | ||||||
|  |             nodes = sessionOverview.getNodes(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog() throws IOException { | ||||||
|  |         sessionsTable.getItems().clear(); | ||||||
|  |         List<SessionOverview> sessions = getCoreClient().getSessions(); | ||||||
|  |         sessionsTable.getItems().addAll(sessions.stream() | ||||||
|  |                 .map(SessionRow::new) | ||||||
|  |                 .collect(Collectors.toList())); | ||||||
|  |         getDialog().show(getController().getStackPane()); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										132
									
								
								corefx/src/main/java/com/core/ui/dialogs/StageDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								corefx/src/main/java/com/core/ui/dialogs/StageDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,132 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.client.ICoreClient; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXDecorator; | ||||||
|  | import javafx.fxml.FXMLLoader; | ||||||
|  | import javafx.geometry.HPos; | ||||||
|  | import javafx.geometry.Insets; | ||||||
|  | import javafx.geometry.Pos; | ||||||
|  | import javafx.geometry.VPos; | ||||||
|  | import javafx.scene.Node; | ||||||
|  | import javafx.scene.Parent; | ||||||
|  | import javafx.scene.Scene; | ||||||
|  | import javafx.scene.image.Image; | ||||||
|  | import javafx.scene.image.ImageView; | ||||||
|  | import javafx.scene.input.KeyCode; | ||||||
|  | import javafx.scene.layout.*; | ||||||
|  | import javafx.stage.Modality; | ||||||
|  | import javafx.stage.Stage; | ||||||
|  | import javafx.stage.StageStyle; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private final Controller controller; | ||||||
|  |     private final Stage stage = new Stage(StageStyle.DECORATED); | ||||||
|  |     private final Scene scene; | ||||||
|  |     private final GridPane gridPane = new GridPane(); | ||||||
|  |     private final HBox buttonBar = new HBox(); | ||||||
|  | 
 | ||||||
|  |     public StageDialog(Controller controller, String fxmlPath) { | ||||||
|  |         this(controller, fxmlPath, Modality.APPLICATION_MODAL); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public StageDialog(Controller controller, String fxmlPath, Modality modality) { | ||||||
|  |         this.controller = controller; | ||||||
|  | 
 | ||||||
|  |         JFXDecorator decorator = new JFXDecorator(stage, gridPane); | ||||||
|  |         decorator.setCustomMaximize(true); | ||||||
|  |         Image coreIcon = new Image(getClass().getResourceAsStream("/core-icon.png")); | ||||||
|  |         decorator.setGraphic(new ImageView(coreIcon)); | ||||||
|  | 
 | ||||||
|  |         scene = new Scene(decorator); | ||||||
|  |         stage.setScene(scene); | ||||||
|  | 
 | ||||||
|  |         stage.setWidth(800); | ||||||
|  |         stage.setHeight(600); | ||||||
|  |         scene.setOnKeyPressed(event -> { | ||||||
|  |             if (KeyCode.ESCAPE == event.getCode()) { | ||||||
|  |                 stage.close(); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         gridPane.setHgap(10); | ||||||
|  |         gridPane.setVgap(10); | ||||||
|  |         gridPane.setMaxWidth(Double.MAX_VALUE); | ||||||
|  |         gridPane.setMaxHeight(Double.MAX_VALUE); | ||||||
|  |         gridPane.setPadding(new Insets(10)); | ||||||
|  | 
 | ||||||
|  |         gridPane.getColumnConstraints().add(new ColumnConstraints(10, Region.USE_COMPUTED_SIZE, | ||||||
|  |                 Region.USE_COMPUTED_SIZE, Priority.ALWAYS, HPos.CENTER, true)); | ||||||
|  |         gridPane.getRowConstraints().add(new RowConstraints(10, Region.USE_COMPUTED_SIZE, | ||||||
|  |                 Region.USE_COMPUTED_SIZE, Priority.ALWAYS, VPos.CENTER, true)); | ||||||
|  |         gridPane.getRowConstraints().add(new RowConstraints(30, 30, | ||||||
|  |                 Region.USE_COMPUTED_SIZE, Priority.NEVER, VPos.CENTER, true)); | ||||||
|  | 
 | ||||||
|  |         buttonBar.setAlignment(Pos.CENTER_RIGHT); | ||||||
|  |         buttonBar.setSpacing(10); | ||||||
|  | 
 | ||||||
|  |         stage.initModality(modality); | ||||||
|  | 
 | ||||||
|  |         FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath)); | ||||||
|  |         loader.setController(this); | ||||||
|  |         try { | ||||||
|  |             Parent parent = loader.load(); | ||||||
|  |             setContent(parent); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error loading fxml: {}", fxmlPath, ex); | ||||||
|  |             throw new RuntimeException(ex); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         gridPane.addRow(1, buttonBar); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void close() { | ||||||
|  |         stage.close(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ICoreClient getCoreClient() { | ||||||
|  |         return controller.getCoreClient(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setContent(Node node) { | ||||||
|  |         gridPane.addRow(0, node); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setTitle(String title) { | ||||||
|  |         stage.setTitle(title); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setOwner(Stage window) { | ||||||
|  |         stage.initOwner(window); | ||||||
|  |         scene.getStylesheets().addAll(window.getScene().getStylesheets()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public JFXButton createButton(String label) { | ||||||
|  |         JFXButton button = new JFXButton(label); | ||||||
|  |         button.getStyleClass().add("core-button"); | ||||||
|  |         buttonBar.getChildren().add(button); | ||||||
|  |         return button; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void addCancelButton() { | ||||||
|  |         JFXButton button = createButton("Cancel"); | ||||||
|  |         button.setOnAction(event -> close()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void show() { | ||||||
|  |         if (buttonBar.getChildren().isEmpty() && gridPane.getChildren().contains(buttonBar)) { | ||||||
|  |             gridPane.getChildren().remove(1); | ||||||
|  |             gridPane.getRowConstraints().remove(1); | ||||||
|  |             gridPane.setVgap(0); | ||||||
|  |         } | ||||||
|  |         stage.showAndWait(); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								corefx/src/main/java/com/core/ui/dialogs/TerminalDialog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								corefx/src/main/java/com/core/ui/dialogs/TerminalDialog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | ||||||
|  | package com.core.ui.dialogs; | ||||||
|  | 
 | ||||||
|  | import com.core.Controller; | ||||||
|  | import com.core.data.CoreNode; | ||||||
|  | import com.core.ui.Toast; | ||||||
|  | import com.jfoenix.controls.JFXButton; | ||||||
|  | import com.jfoenix.controls.JFXTextArea; | ||||||
|  | import com.jfoenix.controls.JFXTextField; | ||||||
|  | import javafx.concurrent.Task; | ||||||
|  | import javafx.fxml.FXML; | ||||||
|  | import javafx.stage.Modality; | ||||||
|  | import lombok.Data; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | public class TerminalDialog extends StageDialog { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private String address; | ||||||
|  |     private int port; | ||||||
|  |     private JFXButton saveButton; | ||||||
|  |     private @FXML JFXTextArea outputTextArea; | ||||||
|  |     private @FXML JFXTextField commandTextField; | ||||||
|  |     private CoreNode node; | ||||||
|  | 
 | ||||||
|  |     public TerminalDialog(Controller controller) { | ||||||
|  |         super(controller, "/fxml/terminal_dialog.fxml", Modality.NONE); | ||||||
|  |         commandTextField.setOnAction(event -> { | ||||||
|  |             String command = commandTextField.getText(); | ||||||
|  |             addOutput(String.format("$> %s", command)); | ||||||
|  |             new Thread(new CommandTask(command)).start(); | ||||||
|  |             commandTextField.clear(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     private class CommandTask extends Task<String> { | ||||||
|  |         private String command; | ||||||
|  | 
 | ||||||
|  |         CommandTask(String command) { | ||||||
|  |             this.command = command; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected String call() throws Exception { | ||||||
|  |             return getCoreClient().nodeCommand(node, command); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void succeeded() { | ||||||
|  |             addOutput(getValue()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         protected void failed() { | ||||||
|  |             Toast.error("Failed sending terminal command", new RuntimeException(getException())); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void addOutput(String output) { | ||||||
|  |         outputTextArea.appendText(String.format("%s%n", output)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void showDialog(CoreNode node) { | ||||||
|  |         this.node = node; | ||||||
|  |         setTitle(String.format("%s Pseudo Terminal", node.getName())); | ||||||
|  |         outputTextArea.setText(""); | ||||||
|  |         commandTextField.setText(""); | ||||||
|  |         commandTextField.requestFocus(); | ||||||
|  |         show(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,15 @@ | ||||||
|  | package com.core.ui.textfields; | ||||||
|  | 
 | ||||||
|  | import javafx.scene.control.TextFormatter; | ||||||
|  | 
 | ||||||
|  | import java.util.function.UnaryOperator; | ||||||
|  | import java.util.regex.Pattern; | ||||||
|  | 
 | ||||||
|  | public class DoubleFilter implements UnaryOperator<TextFormatter.Change> { | ||||||
|  |     private static final Pattern DIGIT_PATTERN = Pattern.compile("\\d*\\.?\\d*"); | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public TextFormatter.Change apply(TextFormatter.Change change) { | ||||||
|  |         return DIGIT_PATTERN.matcher(change.getText()).matches() ? change : null; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										122
									
								
								corefx/src/main/java/com/core/utils/ConfigUtils.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								corefx/src/main/java/com/core/utils/ConfigUtils.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,122 @@ | ||||||
|  | package com.core.utils; | ||||||
|  | 
 | ||||||
|  | import com.core.data.NodeType; | ||||||
|  | import javafx.scene.paint.Color; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.FileInputStream; | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.io.PrintWriter; | ||||||
|  | import java.nio.file.Files; | ||||||
|  | import java.nio.file.Path; | ||||||
|  | import java.nio.file.Paths; | ||||||
|  | import java.util.*; | ||||||
|  | 
 | ||||||
|  | public final class ConfigUtils { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final Path HOME = Paths.get(System.getProperty("user.home"), ".core"); | ||||||
|  |     private static final String CONFIG_FILE_NAME = "config.json"; | ||||||
|  |     private static final String DEFAULT_CONFIG = "/" + CONFIG_FILE_NAME; | ||||||
|  |     private static final Path CONFIG_FILE = Paths.get(HOME.toString(), CONFIG_FILE_NAME); | ||||||
|  |     private static final Path XML_DIR = Paths.get(HOME.toString(), "xml"); | ||||||
|  |     private static final Path MOBILITY_DIR = Paths.get(HOME.toString(), "mobility"); | ||||||
|  |     private static final Path ICON_DIR = Paths.get(HOME.toString(), "icons"); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     private ConfigUtils() { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void save(Configuration configuration) throws IOException { | ||||||
|  |         String fileData = JsonUtils.toPrettyString(configuration); | ||||||
|  |         try (PrintWriter out = new PrintWriter(CONFIG_FILE.toFile())) { | ||||||
|  |             out.println(fileData); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static Configuration readConfig() throws IOException { | ||||||
|  |         logger.info("reading config file: {}", CONFIG_FILE); | ||||||
|  |         return JsonUtils.read(new FileInputStream(CONFIG_FILE.toFile()), Configuration.class); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static List<NodeTypeConfig> createDefaults() throws IOException { | ||||||
|  |         return Arrays.asList( | ||||||
|  |                 createDefault("host", "Host", "/icons/host-100.png", new TreeSet<>(Arrays.asList( | ||||||
|  |                         "DefaultRoute", "SSH" | ||||||
|  |                 ))), | ||||||
|  |                 createDefault("PC", "PC", "/icons/pc-100.png", | ||||||
|  |                         new TreeSet<>(Collections.singletonList("DefaultRoute"))), | ||||||
|  |                 createDefault("mdr", "MDR", "/icons/router-100.png", new TreeSet<>(Arrays.asList( | ||||||
|  |                         "zebra", "OSPFv3MDR", "IPForward" | ||||||
|  |                 ))) | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static NodeTypeConfig createDefault(String model, String display, String icon, | ||||||
|  |                                                 Set<String> services) throws IOException { | ||||||
|  |         String fileName = Paths.get(icon).getFileName().toString(); | ||||||
|  |         Path iconPath = Paths.get(ICON_DIR.toString(), fileName); | ||||||
|  |         Files.copy(ConfigUtils.class.getResourceAsStream(icon), iconPath); | ||||||
|  |         return new NodeTypeConfig(model, display, iconPath.toUri().toString(), services); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static void checkDirectory(Path path) throws IOException { | ||||||
|  |         if (!path.toFile().exists()) { | ||||||
|  |             Files.createDirectory(path); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void checkHomeDirectory() throws IOException { | ||||||
|  |         logger.info("checking core home directory"); | ||||||
|  |         checkDirectory(HOME); | ||||||
|  |         checkDirectory(XML_DIR); | ||||||
|  |         checkDirectory(MOBILITY_DIR); | ||||||
|  |         checkDirectory(ICON_DIR); | ||||||
|  |         if (!CONFIG_FILE.toFile().exists()) { | ||||||
|  |             createDefaultConfigFile(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static void createDefaultConfigFile() throws IOException { | ||||||
|  |         logger.info("creating default configuration"); | ||||||
|  |         Files.copy(ConfigUtils.class.getResourceAsStream(DEFAULT_CONFIG), CONFIG_FILE); | ||||||
|  |         Configuration configuration = readConfig(); | ||||||
|  |         configuration.setXmlPath(XML_DIR.toString()); | ||||||
|  |         configuration.setMobilityPath(MOBILITY_DIR.toString()); | ||||||
|  |         configuration.setIconPath(ICON_DIR.toString()); | ||||||
|  |         configuration.setNodeTypeConfigs(createDefaults()); | ||||||
|  |         configuration.setNodeLabelColor(Color.WHITE.toString()); | ||||||
|  |         configuration.setNodeLabelBackgroundColor(Color.BLACK.toString()); | ||||||
|  |         save(configuration); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static Configuration load() { | ||||||
|  |         try { | ||||||
|  |             Configuration configuration = readConfig(); | ||||||
|  | 
 | ||||||
|  |             // initialize node types | ||||||
|  |             for (NodeTypeConfig nodeTypeConfig : configuration.getNodeTypeConfigs()) { | ||||||
|  |                 NodeType nodeType = new NodeType( | ||||||
|  |                         NodeType.DEFAULT, | ||||||
|  |                         nodeTypeConfig.getModel(), | ||||||
|  |                         nodeTypeConfig.getDisplay(), | ||||||
|  |                         nodeTypeConfig.getIcon() | ||||||
|  |                 ); | ||||||
|  |                 nodeType.getServices().addAll(nodeTypeConfig.getServices()); | ||||||
|  |                 NodeType.add(nodeType); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // override configuration from command line | ||||||
|  |             String coreAddress = System.getProperty("coreAddress"); | ||||||
|  |             if (coreAddress != null) { | ||||||
|  |                 configuration.setCoreAddress(coreAddress); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return configuration; | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             logger.error("error reading config file", ex); | ||||||
|  |             throw new RuntimeException("configuration file did not exist", ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								corefx/src/main/java/com/core/utils/Configuration.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								corefx/src/main/java/com/core/utils/Configuration.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | ||||||
|  | package com.core.utils; | ||||||
|  | 
 | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | import java.util.ArrayList; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @NoArgsConstructor | ||||||
|  | public class Configuration { | ||||||
|  |     private String coreAddress; | ||||||
|  |     private int corePort; | ||||||
|  |     private String xmlPath; | ||||||
|  |     private String mobilityPath; | ||||||
|  |     private String iconPath; | ||||||
|  |     private String shellCommand; | ||||||
|  |     private List<NodeTypeConfig> nodeTypeConfigs = new ArrayList<>(); | ||||||
|  |     private String nodeLabelColor; | ||||||
|  |     private String nodeLabelBackgroundColor; | ||||||
|  |     private Double throughputLimit; | ||||||
|  |     private Integer throughputWidth; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								corefx/src/main/java/com/core/utils/FxmlUtils.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								corefx/src/main/java/com/core/utils/FxmlUtils.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | package com.core.utils; | ||||||
|  | 
 | ||||||
|  | import javafx.fxml.FXMLLoader; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | 
 | ||||||
|  | public final class FxmlUtils { | ||||||
|  |     private FxmlUtils() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void loadRootController(Object obj, String fxmlPath) { | ||||||
|  |         FXMLLoader loader = new FXMLLoader(FxmlUtils.class.getResource(fxmlPath)); | ||||||
|  |         loader.setRoot(obj); | ||||||
|  |         loader.setController(obj); | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             loader.load(); | ||||||
|  |         } catch (IOException ex) { | ||||||
|  |             throw new RuntimeException(ex); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								corefx/src/main/java/com/core/utils/IconUtils.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								corefx/src/main/java/com/core/utils/IconUtils.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | ||||||
|  | package com.core.utils; | ||||||
|  | 
 | ||||||
|  | import com.jfoenix.svg.SVGGlyph; | ||||||
|  | import com.jfoenix.svg.SVGGlyphLoader; | ||||||
|  | import edu.uci.ics.jung.visualization.LayeredIcon; | ||||||
|  | import javafx.scene.paint.Paint; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import javax.swing.*; | ||||||
|  | import java.awt.*; | ||||||
|  | import java.net.URI; | ||||||
|  | import java.net.URISyntaxException; | ||||||
|  | import java.nio.file.Paths; | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public final class IconUtils { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     public static final int ICON_SIZE = 75; | ||||||
|  |     private static final Map<String, ImageIcon> ICON_MAP = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     private IconUtils() { | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static LayeredIcon getExternalLayeredIcon(String iconPath) { | ||||||
|  |         ImageIcon imageIcon = ICON_MAP.computeIfAbsent(iconPath, key -> { | ||||||
|  |             try { | ||||||
|  |                 return new ImageIcon(Paths.get(new URI(iconPath)).toString()); | ||||||
|  |             } catch (URISyntaxException ex) { | ||||||
|  |                 logger.error("error loading icon: {}", iconPath); | ||||||
|  |                 throw new IllegalArgumentException("invalid icon uri: " + iconPath); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         Image image = imageIcon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_DEFAULT); | ||||||
|  |         return new LayeredIcon(image); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static LayeredIcon getLayeredIcon(String iconPath) { | ||||||
|  |         ImageIcon imageIcon = ICON_MAP.computeIfAbsent(iconPath, key -> | ||||||
|  |                 new ImageIcon(IconUtils.class.getResource(iconPath))); | ||||||
|  |         Image image = imageIcon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_DEFAULT); | ||||||
|  |         return new LayeredIcon(image); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static SVGGlyph get(String name) { | ||||||
|  |         SVGGlyph svg = null; | ||||||
|  |         try { | ||||||
|  |             svg = SVGGlyphLoader.getIcoMoonGlyph("icomoon.svg." + name); | ||||||
|  |         } catch (Exception ex) { | ||||||
|  |             logger.error("error loading icon: {}", name, ex); | ||||||
|  |         } | ||||||
|  |         return svg; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static SVGGlyph get(String name, int size, String paint) { | ||||||
|  |         SVGGlyph svg = get(name); | ||||||
|  |         if (svg != null) { | ||||||
|  |             svg.setSize(size); | ||||||
|  |             svg.setFill(Paint.valueOf(paint)); | ||||||
|  |         } | ||||||
|  |         return svg; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								corefx/src/main/java/com/core/utils/JsonUtils.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								corefx/src/main/java/com/core/utils/JsonUtils.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | ||||||
|  | package com.core.utils; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.core.JsonProcessingException; | ||||||
|  | import com.fasterxml.jackson.databind.ObjectMapper; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.io.InputStream; | ||||||
|  | 
 | ||||||
|  | public final class JsonUtils { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static ObjectMapper mapper = new ObjectMapper(); | ||||||
|  | 
 | ||||||
|  |     private JsonUtils() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static ObjectMapper getMapper() { | ||||||
|  |         return mapper; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T read(byte[] data, Class<T> clazz) throws IOException { | ||||||
|  |         return mapper.readValue(data, clazz); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T read(String data, Class<T> clazz) throws IOException { | ||||||
|  |         return mapper.readValue(data, clazz); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T read(InputStream input, Class<T> clazz) throws IOException { | ||||||
|  |         return mapper.readValue(input, clazz); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void logPrettyJson(Object obj) { | ||||||
|  |         try { | ||||||
|  |             logger.debug(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj)); | ||||||
|  |         } catch (JsonProcessingException e) { | ||||||
|  |             logger.error("error making pretty json", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static String toPrettyString(Object obj) throws JsonProcessingException { | ||||||
|  |         return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static String toString(Object obj) throws JsonProcessingException { | ||||||
|  |         return mapper.writeValueAsString(obj); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static byte[] toBytes(Object obj) throws JsonProcessingException { | ||||||
|  |         return mapper.writeValueAsBytes(obj); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								corefx/src/main/java/com/core/utils/NodeTypeConfig.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								corefx/src/main/java/com/core/utils/NodeTypeConfig.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | ||||||
|  | package com.core.utils; | ||||||
|  | 
 | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.NoArgsConstructor; | ||||||
|  | 
 | ||||||
|  | import java.util.Set; | ||||||
|  | 
 | ||||||
|  | @Data | ||||||
|  | @EqualsAndHashCode(onlyExplicitlyIncluded = true) | ||||||
|  | @NoArgsConstructor | ||||||
|  | @AllArgsConstructor | ||||||
|  | public class NodeTypeConfig { | ||||||
|  |     @EqualsAndHashCode.Include | ||||||
|  |     private String model; | ||||||
|  |     private String display; | ||||||
|  |     private String icon; | ||||||
|  |     private Set<String> services; | ||||||
|  | } | ||||||
							
								
								
									
										174
									
								
								corefx/src/main/java/com/core/utils/WebUtils.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								corefx/src/main/java/com/core/utils/WebUtils.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,174 @@ | ||||||
|  | package com.core.utils; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.core.type.TypeReference; | ||||||
|  | import okhttp3.*; | ||||||
|  | import org.apache.logging.log4j.LogManager; | ||||||
|  | import org.apache.logging.log4j.Logger; | ||||||
|  | 
 | ||||||
|  | import java.io.*; | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.Map; | ||||||
|  | 
 | ||||||
|  | public final class WebUtils { | ||||||
|  |     private static final Logger logger = LogManager.getLogger(); | ||||||
|  |     private static final OkHttpClient client = new OkHttpClient(); | ||||||
|  |     private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); | ||||||
|  | 
 | ||||||
|  |     private WebUtils() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T getJson(String url, Class<T> clazz) throws IOException { | ||||||
|  |         return getJson(url, clazz, Collections.emptyMap()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T getJson(String url, Class<T> clazz, Map<String, String> args) throws IOException { | ||||||
|  |         logger.debug("get json: {}", url); | ||||||
|  |         HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); | ||||||
|  |         args.forEach(urlBuilder::addQueryParameter); | ||||||
|  |         HttpUrl httpUrl = urlBuilder.build(); | ||||||
|  | 
 | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(httpUrl) | ||||||
|  |                 .build(); | ||||||
|  |         String response = readResponse(request); | ||||||
|  |         return JsonUtils.read(response, clazz); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static void getFile(String url, File file) throws IOException { | ||||||
|  |         logger.debug("get file: {}", url); | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .build(); | ||||||
|  |         try (Response response = client.newCall(request).execute()) { | ||||||
|  |             InputStream input = response.body().byteStream(); | ||||||
|  |             try (OutputStream output = new FileOutputStream(file)) { | ||||||
|  |                 int count; | ||||||
|  |                 byte[] data = new byte[1024]; | ||||||
|  |                 while ((count = input.read(data)) != -1) { | ||||||
|  |                     output.write(data, 0, count); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static boolean postFile(String url, File file) throws IOException { | ||||||
|  |         MediaType mediaType = MediaType.parse("File/*"); | ||||||
|  |         RequestBody requestBody = new MultipartBody.Builder() | ||||||
|  |                 .setType(MultipartBody.FORM) | ||||||
|  |                 .addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file)) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .post(requestBody) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         try (Response response = client.newCall(request).execute()) { | ||||||
|  |             return response.isSuccessful(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T postFile(String url, File file, Class<T> clazz) throws IOException { | ||||||
|  |         MediaType mediaType = MediaType.parse("File/*"); | ||||||
|  |         RequestBody requestBody = new MultipartBody.Builder() | ||||||
|  |                 .setType(MultipartBody.FORM) | ||||||
|  |                 .addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file)) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .post(requestBody) | ||||||
|  |                 .build(); | ||||||
|  | 
 | ||||||
|  |         String response = readResponse(request); | ||||||
|  |         return JsonUtils.read(response, clazz); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T getJson(String url, TypeReference<T> reference) throws IOException { | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .build(); | ||||||
|  |         String response = readResponse(request); | ||||||
|  |         return JsonUtils.getMapper().readValue(response, reference); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private static String readResponse(Request request) throws IOException { | ||||||
|  |         try (Response response = client.newCall(request).execute()) { | ||||||
|  |             ResponseBody body = response.body(); | ||||||
|  |             if (body == null) { | ||||||
|  |                 throw new IOException("failed to received body"); | ||||||
|  |             } else { | ||||||
|  |                 return body.string(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static boolean postJson(String url, Object json) throws IOException { | ||||||
|  |         logger.debug("post json: {} - {}", url, json); | ||||||
|  |         RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json)); | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .post(body) | ||||||
|  |                 .build(); | ||||||
|  |         try (Response response = client.newCall(request).execute()) { | ||||||
|  |             return response.isSuccessful(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static boolean putJson(String url) throws IOException { | ||||||
|  |         logger.debug("put json: {}", url); | ||||||
|  |         RequestBody body = new FormBody.Builder().build(); | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .put(body) | ||||||
|  |                 .build(); | ||||||
|  |         try (Response response = client.newCall(request).execute()) { | ||||||
|  |             return response.isSuccessful(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static boolean putJson(String url, Object json) throws IOException { | ||||||
|  |         logger.debug("put json: {} - {}", url, json); | ||||||
|  |         RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json)); | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .put(body) | ||||||
|  |                 .build(); | ||||||
|  |         try (Response response = client.newCall(request).execute()) { | ||||||
|  |             return response.isSuccessful(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T putJson(String url, Object json, Class<T> clazz) throws IOException { | ||||||
|  |         logger.debug("put json: {} - {}", url, json); | ||||||
|  |         RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json)); | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .put(body) | ||||||
|  |                 .build(); | ||||||
|  |         String response = readResponse(request); | ||||||
|  |         return JsonUtils.read(response, clazz); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static <T> T post(String url, Class<T> clazz) throws IOException { | ||||||
|  |         logger.debug("post: {}", url); | ||||||
|  |         RequestBody body = new FormBody.Builder().build(); | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .post(body) | ||||||
|  |                 .build(); | ||||||
|  |         String response = readResponse(request); | ||||||
|  |         return JsonUtils.read(response, clazz); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static boolean delete(String url) throws IOException { | ||||||
|  |         logger.debug("delete: {}", url); | ||||||
|  |         Request request = new Request.Builder() | ||||||
|  |                 .url(url) | ||||||
|  |                 .delete() | ||||||
|  |                 .build(); | ||||||
|  |         try (Response response = client.newCall(request).execute()) { | ||||||
|  |             return response.isSuccessful(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue