diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java index b5acd432..9c35d17f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java @@ -152,6 +152,30 @@ public final class ClientConnection implements GrantEntity { return true; } + public boolean dataEquals(final ClientConnection other) { + if (other == null) { + return true; + } + if (this.clientAddress == null) { + if (other.clientAddress != null) + return false; + } else if (!this.clientAddress.equals(other.clientAddress)) + return false; + if (this.status != other.status) + return false; + if (this.userSessionId == null) { + if (other.userSessionId != null) + return false; + } else if (!this.userSessionId.equals(other.userSessionId)) + return false; + if (this.virtualClientAddress == null) { + if (other.virtualClientAddress != null) + return false; + } else if (!this.virtualClientAddress.equals(other.virtualClientAddress)) + return false; + return true; + } + @Override public String toString() { final StringBuilder builder = new StringBuilder(); diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java index 4460347f..3f044511 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnectionData.java @@ -9,18 +9,21 @@ package ch.ethz.seb.sebserver.gbl.model.session; import java.util.Collection; +import java.util.Iterator; import java.util.List; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import ch.ethz.seb.sebserver.gbl.util.Utils; + public class ClientConnectionData { @JsonProperty("clientConnection") public final ClientConnection clientConnection; @JsonProperty("indicatorValues") - public final Collection indicatorValues; + public final List indicatorValues; @JsonCreator protected ClientConnectionData( @@ -28,7 +31,7 @@ public class ClientConnectionData { @JsonProperty("indicatorValues") final Collection indicatorValues) { this.clientConnection = clientConnection; - this.indicatorValues = indicatorValues; + this.indicatorValues = Utils.immutableListOf(indicatorValues); } protected ClientConnectionData( @@ -36,7 +39,7 @@ public class ClientConnectionData { @JsonProperty("indicatorValues") final List indicatorValues) { this.clientConnection = clientConnection; - this.indicatorValues = indicatorValues; + this.indicatorValues = Utils.immutableListOf(indicatorValues); } @JsonIgnore @@ -52,6 +55,28 @@ public class ClientConnectionData { return this.indicatorValues; } + public boolean dataEquals(final ClientConnectionData other) { + if (!this.clientConnection.dataEquals(other.clientConnection)) { + return false; + } + + if (this.indicatorValues.size() != other.indicatorValues.size()) { + return false; + } + + final Iterator i1 = this.indicatorValues.iterator(); + final Iterator i2 = other.indicatorValues.iterator(); + while (i1.hasNext()) { + final IndicatorValue iv1 = i1.next(); + final IndicatorValue iv2 = i2.next(); + if (iv1.getType() != iv2.getType() || iv1.getValue() != iv2.getValue()) { + return false; + } + } + + return true; + } + @Override public String toString() { final StringBuilder builder = new StringBuilder(); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java index 04651445..f1191983 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java @@ -11,9 +11,12 @@ package ch.ethz.seb.sebserver.gui.service.session; import java.util.Collection; import java.util.Comparator; import java.util.EnumMap; -import java.util.HashMap; -import java.util.Map; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; @@ -41,6 +44,8 @@ public final class ClientConnectionTable { private static final int BOTTOM_PADDING = 20; + private final static String STATUS_LOC_TEXT_KEY_PREFIX = "sebserver.monitoring.connection.status."; + private final static LocTextKey CONNECTION_ID_TEXT_KEY = new LocTextKey("sebserver.monitoring.connection.list.column.id"); private final static LocTextKey CONNECTION_ADDRESS_TEXT_KEY = @@ -56,9 +61,10 @@ public final class ClientConnectionTable { private final Color color1; private final Color color2; private final Color color3; - private int tableWidth; - private final Map tableMapping; + private int tableWidth; + private boolean needsSort = false; + private LinkedHashMap tableMapping; public ClientConnectionTable( final WidgetFactory widgetFactory, @@ -105,7 +111,7 @@ public final class ClientConnectionTable { this.color2 = new Color(display, new RGB(249, 166, 2), 100); this.color3 = new Color(display, new RGB(255, 0, 0), 100); - this.tableMapping = new HashMap<>(); + this.tableMapping = new LinkedHashMap<>(); this.table.layout(); } @@ -121,47 +127,28 @@ public final class ClientConnectionTable { for (final ClientConnectionData data : connectionInfo) { final UpdatableTableItem tableItem = this.tableMapping.computeIfAbsent( data.getConnectionId(), - userIdentifier -> new UpdatableTableItem(this.table, data.getConnectionId())); + userIdentifier -> new UpdatableTableItem(data.getConnectionId())); tableItem.push(data); } } public void updateGUI() { - boolean sort = false; - for (final UpdatableTableItem uti : this.tableMapping.values()) { - if (uti.tableItem == null) { - createTableItem(uti); - updateIndicatorValues(uti, false); - updateConnectionStatusColor(uti); - sort = true; - } else { - if (uti.previous_connectionData == null || !uti.connectionData.clientConnection.status - .equals(uti.previous_connectionData.clientConnection.status)) { - uti.tableItem.setText(0, uti.getConnectionIdentifer()); - uti.tableItem.setText(2, uti.getStatusName()); - updateConnectionStatusColor(uti); - sort = true; - } - if (uti.hasStatus(ConnectionStatus.ESTABLISHED)) { - sort = updateIndicatorValues(uti, true); - } - } - uti.tableItem.getDisplay(); - } - adaptTableWidth(); - if (sort) { + fillTable(); + if (this.needsSort) { sortTable(); } - this.table.getParent().layout(true, true); - } - private void createTableItem(final UpdatableTableItem uti) { - uti.tableItem = new TableItem(this.table, SWT.NONE); - uti.tableItem.setText(0, uti.getConnectionIdentifer()); - uti.tableItem.setText(1, uti.getConnectionAddress()); - uti.tableItem.setText(2, uti.getStatusName()); - uti.tableItem.setData("TABLE_ITEM_DATA", uti); + final TableItem[] items = this.table.getItems(); + final Iterator> iterator = this.tableMapping.entrySet().iterator(); + for (int i = 0; i < items.length; i++) { + final UpdatableTableItem uti = iterator.next().getValue(); + uti.update(items[i], this.needsSort); + } + + this.needsSort = false; + adaptTableWidth(); + this.table.layout(true, true); } private void adaptTableWidth() { @@ -179,99 +166,163 @@ public final class ClientConnectionTable { gridData.heightHint = area.height - BOTTOM_PADDING; } + private void fillTable() { + if (this.tableMapping.size() > this.table.getItemCount()) { + while (this.tableMapping.size() > this.table.getItemCount()) { + new TableItem(this.table, SWT.NONE); + } + this.needsSort = true; + } else if (this.tableMapping.size() < this.table.getItemCount()) { + while (this.tableMapping.size() < this.table.getItemCount()) { + this.table.getItem(0).dispose(); + } + this.needsSort = true; + } + } + private void sortTable() { - System.out.println("************** sortTable"); -// final TableItem[] items = this.table.getItems(); -// Arrays.sort(items, TABLE_COMPARATOR); -// for (final TableItem item : items) { -// final UpdatableTableItem uti = (UpdatableTableItem) item.getData("TABLE_ITEM_DATA"); -// item.dispose(); -// createTableItem(uti); -// updateIndicatorValues(uti, false); -// updateConnectionStatusColor(uti); -// } + this.tableMapping = this.tableMapping.entrySet() + .stream() + .sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue())) + .collect(Collectors.toMap( + Entry::getKey, + Entry::getValue, + (e1, e2) -> e1, LinkedHashMap::new)); } - private boolean updateIndicatorValues(final UpdatableTableItem uti, final boolean established) { - boolean sort = false; - for (final IndicatorValue iv : uti.connectionData.indicatorValues) { - final IndicatorData indicatorData = this.indicatorMapping.get(iv.getType()); - if (indicatorData != null) { - if (!established && iv.getType() == IndicatorType.LAST_PING) { - uti.tableItem.setText(indicatorData.index, "--"); - } else { - uti.tableItem.setText(indicatorData.index, String.valueOf(iv.getValue())); - final Color newColor = this.getColorForValue(indicatorData, iv.getValue()); - final Color background = uti.tableItem.getBackground(indicatorData.index); - if (newColor != background) { - uti.tableItem.setBackground(indicatorData.index, newColor); - sort = true; - } - } - } - } - return sort; - } - - private void updateConnectionStatusColor(final UpdatableTableItem uti) { - switch (uti.connectionData.clientConnection.status) { - case ESTABLISHED: { - uti.tableItem.setBackground(2, this.color1); - break; - } - case ABORTED: { - uti.tableItem.setBackground(2, this.color3); - break; - } - default: { - uti.tableItem.setBackground(2, this.color2); - } - } - } - - private Color getColorForValue(final IndicatorData indicatorData, final double value) { - - for (int i = 0; i < indicatorData.thresholdColor.length; i++) { - if (value < indicatorData.thresholdColor[i].value) { - return indicatorData.thresholdColor[i].color; - } - } - - return indicatorData.thresholdColor[indicatorData.thresholdColor.length - 1].color; - } - - private static final class UpdatableTableItem { + private final class UpdatableTableItem implements Comparable { @SuppressWarnings("unused") final Long connectionId; - TableItem tableItem; - ClientConnectionData previous_connectionData; - ClientConnectionData connectionData; + private boolean changed = false; + private ClientConnectionData connectionData; + private int[] thresholdColorIndices; - private UpdatableTableItem(final Table parent, final Long connectionId) { - this.tableItem = null; + UpdatableTableItem(final Long connectionId) { this.connectionId = connectionId; } - public void update(final TableItem tableItem) { - - } - - public String getStatusName() { - if (this.connectionData != null && this.connectionData.clientConnection.status != null) { - return this.connectionData.clientConnection.status.name(); + void update(final TableItem tableItem, final boolean force) { + if (force || this.changed) { + update(tableItem); } - return ConnectionStatus.UNDEFINED.name(); + this.changed = false; } - public String getConnectionAddress() { + void update(final TableItem tableItem) { + updateData(tableItem); + if (this.connectionData != null) { + updateConnectionStatusColor(tableItem); + updateIndicatorValues(tableItem); + } + } + + void updateData(final TableItem tableItem) { + tableItem.setText(0, getConnectionIdentifer()); + tableItem.setText(1, getConnectionAddress()); + tableItem.setText(2, getStatusName()); + } + + void updateConnectionStatusColor(final TableItem tableItem) { + switch (this.connectionData.clientConnection.status) { + case ESTABLISHED: { + tableItem.setBackground(2, ClientConnectionTable.this.color1); + break; + } + case ABORTED: { + tableItem.setBackground(2, ClientConnectionTable.this.color3); + break; + } + default: { + tableItem.setBackground(2, ClientConnectionTable.this.color2); + } + } + } + + void updateIndicatorValues(final TableItem tableItem) { + + final boolean fillEmpty = (this.connectionData == null || + this.connectionData.clientConnection.status != ConnectionStatus.ESTABLISHED); + + for (int i = 0; i < this.connectionData.indicatorValues.size(); i++) { + final IndicatorValue indicatorValue = this.connectionData.indicatorValues.get(i); + final IndicatorData indicatorData = + ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getType()); + + if (fillEmpty) { + tableItem.setText(indicatorData.index, Constants.EMPTY_NOTE); + tableItem.setBackground( + indicatorData.index, + indicatorData.defaultColor); + } else { + tableItem.setText(indicatorData.index, String.valueOf(indicatorValue.getValue())); + tableItem.setBackground( + indicatorData.index, + indicatorData.thresholdColor[this.thresholdColorIndices[i]].color); + } + } + } + + @Override + public int compareTo(final UpdatableTableItem other) { + return Comparator.comparingInt(UpdatableTableItem::statusWeight) + .thenComparingInt(UpdatableTableItem::thresholdsWeight) + .thenComparing(UpdatableTableItem::getConnectionIdentifer) + .compare(this, other); + } + + int statusWeight() { + if (this.connectionData == null) { + return 100; + } + + switch (this.connectionData.clientConnection.status) { + case ABORTED: + return 0; + case CONNECTION_REQUESTED: + case AUTHENTICATED: + return 1; + case ESTABLISHED: + return 2; + case CLOSED: + return 3; + default: + return 10; + } + } + + int thresholdsWeight() { + if (this.thresholdColorIndices == null) { + return 100; + } + + int weight = 0; + for (int i = 0; i < this.thresholdColorIndices.length; i++) { + weight += this.thresholdColorIndices[i]; + } + return 100 - weight; + } + + String getStatusName() { + + String name; + if (this.connectionData != null && this.connectionData.clientConnection.status != null) { + name = this.connectionData.clientConnection.status.name(); + } else { + name = ConnectionStatus.UNDEFINED.name(); + } + return ClientConnectionTable.this.widgetFactory.getI18nSupport() + .getText(STATUS_LOC_TEXT_KEY_PREFIX + name, name); + } + + String getConnectionAddress() { if (this.connectionData != null && this.connectionData.clientConnection.clientAddress != null) { return this.connectionData.clientConnection.clientAddress; } return Constants.EMPTY_NOTE; } - public String getConnectionIdentifer() { + String getConnectionIdentifer() { if (this.connectionData != null && this.connectionData.clientConnection.userSessionId != null) { return this.connectionData.clientConnection.userSessionId; } @@ -279,35 +330,71 @@ public final class ClientConnectionTable { return "--"; } - public boolean hasStatus(final ConnectionStatus status) { - if (this.connectionData != null && this.connectionData.clientConnection != null) { - return status == this.connectionData.clientConnection.status; + void push(final ClientConnectionData connectionData) { + this.changed = this.connectionData == null || + !this.connectionData.dataEquals(connectionData); + + ClientConnectionTable.this.needsSort = this.connectionData == null || + this.connectionData.clientConnection.status != connectionData.clientConnection.status; + + if (this.thresholdColorIndices == null) { + this.thresholdColorIndices = new int[connectionData.indicatorValues.size()]; } - return false; - } + for (int i = 0; i < connectionData.indicatorValues.size(); i++) { + final IndicatorValue indicatorValue = connectionData.indicatorValues.get(i); + final IndicatorData indicatorData = + ClientConnectionTable.this.indicatorMapping.get(indicatorValue.getType()); + + final double value = indicatorValue.getValue(); + final int colorIndex = getColorIndex(indicatorData, value); + if (this.thresholdColorIndices[i] != colorIndex) { + ClientConnectionTable.this.needsSort = true; + } + this.thresholdColorIndices[i] = colorIndex; + } - public void push(final ClientConnectionData connectionData) { - this.previous_connectionData = this.connectionData; this.connectionData = connectionData; } + + } + + private static final int getColorIndex(final IndicatorData indicatorData, final double value) { + for (int j = 0; j < indicatorData.thresholdColor.length; j++) { + if (value < indicatorData.thresholdColor[j].value) { + return j; + } + } + + return indicatorData.thresholdColor.length - 1; } private static final class IndicatorData { final int index; @SuppressWarnings("unused") final Indicator indicator; + final Color defaultColor; final ThresholdColor[] thresholdColor; protected IndicatorData(final Indicator indicator, final int index, final Display display) { this.indicator = indicator; this.index = index; + + if (StringUtils.isNotBlank(indicator.defaultColor)) { + final RGB rgb = new RGB( + Integer.parseInt(indicator.defaultColor.substring(0, 2), 16), + Integer.parseInt(indicator.defaultColor.substring(2, 4), 16), + Integer.parseInt(indicator.defaultColor.substring(4, 6), 16)); + this.defaultColor = new Color(display, rgb, 100); + } else { + this.defaultColor = new Color(display, new RGB(255, 255, 255), 100); + } + this.thresholdColor = new ThresholdColor[indicator.thresholds.size()]; for (int i = 0; i < indicator.thresholds.size(); i++) { this.thresholdColor[i] = new ThresholdColor(indicator.thresholds.get(i), display); } } - } private static final class ThresholdColor { @@ -316,29 +403,15 @@ public final class ClientConnectionTable { protected ThresholdColor(final Threshold threshold, final Display display) { this.value = threshold.value; - final RGB rgb = new RGB( - Integer.parseInt(threshold.color.substring(0, 2), 16), - Integer.parseInt(threshold.color.substring(2, 4), 16), - Integer.parseInt(threshold.color.substring(4, 6), 16)); - this.color = new Color(display, rgb, 100); - } - } - - private static final Comparator TABLE_COMPARATOR = new Comparator<>() { - - @Override - public int compare(final TableItem o1, final TableItem o2) { - final String name1 = o1.getText(0); - final String name2 = o2.getText(0); - if (name1 != null) { - return name1.compareTo(name2); - } else if (name2 != null) { - return name2.compareTo(name1); + if (StringUtils.isNotBlank(threshold.color)) { + final RGB rgb = new RGB( + Integer.parseInt(threshold.color.substring(0, 2), 16), + Integer.parseInt(threshold.color.substring(2, 4), 16), + Integer.parseInt(threshold.color.substring(4, 6), 16)); + this.color = new Color(display, rgb, 100); } else { - return -1; + this.color = new Color(display, new RGB(255, 255, 255), 100); } } - - }; - + } } diff --git a/src/main/resources/config/application-dev.properties b/src/main/resources/config/application-dev.properties index 081348b9..db3d7e4b 100644 --- a/src/main/resources/config/application-dev.properties +++ b/src/main/resources/config/application-dev.properties @@ -4,7 +4,3 @@ server.address=localhost server.port=8080 server.servlet.context-path=/ -#sebserver.webservice.api.redirect.unauthorized=http://localhost:8080/gui - - -