Skip to content

Commit

Permalink
Merge pull request #98 from cisco-system-traffic-generator/trex-daemo…
Browse files Browse the repository at this point in the history
…n-control

Trex daemon control
  • Loading branch information
EgorBlagov authored Oct 8, 2018
2 parents 617e9d6 + e7bd365 commit ebe2d79
Show file tree
Hide file tree
Showing 17 changed files with 1,468 additions and 2 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ dependencies {
compile group: 'org.testng', name: 'testng', version:'6.9.10'
compile group: 'net.java.dev.jna', name: 'jna', version: '4.4.0'
compile group: 'net.java.dev.jna', name: 'jna-platform', version: '4.4.0'

compile group: 'com.github.arteam', name: 'simple-json-rpc-client', version: '0.9'
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.6'

testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile "org.testfx:testfx-core:4.0.+"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.cisco.trex.stl.gui.storages.StatsStorage;
import com.cisco.trex.stl.gui.util.RunningConfiguration;
import com.exalttech.trex.core.RPCMethods;
import com.exalttech.trex.ui.controllers.daemon.InterfaceInfoProvider;
import com.exalttech.trex.ui.views.streams.builder.ProtocolDataView;
import com.google.common.eventbus.EventBus;
import com.google.inject.AbstractModule;
Expand All @@ -20,5 +21,6 @@ protected void configure() {
bind(ProtocolDataView.class).toProvider(ProtocolDataViewProvider.class);
bind(StatsStorage.class).in(Singleton.class);
bind(IDataCompressor.class).to(TRexDataCompressor.class);
bind(InterfaceInfoProvider.class).in(Singleton.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ public class MainViewController implements Initializable, EventHandler<KeyEvent>
private DialogWindow captureWindow;
private DialogWindow preferencesWindow;
private DialogWindow dashboardWindow;
private DialogWindow trexDaemonWindow;

private SystemInfoReq systemInfoReq = null;
private PacketTableView tableView;
Expand Down Expand Up @@ -1795,6 +1796,32 @@ public void handleDevicesTreeArrowClicked(MouseEvent event) {
treeviewOpened = !treeviewOpened;
}

/**
* Handle menu item connect to TRex Daemon
*
* @param actionEvent
*/
@FXML
public void handleTRexDaemonItemClick(ActionEvent actionEvent) {
try {
if (trexDaemonWindow == null) {
trexDaemonWindow = new DialogWindow(
"TRexDaemonDialog.fxml",
"TRex Daemon",
50,
10,
1200,
750,
true,
TrexApp.getPrimaryStage()
);
}
trexDaemonWindow.show(false);
} catch (IOException ex) {
LOG.error("Error opening TRex Daemon view", ex);
}
}

/**
* Enumerator that present Context menu item type
*/
Expand Down
267 changes: 267 additions & 0 deletions src/main/java/com/exalttech/trex/ui/controllers/daemon/ConfigNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
package com.exalttech.trex.ui.controllers.daemon;

import com.google.common.net.InetAddresses;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableBooleanValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import java.text.MessageFormat;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


public class ConfigNode {
@FunctionalInterface
public interface Validator {
/**
* Validates given value. If doesn't throw then it's value is valid
* @param value
* @throws Exception
*/
void validate(Object value) throws Exception;
}

private MetaField meta;

private ObservableList<ConfigNode> children = FXCollections.observableArrayList();
private ConfigNode parent;

private boolean removable;
private SimpleBooleanProperty mandatoryProperty = new SimpleBooleanProperty();

private Object value;

private Map<MetaField.Type, Validator> validationMap = new HashMap<>();


public ConfigNode(MetaField meta, ConfigNode parent, boolean removable) {
this.removable = removable;
this.parent = parent;
this.meta = meta;

initValidator();

if (getType() == MetaField.Type.OBJECT) {
this.meta.attributes.forEach(metaField -> {
ConfigNode child = new ConfigNode(metaField, this);
this.children.add(child);
});
}

mandatoryProperty.setValue(isMandatory());

}

public ConfigNode(MetaField meta, ConfigNode parent) {
this(meta, parent, false);
}

public ConfigNode(MetaField meta) {
this(meta, null, false);
}

private void initValidator() {
validationMap.put(MetaField.Type.STRING, val -> { String casted = (String) value; });
validationMap.put(MetaField.Type.NUMBER, val -> Integer.parseInt((String) value));
validationMap.put(MetaField.Type.FLOAT, val -> Float.parseFloat((String) value));
validationMap.put(MetaField.Type.BOOLEAN, val -> { boolean casted = (boolean) value; });
validationMap.put(MetaField.Type.IP, val -> InetAddresses.forString((String) value));
validationMap.put(MetaField.Type.MAC, val -> {
if (!Pattern.matches("^([0-9a-fA-F]{2}:){5}([0-9a-fA-F]{2})$", (String) value)) {
throw new Exception();
}
});

validationMap.put(MetaField.Type.LIST, val -> {
for (ConfigNode node : children) {
if (!node.validateValue()) {
throw new Exception();
}
}
});

validationMap.put(MetaField.Type.OBJECT, val -> {
for (ConfigNode node : children) {
if (!node.validateValue()) {
throw new Exception();
}
}
});
}

public MetaField.Type getType() {
return meta.type;
}

public boolean isMandatory() {
if (meta.mandatory_if_not_set == null) {
return meta.mandatory;
} else {
return !isDependencySpecified();
}
}

private boolean isDependencySpecified() {
return parent.getChildren()
.stream()
.filter(sibling -> sibling.getId().equals(meta.mandatory_if_not_set))
.anyMatch(sibling -> sibling.getValue() != null);
}

public ObservableBooleanValue mandatoryProperty() {
return mandatoryProperty;
}

public String getDefaultValue() {
return meta.default_value;
}

public String getName() {
return meta.name;
}

public String getDescription() {
return meta.description;
}

public String getId() {
return meta.id;
}

public void setValue(Object newValue) {
if (getType() == MetaField.Type.LIST) {
List<Object> newChildren = ((List<Object>) newValue);
newChildren.forEach(x -> {
ConfigNode configNode = addListItem();
configNode.setValue(x);
});
} else if (getType() == MetaField.Type.OBJECT){
Map<String, Object> newMap = (Map<String, Object>) newValue;
for (Map.Entry<String, Object> entry : newMap.entrySet()) {
children.stream()
.filter(x -> x.getId().equals(entry.getKey()))
.findFirst()
.ifPresent(x -> x.setValue(entry.getValue()));
}
} else {
value = newValue;
}

if (getParent() != null) {
getParent().updateDependencies();
}
}

public Object getValue() {
if (getType() == MetaField.Type.LIST) {
List<Object> childrenValues = getChildren().stream()
.map(ConfigNode::getValue)
.filter(Objects::nonNull)
.collect(Collectors.toList());

if (childrenValues.isEmpty()) {
return null;
}
return childrenValues;

} else if (getType() == MetaField.Type.OBJECT) {
Map<String, Object> childrenMap = new LinkedHashMap<>();
getChildren().stream()
.filter(field -> field.getValue() != null)
.forEach(field -> childrenMap.put(field.meta.id, field.getValue()));

if (childrenMap.isEmpty()) {
return null;
}
return childrenMap;

} else {
try {
if (getType() == MetaField.Type.NUMBER) {
return Integer.parseInt((String) value);
} else if (getType() == MetaField.Type.FLOAT) {
return Float.parseFloat((String) value);
}
} catch (Exception ignored) {

}
return value;
}
}

private void updateDependencies() {
getChildren().forEach(x -> x.mandatoryProperty.setValue(x.isMandatory()));
}

public boolean validateValue() {
if (getValue() == null) {
return !isMandatory();
}

try {
validationMap.get(getType()).validate(value);
return true;
} catch (Exception ex) {
return false;
}
}

public List<String> getValidationErrors() {
List<String> errors = new ArrayList<>();
for (ConfigNode node : this.children) {
errors.addAll(node.getValidationErrors());
}

if (errors.isEmpty()) {
String idDescription = getIdDescription();

if (getValue() == null && isMandatory()) {
errors.add(MessageFormat.format("Field {0} ({1}) is mandatory, it must be specified",
getName(),
idDescription
));
} else if (!validateValue()) {
errors.add(MessageFormat.format("Field {0} ({1}) equals \"{2}\", and cannot be parsed as {3}",
getName(),
idDescription,
value,
getType().toString()
));
}
}

return errors;
}

private String getIdDescription() {
if (getParent() != null) {
if (getParent().getType() == MetaField.Type.LIST) {
return getParent().getIdDescription() + "[" + getParent().getChildren().indexOf(this) + "]";
} else {
return getParent().getIdDescription() + "." + getId();
}
} else {
return getId();
}
}

public ConfigNode getParent() {
return parent;
}

public ObservableList<ConfigNode> getChildren() {
return children;
}

public ConfigNode addListItem() {
ConfigNode newChild = new ConfigNode(meta.item, this, true);
children.add(newChild);
return newChild;
}

public boolean isRemovable() {
return removable;
}
}
Loading

0 comments on commit ebe2d79

Please sign in to comment.