diff --git a/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF index 0a26e77fc02..8a2c32092f2 100644 --- a/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF @@ -7,6 +7,8 @@ Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Require-Bundle: com.sap.sailing.domain.common;bundle-version="1.0.0" Export-Package: com.sap.sailing.domain.base, + com.sap.sailing.domain.base.configuration, + com.sap.sailing.domain.base.configuration.impl, com.sap.sailing.domain.base.impl, com.sap.sailing.domain.base.racegroup, com.sap.sailing.domain.base.racegroup.impl, diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/DeviceConfiguration.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfiguration.java similarity index 85% rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/DeviceConfiguration.java rename to java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfiguration.java index e8986f8308b..df7e8c388b5 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/DeviceConfiguration.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfiguration.java @@ -1,8 +1,7 @@ -package com.sap.sailing.domain.base; +package com.sap.sailing.domain.base.configuration; import java.util.List; - /** * Interface holding information about tablet's (RCApp) configuration. */ diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/DeviceConfigurationIdentifier.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfigurationIdentifier.java similarity index 59% rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/DeviceConfigurationIdentifier.java rename to java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfigurationIdentifier.java index 3a119979388..3ba79ef24db 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/DeviceConfigurationIdentifier.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfigurationIdentifier.java @@ -1,11 +1,11 @@ -package com.sap.sailing.domain.base; +package com.sap.sailing.domain.base.configuration; + +import java.io.Serializable; /** * Each tablet configuration is bound to a specific client. Use this interface instead of a plain {@link String} to * enable additions (like event-specific configurations). */ -public interface DeviceConfigurationIdentifier { - +public interface DeviceConfigurationIdentifier extends Serializable { String getClientIdentifier(); - } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfigurationMatcher.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfigurationMatcher.java new file mode 100644 index 00000000000..d51ba5df2be --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/DeviceConfigurationMatcher.java @@ -0,0 +1,12 @@ +package com.sap.sailing.domain.base.configuration; + +import java.io.Serializable; + +public interface DeviceConfigurationMatcher extends Serializable { + public final static int RANK_SINGLE = 1; + public final static int RANK_MULTI = 2; + public final static int RANK_ANY = 3; + + int getMatchingRank(); + boolean matches(DeviceConfigurationIdentifier identifier); +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/DeviceConfigurationIdentifierImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationIdentifierImpl.java similarity index 58% rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/DeviceConfigurationIdentifierImpl.java rename to java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationIdentifierImpl.java index 9e2b14eb842..eae7ede50ed 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/DeviceConfigurationIdentifierImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationIdentifierImpl.java @@ -1,11 +1,13 @@ -package com.sap.sailing.domain.base.impl; +package com.sap.sailing.domain.base.configuration.impl; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; public class DeviceConfigurationIdentifierImpl implements DeviceConfigurationIdentifier { + + private static final long serialVersionUID = 2785847392322741468L; private final String clientIdentifier; - + public DeviceConfigurationIdentifierImpl(String clientIdentifier) { this.clientIdentifier = clientIdentifier; } @@ -15,9 +17,4 @@ public class DeviceConfigurationIdentifierImpl implements DeviceConfigurationIde return clientIdentifier; } - @Override - public String toString() { - return "TabletConfigurationIdentifierImpl [clientIdentifier=" + clientIdentifier + "]"; - } - } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/DeviceConfigurationImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationImpl.java similarity index 90% rename from java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/DeviceConfigurationImpl.java rename to java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationImpl.java index 39821ae3616..e1bdb872341 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/DeviceConfigurationImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationImpl.java @@ -1,7 +1,7 @@ -package com.sap.sailing.domain.base.impl; +package com.sap.sailing.domain.base.configuration.impl; import java.util.List; -import com.sap.sailing.domain.base.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; public class DeviceConfigurationImpl implements DeviceConfiguration { diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMapImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMapImpl.java new file mode 100644 index 00000000000..b15f290ae13 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMapImpl.java @@ -0,0 +1,51 @@ +package com.sap.sailing.domain.base.configuration.impl; + +import java.util.concurrent.ConcurrentHashMap; + +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; + +public class DeviceConfigurationMapImpl extends ConcurrentHashMap { + + private static final long serialVersionUID = -8009136964737670452L; + + private interface Action { + DeviceConfiguration call(DeviceConfigurationMatcher matcher); + } + + public DeviceConfiguration getByMatch(DeviceConfigurationIdentifier key) { + return doByMatch(key, new Action() { + @Override + public DeviceConfiguration call(DeviceConfigurationMatcher match) { + return get(match); + } + }); + } + + public DeviceConfiguration removeByMatch(DeviceConfigurationIdentifier key) { + return doByMatch(key, new Action() { + @Override + public DeviceConfiguration call(DeviceConfigurationMatcher match) { + return remove(match); + } + }); + } + + private DeviceConfiguration doByMatch(DeviceConfigurationIdentifier key, Action action) { + DeviceConfigurationMatcher match = null; + for (Entry entry : entrySet()) { + if (entry.getKey().matches(key)) { + if (match == null || match.getMatchingRank() > entry.getKey().getMatchingRank()) { + match = entry.getKey(); + } + } + } + if (match != null) { + return action.call(match); + } else { + return null; + } + } + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherAny.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherAny.java new file mode 100644 index 00000000000..400e0cf0574 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherAny.java @@ -0,0 +1,21 @@ +package com.sap.sailing.domain.base.configuration.impl; + +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; + +public enum DeviceConfigurationMatcherAny implements DeviceConfigurationMatcher { + INSTANCE; + + private static final long serialVersionUID = 4574449656453672610L; + + @Override + public boolean matches(DeviceConfigurationIdentifier identifier) { + return true; + } + + @Override + public int getMatchingRank() { + return RANK_ANY; + } + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherMulti.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherMulti.java new file mode 100644 index 00000000000..e6c64cead51 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherMulti.java @@ -0,0 +1,57 @@ +package com.sap.sailing.domain.base.configuration.impl; + +import java.util.List; + +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; + +public class DeviceConfigurationMatcherMulti implements DeviceConfigurationMatcher { + + private static final long serialVersionUID = 2372299957258702516L; + + private final List clientIdentifiers; + + public DeviceConfigurationMatcherMulti(List matchingClientIdentifiers) { + this.clientIdentifiers = matchingClientIdentifiers; + } + + @Override + public boolean matches(DeviceConfigurationIdentifier identifier) { + return this.clientIdentifiers.contains(identifier.getClientIdentifier()); + } + + @Override + public int getMatchingRank() { + return RANK_MULTI; + } + + public List getClientIdentifiers() { + return clientIdentifiers; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((clientIdentifiers == null) ? 0 : clientIdentifiers.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DeviceConfigurationMatcherMulti other = (DeviceConfigurationMatcherMulti) obj; + if (clientIdentifiers == null) { + if (other.clientIdentifiers != null) + return false; + } else if (!clientIdentifiers.equals(other.clientIdentifiers)) + return false; + return true; + } + +} diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherSingle.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherSingle.java new file mode 100644 index 00000000000..c1f695cb2e5 --- /dev/null +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/configuration/impl/DeviceConfigurationMatcherSingle.java @@ -0,0 +1,54 @@ +package com.sap.sailing.domain.base.configuration.impl; + +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; + +public class DeviceConfigurationMatcherSingle implements DeviceConfigurationMatcher { + + private static final long serialVersionUID = -3662453614818373801L; + private final String clientIdentifier; + + public DeviceConfigurationMatcherSingle(String matchingClientIdentifier) { + this.clientIdentifier = matchingClientIdentifier; + } + + @Override + public boolean matches(DeviceConfigurationIdentifier identifier) { + return this.clientIdentifier.equals(identifier.getClientIdentifier()); + } + + @Override + public int getMatchingRank() { + return RANK_SINGLE; + } + + public String getClientIdentifier() { + return clientIdentifier; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((clientIdentifier == null) ? 0 : clientIdentifier.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DeviceConfigurationMatcherSingle other = (DeviceConfigurationMatcherSingle) obj; + if (clientIdentifier == null) { + if (other.clientIdentifier != null) + return false; + } else if (!clientIdentifier.equals(other.clientIdentifier)) + return false; + return true; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java index c394bea8708..40770d28c86 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/AdminConsoleEntryPoint.java @@ -47,6 +47,9 @@ public class AdminConsoleEntryPoint extends AbstractEntryPoint implements Regatt tabPanel.setSize("99%", "95%"); verticalPanel.add(tabPanel); //, 10, 10); + final DeviceConfigurationPanel deviceConfigurationPanel = new DeviceConfigurationPanel(sailingService, stringMessages, this); + tabPanel.add(deviceConfigurationPanel, "Device Configuration", false); + regattaDisplayers = new HashSet(); SailingEventManagementPanel sailingEventManagementPanel = new SailingEventManagementPanel(sailingService, this, stringMessages); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationCreateDialog.java new file mode 100644 index 00000000000..6dce042585a --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationCreateDialog.java @@ -0,0 +1,177 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.Image; +import com.google.gwt.user.client.ui.ListBox; +import com.google.gwt.user.client.ui.PushButton; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.ui.client.DataEntryDialog; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO.Type; + +public class DeviceConfigurationCreateDialog extends DataEntryDialog { + + public static class DuplicationValidator implements Validator { + + private List allMatchers; + + public DuplicationValidator(List allMatchers) { + this.allMatchers = allMatchers; + } + + @Override + public String getErrorMessage(DeviceConfigurationMatcherDTO valueToValidate) { + for (DeviceConfigurationMatcherDTO existingMatcher : allMatchers) { + if (existingMatcher.type.equals(valueToValidate.type)) { + switch (valueToValidate.type) { + case SINGLE: + if (existingMatcher.clients.containsAll(valueToValidate.clients)) { + return "There is already a configuration for such a matcher."; + } + break; + case MULTI: + if (existingMatcher.clients.containsAll(valueToValidate.clients) && + valueToValidate.clients.containsAll(existingMatcher.clients)) { + return "There is already a configuration for such a matcher."; + } + break; + case ANY: + return "There is already a configuration matching all devices."; + default: + break; + } + } + } + return null; + } + + } + + private static AdminConsoleResources resources = GWT.create(AdminConsoleResources.class); + private ListBox typeBox; + private List devicesBoxes; + + public DeviceConfigurationCreateDialog(StringMessages stringMessages, + Validator validator, + com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback callback) { + super("Create Device Configuration", "Specify for which devices the new configuration should apply", + "Create", stringMessages.cancel(), validator, callback); + this.devicesBoxes = new ArrayList(); + } + + @Override + protected Widget getAdditionalWidget() { + final Grid valueGrid = new Grid(2, 2); + + valueGrid.setWidget(0, 0, createLabel("Matcher type")); + typeBox = createListBox(false); + typeBox.addItem(DeviceConfigurationMatcherDTO.Type.SINGLE.name()); + typeBox.addItem(DeviceConfigurationMatcherDTO.Type.MULTI.name()); + typeBox.addItem(DeviceConfigurationMatcherDTO.Type.ANY.name()); + valueGrid.setWidget(0, 1, typeBox); + valueGrid.setWidget(1, 0, createLabel("Matching devices")); + + final Grid devicesGrid = new Grid(2, 2); + TextBox firstDeviceBox = createTextBox(""); + devicesGrid.setWidget(0, 0, firstDeviceBox); + devicesBoxes.add(firstDeviceBox); + + final Button addDeviceButton = new Button("Add Device"); + addDeviceButton.setVisible(false); + addDeviceButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + devicesGrid.insertRow(0); + TextBox deviceBox = createTextBox(""); + devicesBoxes.add(deviceBox); + devicesGrid.setWidget(0, 0, deviceBox); + devicesGrid.setWidget(0, 1, createRemoveButton(devicesGrid)); + } + }); + devicesGrid.setWidget(1, 0, addDeviceButton); + valueGrid.setWidget(1, 1, devicesGrid); + + typeBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + Type type = DeviceConfigurationMatcherDTO.Type.valueOf(typeBox.getValue(typeBox.getSelectedIndex())); + switch (type) { + case SINGLE: + valueGrid.getWidget(1, 0).setVisible(true); + valueGrid.getWidget(1, 1).setVisible(true); + devicesGrid.getWidget(0, 0).setVisible(true); + devicesGrid.getWidget(1, 0).setVisible(false); + for (int i = 0; i < devicesGrid.getRowCount() - 2; i++) { + devicesGrid.getWidget(i, 0).setVisible(false); + devicesGrid.getWidget(i, 1).setVisible(false); + } + break; + case MULTI: + valueGrid.getWidget(1, 0).setVisible(true); + valueGrid.getWidget(1, 1).setVisible(true); + devicesGrid.getWidget(0, 0).setVisible(true); + devicesGrid.getWidget(1, 0).setVisible(true); + for (int i = 0; i < devicesGrid.getRowCount() - 2; i++) { + devicesGrid.getWidget(i, 0).setVisible(true); + devicesGrid.getWidget(i, 1).setVisible(true); + } + break; + default: + valueGrid.getWidget(1, 0).setVisible(false); + valueGrid.getWidget(1, 1).setVisible(false); + break; + } + } + }); + + return valueGrid; + } + + @Override + protected DeviceConfigurationMatcherDTO getResult() { + DeviceConfigurationMatcherDTO dto = new DeviceConfigurationMatcherDTO(); + dto.type = DeviceConfigurationMatcherDTO.Type.valueOf(typeBox.getValue(typeBox.getSelectedIndex())); + switch (dto.type) { + case SINGLE: + dto.clients = Arrays.asList(devicesBoxes.get(0).getText()); + break; + case MULTI: + dto.clients = new ArrayList(); + for (TextBox textBox : devicesBoxes) { + dto.clients.add(textBox.getText()); + } + break; + default: + dto.clients = Collections.emptyList(); + break; + } + return dto; + } + + private PushButton createRemoveButton(final Grid devicesGrid) { + PushButton removeButton = new PushButton(new Image(resources.removeIcon())); + removeButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + int rowToBeRemoved = devicesGrid.getCellForEvent(event).getRowIndex(); + devicesBoxes.remove(devicesGrid.getWidget(rowToBeRemoved, 0)); + devicesGrid.removeRow(rowToBeRemoved); + } + }); + return removeButton; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationDetailComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationDetailComposite.java new file mode 100644 index 00000000000..a169b346c94 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationDetailComposite.java @@ -0,0 +1,197 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.Arrays; + +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.event.dom.client.KeyUpHandler; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.CaptionPanel; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.sap.sailing.gwt.ui.client.ErrorReporter; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; + +public class DeviceConfigurationDetailComposite extends Composite { + + private final SailingServiceAsync sailingService; + private final ErrorReporter errorReporter; + + private CaptionPanel captionPanel; + private Grid mainGrid; + private Button updateButton; + + private DeviceConfigurationMatcherDTO matcher; + private DeviceConfigurationDTO configuration; + + private TextBox allowedCourseAreasBox; + private TextBox minRoundsBox; + private TextBox maxRoundsBox; + private TextBox mailRecipientBox; + + public DeviceConfigurationDetailComposite(final SailingServiceAsync sailingService, final ErrorReporter errorReporter, StringMessages stringMessages) { + this.sailingService = sailingService; + this.errorReporter = errorReporter; + + this.matcher = null; + this.configuration = null; + + captionPanel = new CaptionPanel("Configuration"); + VerticalPanel verticalPanel = new VerticalPanel(); + mainGrid = new Grid(4, 2); + updateButton = new Button("Update"); + updateButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + updateConfiguration(sailingService, errorReporter); + } + }); + + verticalPanel.add(mainGrid); + verticalPanel.add(updateButton); + captionPanel.add(verticalPanel); + initWidget(captionPanel); + } + + public void setConfiguration(final DeviceConfigurationMatcherDTO matcher) { + if (matcher == null) { + clearUi(); + } else { + sailingService.getDeviceConfiguration(matcher, new AsyncCallback() { + @Override + public void onSuccess(DeviceConfigurationDTO result) { + setupUi(matcher, result); + } + + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError(caught.getMessage()); + } + }); + } + } + + private void markAsDrity(boolean dirty) { + if (dirty) { + captionPanel.setCaptionText("Configuration*"); + } else { + captionPanel.setCaptionText("Configuration"); + } + } + + private void setupUi(DeviceConfigurationMatcherDTO matcher, DeviceConfigurationDTO result) { + clearUi(); + this.matcher = matcher; + this.configuration = result; + + allowedCourseAreasBox = new TextBox(); + allowedCourseAreasBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + if (allowedCourseAreasBox.getText().isEmpty()) { + configuration.allowedCourseAreaNames = null; + } else { + configuration.allowedCourseAreaNames = Arrays.asList(allowedCourseAreasBox.getText().split(",")); + } + } + }); + allowedCourseAreasBox.addKeyUpHandler(dirtyMarker); + if (result.allowedCourseAreaNames != null) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < result.allowedCourseAreaNames.size(); i++) { + builder.append(result.allowedCourseAreaNames.get(i)); + builder.append(','); + } + allowedCourseAreasBox.setText(builder.substring(0, builder.length() - 1)); + } + mainGrid.setWidget(0, 0, new Label("Allowed Course Areas")); + mainGrid.setWidget(0, 1, allowedCourseAreasBox); + + minRoundsBox = new TextBox(); + minRoundsBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + configuration.minRoundsForCourse = minRoundsBox.getText().isEmpty() ? null : Integer.valueOf(minRoundsBox.getText()); + } + }); + minRoundsBox.addKeyUpHandler(dirtyMarker); + if (result.minRoundsForCourse != null) { + minRoundsBox.setText(result.minRoundsForCourse.toString()); + } + mainGrid.setWidget(1, 0, new Label("Minimum Rounds for Course")); + mainGrid.setWidget(1, 1, minRoundsBox); + + maxRoundsBox = new TextBox(); + maxRoundsBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + configuration.maxRoundsForCourse = maxRoundsBox.getText().isEmpty() ? null : Integer.valueOf(maxRoundsBox.getText()); + } + }); + maxRoundsBox.addKeyUpHandler(dirtyMarker); + if (result.maxRoundsForCourse != null) { + maxRoundsBox.setText(result.maxRoundsForCourse.toString()); + } + mainGrid.setWidget(2, 0, new Label("Maximum Rounds for Course")); + mainGrid.setWidget(2, 1, maxRoundsBox); + + mailRecipientBox = new TextBox(); + mailRecipientBox.addChangeHandler(new ChangeHandler() { + @Override + public void onChange(ChangeEvent event) { + configuration.resultsMailRecipient = mailRecipientBox.getText().isEmpty() ? null : mailRecipientBox.getText(); + } + }); + mailRecipientBox.addKeyUpHandler(dirtyMarker); + if (result.resultsMailRecipient != null) { + mailRecipientBox.setText(result.resultsMailRecipient); + } + mainGrid.setWidget(3, 0, new Label("Results Mail Recipient")); + mainGrid.setWidget(3, 1, mailRecipientBox); + } + + private void clearUi() { + this.matcher = null; + this.configuration = null; + mainGrid.clear(); + } + + private void updateConfiguration(final SailingServiceAsync sailingService, final ErrorReporter errorReporter) { + if (matcher == null || configuration == null) { + errorReporter.reportError("Invalid state."); + return; + } + sailingService.addDeviceConfiguration(matcher.type, matcher.clients, + configuration.allowedCourseAreaNames, configuration.minRoundsForCourse, + configuration.maxRoundsForCourse, configuration.resultsMailRecipient, + new AsyncCallback() { + @Override + public void onSuccess(DeviceConfigurationMatcherDTO matcher) { + markAsDrity(false); + } + + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError(caught.getMessage()); + } + }); + } + + private KeyUpHandler dirtyMarker = new KeyUpHandler() { + @Override + public void onKeyUp(KeyUpEvent event) { + markAsDrity(true); + } + }; + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationListComposite.java new file mode 100644 index 00000000000..aaccf6c10f0 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationListComposite.java @@ -0,0 +1,162 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.cellview.client.CellTable; +import com.google.gwt.user.cellview.client.ColumnSortEvent; +import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; +import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.view.client.ListDataProvider; +import com.google.gwt.view.client.MultiSelectionModel; +import com.google.gwt.view.client.SelectionChangeEvent; +import com.google.gwt.view.client.SelectionModel; +import com.sap.sailing.gwt.ui.client.ErrorReporter; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.client.SelectionProvider; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; + +public class DeviceConfigurationListComposite extends Composite { + + private final SelectionModel configurationSelectionModel; + private final CellTable configurationTable; + private ListDataProvider configurationsDataProvider; + + + private final SimplePanel mainPanel; + private final VerticalPanel panel; + + private final Label noConfigurationsLabel; + + private final SailingServiceAsync sailingService; + private final ErrorReporter errorReporter; + private final StringMessages stringMessages; + + private static AdminConsoleTableResources tableResource = GWT.create(AdminConsoleTableResources.class); + + public DeviceConfigurationListComposite(final SailingServiceAsync sailingService, + final SelectionProvider selectionProvider, + final ErrorReporter errorReporter, final StringMessages stringMessages) { + this.sailingService = sailingService; + this.errorReporter = errorReporter; + this.stringMessages = stringMessages; + + mainPanel = new SimplePanel(); + panel = new VerticalPanel(); + mainPanel.setWidget(panel); + + noConfigurationsLabel = new Label("There are no configurations."); + noConfigurationsLabel.setWordWrap(false); + panel.add(noConfigurationsLabel); + + configurationsDataProvider = new ListDataProvider(); + refreshTable(); + + configurationTable = createConfigurationTable(); + configurationTable.setVisible(true); + + configurationSelectionModel = new MultiSelectionModel(); + configurationSelectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { + @SuppressWarnings("unchecked") + @Override + public void onSelectionChange(SelectionChangeEvent event) { + selectionProvider.setSelection(getSelectedConfigurations()); + } + }); + configurationTable.setSelectionModel(configurationSelectionModel); + panel.add(configurationTable); + + initWidget(mainPanel); + } + + public void refreshTable() { + sailingService.getDeviceConfigurationMatchers(new AsyncCallback>() { + + @Override + public void onSuccess(List result) { + if (configurationsDataProvider.getList().isEmpty()) { + configurationTable.getColumnSortList().clear(); + configurationTable.getColumnSortList().push(configurationTable.getColumn(0)); + } + configurationsDataProvider.getList().clear(); + configurationsDataProvider.getList().addAll(result); + ColumnSortEvent.fire(configurationTable, configurationTable.getColumnSortList()); + + noConfigurationsLabel.setVisible(false); + } + + @Override + public void onFailure(Throwable caught) { + noConfigurationsLabel.setText("Error retrieving configuration data from server."); + noConfigurationsLabel.setVisible(true); + configurationTable.setVisible(false); + errorReporter.reportError("Error retrieving configuration data from server: " + caught.getMessage()); + } + }); + } + + private CellTable createConfigurationTable() { + CellTable table = new CellTable( + /* pageSize */10000, tableResource); + configurationsDataProvider.addDataDisplay(table); + table.setWidth("100%"); + + ListHandler columnSortHandler = + new ListHandler(configurationsDataProvider.getList()); + table.addColumnSortHandler(columnSortHandler); + + TextColumn identifierTypeColumn = + new TextColumn() { + @Override + public String getValue(DeviceConfigurationMatcherDTO identifier) { + return identifier.type.name(); + } + }; + identifierTypeColumn.setSortable(true); + columnSortHandler.setComparator(identifierTypeColumn, new Comparator() { + @Override + public int compare(DeviceConfigurationMatcherDTO r1, DeviceConfigurationMatcherDTO r2) { + return new Integer(r1.rank).compareTo(r2.rank); + } + }); + + TextColumn identifierNameColumn = + new TextColumn() { + @Override + public String getValue(DeviceConfigurationMatcherDTO identifier) { + return identifier.clients.toString(); + } + }; + identifierNameColumn.setSortable(true); + columnSortHandler.setComparator(identifierNameColumn, new Comparator() { + @Override + public int compare(DeviceConfigurationMatcherDTO r1, DeviceConfigurationMatcherDTO r2) { + return r1.toString().compareTo(r2.toString()); + } + }); + + table.addColumn(identifierTypeColumn, "Matcher"); + table.addColumn(identifierNameColumn, "Device"); + return table; + } + + private List getSelectedConfigurations() { + List result = new ArrayList(); + if (configurationsDataProvider != null) { + for (DeviceConfigurationMatcherDTO regatta : configurationsDataProvider.getList()) { + if (configurationSelectionModel.isSelected(regatta)) { + result.add(regatta); + } + } + } + return result; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationPanel.java new file mode 100644 index 00000000000..e5dddad69dd --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/DeviceConfigurationPanel.java @@ -0,0 +1,166 @@ +package com.sap.sailing.gwt.ui.adminconsole; + +import java.util.Arrays; +import java.util.List; + +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HasVerticalAlignment; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.sap.sailing.gwt.ui.client.DataEntryDialog.DialogCallback; +import com.sap.sailing.gwt.ui.client.DataEntryDialog.Validator; +import com.sap.sailing.gwt.ui.client.ErrorReporter; +import com.sap.sailing.gwt.ui.client.SailingServiceAsync; +import com.sap.sailing.gwt.ui.client.SelectionChangeListener; +import com.sap.sailing.gwt.ui.client.SelectionProvider; +import com.sap.sailing.gwt.ui.client.SelectionProviderImpl; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; + +public class DeviceConfigurationPanel extends SimplePanel implements SelectionChangeListener { + + private final SailingServiceAsync sailingService; + private final StringMessages stringMessages; + private final ErrorReporter errorReporter; + + private Button addConfigurationButton; + private Button removeConfigurationButton; + private DeviceConfigurationListComposite listComposite; + private DeviceConfigurationDetailComposite detailComposite; + + private final SelectionProvider selectionProvider; + + public DeviceConfigurationPanel(SailingServiceAsync sailingService, StringMessages stringMessages, ErrorReporter reporter) { + this.sailingService = sailingService; + this.stringMessages = stringMessages; + this.errorReporter = reporter; + + this.selectionProvider = new SelectionProviderImpl(true); + this.selectionProvider.addSelectionChangeListener(this); + + setupUi(); + } + + private void setupUi() { + VerticalPanel mainPanel = new VerticalPanel(); + setWidget(mainPanel); + mainPanel.setWidth("100%"); + setupControlPanel(mainPanel); + setupConfigurationPanels(mainPanel); + } + + private void setupControlPanel(VerticalPanel mainPanel) { + HorizontalPanel deviceManagementControlPanel = new HorizontalPanel(); + deviceManagementControlPanel.setSpacing(5); + addConfigurationButton = new Button("Add Configuration"); + addConfigurationButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + addConfiguration(); + } + }); + deviceManagementControlPanel.add(addConfigurationButton); + + removeConfigurationButton = new Button(stringMessages.remove()); + removeConfigurationButton.setEnabled(false); + removeConfigurationButton.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + removeConfiguration(); + } + }); + deviceManagementControlPanel.add(removeConfigurationButton); + mainPanel.add(deviceManagementControlPanel); + } + + private void setupConfigurationPanels(VerticalPanel mainPanel) { + Grid grid = new Grid(1 ,2); + mainPanel.add(grid); + + listComposite = new DeviceConfigurationListComposite(sailingService, selectionProvider, + errorReporter, stringMessages); + grid.setWidget(0, 0, listComposite); + grid.getRowFormatter().setVerticalAlign(0, HasVerticalAlignment.ALIGN_TOP); + grid.getColumnFormatter().getElement(1).getStyle().setPaddingTop(2.0, Unit.EM); + + detailComposite = new DeviceConfigurationDetailComposite(sailingService, errorReporter, stringMessages); + detailComposite.setVisible(false); + grid.setWidget(0, 1, detailComposite); + } + + @Override + public void onSelectionChange(List selectedConfigurations) { + if (selectedConfigurations.size() == 1 && selectedConfigurations.iterator().hasNext()) { + detailComposite.setConfiguration(selectedConfigurations.iterator().next()); + detailComposite.setVisible(true); + } else { + detailComposite.setConfiguration(null); + detailComposite.setVisible(false); + } + removeConfigurationButton.setEnabled(!selectedConfigurations.isEmpty()); + } + + private void addConfiguration() { + sailingService.getDeviceConfigurationMatchers(new AsyncCallback>() { + @Override + public void onSuccess(List allMatchers) { + DeviceConfigurationCreateDialog dialog = new DeviceConfigurationCreateDialog( + stringMessages, + new DeviceConfigurationCreateDialog.DuplicationValidator(allMatchers), + new DialogCallback() { + @Override + public void ok(DeviceConfigurationMatcherDTO createdMatcher) { + sailingService.addDeviceConfiguration(createdMatcher.type, createdMatcher.clients, + null, null, null, null, new AsyncCallback() { + @Override + public void onSuccess(DeviceConfigurationMatcherDTO matcher) { + listComposite.refreshTable(); + onSelectionChange(Arrays.asList(matcher)); + } + + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError(caught.getMessage()); + } + }); + } + + @Override + public void cancel() { } + }); + dialog.show(); + } + + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError(caught.getMessage()); + } + }); + } + + private void removeConfiguration() { + detailComposite.setConfiguration(null); + detailComposite.setVisible(false); + for (DeviceConfigurationMatcherDTO identifier : selectionProvider.getSelectedItems()) { + sailingService.removeDeviceConfiguration(identifier.type, identifier.clients, new AsyncCallback() { + @Override + public void onSuccess(Boolean result) { + listComposite.refreshTable(); + } + + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError(caught.getMessage()); + } + }); + } + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index 6a2d7dc78af..0e7a4fd382a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -36,6 +36,9 @@ import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO; import com.sap.sailing.gwt.ui.shared.ControlPointDTO; import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO.Type; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.GPSFixDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; @@ -328,4 +331,12 @@ public interface SailingService extends RemoteService { void reloadRaceLog(String selectedLeaderboardName, RaceColumnDTO raceColumnDTO, FleetDTO fleet); MasterDataImportObjectCreationCount importMasterData(String host, String[] groupNames, boolean override); + + List getDeviceConfigurationMatchers(); + + DeviceConfigurationDTO getDeviceConfiguration(DeviceConfigurationMatcherDTO matcher); + + DeviceConfigurationMatcherDTO addDeviceConfiguration(Type type, List clientIds, List allowedCourseAreaNames, Integer minRounds, Integer maxRounds, String mailRecipient); + + boolean removeDeviceConfiguration(Type type, List clientIds); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index d58579a2bb2..61d77f6290e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -36,6 +36,9 @@ import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO; import com.sap.sailing.gwt.ui.shared.ControlPointDTO; import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO.Type; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.GPSFixDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; @@ -450,6 +453,14 @@ public interface SailingServiceAsync { void importMasterData(String host, String[] names, boolean override, AsyncCallback asyncCallback); + + void getDeviceConfigurationMatchers(AsyncCallback> asyncCallback); + + void getDeviceConfiguration(DeviceConfigurationMatcherDTO matcher, AsyncCallback callback); + + void addDeviceConfiguration(Type type, List clientIds, List allowedCourseAreaNames, Integer minRounds, Integer maxRounds, String mailRecipient, AsyncCallback callback); + + void removeDeviceConfiguration(Type type, List clientIds, AsyncCallback asyncCallback); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionChangeListener.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionChangeListener.java new file mode 100644 index 00000000000..4ad12c87def --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionChangeListener.java @@ -0,0 +1,19 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.List; + +/** + * Allows UI components to observe a selector, such as a drop-down box showing a list of items. + * + * + */ +public interface SelectionChangeListener { + + /** + * The first element is the first one selected + * + * @param selectedItems a non-null list which is empty if nothing is selected + */ + void onSelectionChange(List selectedItems); + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionProvider.java new file mode 100644 index 00000000000..baaefdcebcb --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionProvider.java @@ -0,0 +1,25 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.List; + +public interface SelectionProvider { + /** + * @return a non-null list which may be empty + */ + List getSelectedItems(); + + void addSelectionChangeListener(SelectionChangeListener listener); + + void removeSelectionChangeListener(SelectionChangeListener listener); + + void setSelection(List newSelection, SelectionChangeListener... listenersNotToNotify); + + boolean hasMultiSelection(); + + /** + * @return a non-null list which may be empty + */ + List getAllItems(); + + void setAllItems(List newAllItems, SelectionChangeListener... listenersNotToNotify); +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionProviderImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionProviderImpl.java new file mode 100644 index 00000000000..7a6b26b23ff --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SelectionProviderImpl.java @@ -0,0 +1,92 @@ +package com.sap.sailing.gwt.ui.client; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +public class SelectionProviderImpl implements SelectionProvider { + private final List selection; + + private final List allItems; + + private final Set> listeners; + + private final boolean hasMultiSelection; + + public SelectionProviderImpl(boolean hasMultiSelection) { + this.hasMultiSelection = hasMultiSelection; + this.selection = new ArrayList(); + this.allItems = new ArrayList(); + listeners = new HashSet>(); + } + + @Override + public List getSelectedItems() { + return Collections.unmodifiableList(selection); + } + + @Override + public void addSelectionChangeListener(SelectionChangeListener listener) { + listeners.add(listener); + } + + @Override + public void removeSelectionChangeListener(SelectionChangeListener listener) { + listeners.remove(listener); + } + + @Override + public void setSelection(List newSelection, SelectionChangeListener... listenersNotToNotify) { + boolean notify = !selection.equals(newSelection); + selection.clear(); + selection.addAll(newSelection); + if (notify) { + notifyListeners(listenersNotToNotify); + } + } + + private void notifyListeners(SelectionChangeListener[] listenersNotToNotify) { + List selectedRegattas = getSelectedItems(); + for (SelectionChangeListener listener : listeners) { + if (listenersNotToNotify == null || !Arrays.asList(listenersNotToNotify).contains(listener)) { + listener.onSelectionChange(selectedRegattas); + } + } + } + + /** + * Sets the universe of all items from which this selection model may select. An equal list will subsequently be + * returned by {@link #getAllItems()}. Items from the {@link #getSelectedItems() selection} not in + * newAllItems are removed from the selection. If this happens, the selection listeners are notified. + */ + @Override + public void setAllItems(List newAllItems, SelectionChangeListener... listenersNotToNotify) { + allItems.clear(); + for (T r : newAllItems) { + allItems.add(r); + } + for (Iterator i = selection.iterator(); i.hasNext(); ) { + T selectedRegatta = i.next(); + if (!allItems.contains(selectedRegatta)) { + i.remove(); + } + } + // when setting all items, the underlying items will usually have changed their identity and maybe also their state; + // so notifying the selection listeners is necessary anyhow + notifyListeners(listenersNotToNotify); + } + + @Override + public List getAllItems() { + return Collections.unmodifiableList(allItems); + } + + @Override + public boolean hasMultiSelection() { + return hasMultiSelection; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index cca7fe5ce2a..f79cc4475a9 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -66,6 +66,12 @@ import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Series; import com.sap.sailing.domain.base.Sideline; import com.sap.sailing.domain.base.Waypoint; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationImpl; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherAny; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherMulti; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle; import com.sap.sailing.domain.base.impl.FleetImpl; import com.sap.sailing.domain.base.impl.KnotSpeedImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; @@ -197,6 +203,9 @@ import com.sap.sailing.gwt.ui.shared.CompetitorsRaceDataDTO; import com.sap.sailing.gwt.ui.shared.ControlPointDTO; import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.CoursePositionsDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO; +import com.sap.sailing.gwt.ui.shared.DeviceConfigurationMatcherDTO.Type; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.GPSFixDTO; import com.sap.sailing.gwt.ui.shared.GateDTO; @@ -3327,4 +3336,93 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } } + @Override + public List getDeviceConfigurationMatchers() { + List configs = new ArrayList(); + for (Entry entry : + getService().getAllDeviceConfigurations().entrySet()) { + DeviceConfigurationMatcher matcher = entry.getKey(); + configs.add(convertToDeviceConfigurationMatcherDTO(matcher)); + } + return configs; + } + + @Override + public DeviceConfigurationDTO getDeviceConfiguration(DeviceConfigurationMatcherDTO matcherDto) { + DeviceConfigurationMatcher matcher = convertToDeviceConfigurationMatcher(matcherDto.type, matcherDto.clients); + DeviceConfiguration configuration = getService().getAllDeviceConfigurations().get(matcher); + if (configuration == null) { + return null; + } else { + return convertToDeviceConfigurationDTO(configuration); + } + } + + @Override + public DeviceConfigurationMatcherDTO addDeviceConfiguration(Type type, List clientIds, List allowedCourseAreaNames, Integer minRounds, Integer maxRounds, String mailRecipient) { + DeviceConfigurationMatcher matcher = convertToDeviceConfigurationMatcher(type, clientIds); + DeviceConfigurationImpl configuration = new DeviceConfigurationImpl(); + configuration.setAllowedCourseAreaNames(allowedCourseAreaNames); + configuration.setMinimumRoundsForCourse(minRounds); + configuration.setMaximumRoundsForCourse(maxRounds); + configuration.setResultsMailRecipient(mailRecipient); + getService().addDeviceConfiguration(matcher, configuration); + return convertToDeviceConfigurationMatcherDTO(matcher); + } + + @Override + public boolean removeDeviceConfiguration(Type type, List clientIds) { + DeviceConfigurationMatcher matcher = convertToDeviceConfigurationMatcher(type, clientIds); + getService().removeDeviceConfiguration(matcher); + return true; + } + + private DeviceConfigurationMatcherDTO convertToDeviceConfigurationMatcherDTO(DeviceConfigurationMatcher matcher) { + List clients = new ArrayList(); + DeviceConfigurationMatcherDTO.Type type = Type.UNKNOWN; + + if (matcher instanceof DeviceConfigurationMatcherSingle) { + type = Type.SINGLE; + clients.add(((DeviceConfigurationMatcherSingle)matcher).getClientIdentifier()); + } else if (matcher instanceof DeviceConfigurationMatcherMulti) { + type = Type.MULTI; + clients.addAll(((DeviceConfigurationMatcherMulti)matcher).getClientIdentifiers()); + } else if (matcher instanceof DeviceConfigurationMatcherAny) { + type = Type.ANY; + } + + DeviceConfigurationMatcherDTO dto = new DeviceConfigurationMatcherDTO( + type, + clients, + matcher.getMatchingRank()); + return dto; + } + + private DeviceConfigurationMatcher convertToDeviceConfigurationMatcher(Type type, List clientIds) { + DeviceConfigurationMatcher matcher = null; + switch (type) { + case SINGLE: + matcher = new DeviceConfigurationMatcherSingle(clientIds.get(0)); + break; + case MULTI: + matcher = new DeviceConfigurationMatcherMulti(clientIds); + break; + case ANY: + matcher = DeviceConfigurationMatcherAny.INSTANCE; + break; + default: + break; + } + return matcher; + } + + private DeviceConfigurationDTO convertToDeviceConfigurationDTO(DeviceConfiguration configuration) { + DeviceConfigurationDTO dto = new DeviceConfigurationDTO(); + dto.allowedCourseAreaNames = configuration.getAllowedCourseAreaNames(); + dto.minRoundsForCourse = configuration.getMinimumRoundsForCourse(); + dto.maxRoundsForCourse = configuration.getMaximumRoundsForCourse(); + dto.resultsMailRecipient = configuration.getResultsMailRecipient(); + return dto; + } + } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceConfigurationDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceConfigurationDTO.java new file mode 100644 index 00000000000..6193c0e27b6 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceConfigurationDTO.java @@ -0,0 +1,14 @@ +package com.sap.sailing.gwt.ui.shared; + +import java.util.List; + +import com.google.gwt.user.client.rpc.IsSerializable; + +public class DeviceConfigurationDTO implements IsSerializable { + + public List allowedCourseAreaNames; + public Integer minRoundsForCourse; + public Integer maxRoundsForCourse; + public String resultsMailRecipient; + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceConfigurationMatcherDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceConfigurationMatcherDTO.java new file mode 100644 index 00000000000..a8ed47c2e0b --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/DeviceConfigurationMatcherDTO.java @@ -0,0 +1,30 @@ +package com.sap.sailing.gwt.ui.shared; + +import java.util.List; + +import com.google.gwt.user.client.rpc.IsSerializable; + +public class DeviceConfigurationMatcherDTO implements IsSerializable { + + public enum Type { + UNKNOWN, + SINGLE, + MULTI, + ANY + } + + public List clients; + public Type type; + public int rank; + + public DeviceConfigurationMatcherDTO() { + + } + + public DeviceConfigurationMatcherDTO(Type type, List clients, int rank) { + this.clients = clients; + this.type = type; + this.rank = rank; + } + +} diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/DeviceConfigurationJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/DeviceConfigurationJsonDeserializer.java index 8fa26d106e2..1f21e1957af 100644 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/DeviceConfigurationJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/DeviceConfigurationJsonDeserializer.java @@ -6,8 +6,8 @@ import java.util.List; import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.impl.DeviceConfigurationImpl; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationImpl; import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException; import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; import com.sap.sailing.server.gateway.serialization.impl.DeviceConfigurationJsonSerializer; diff --git a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/DeviceConfigurationJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/DeviceConfigurationJsonSerializer.java index 242bfd1a2ad..f978564be06 100644 --- a/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/DeviceConfigurationJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/serialization/impl/DeviceConfigurationJsonSerializer.java @@ -3,7 +3,7 @@ package com.sap.sailing.server.gateway.serialization.impl; import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import com.sap.sailing.domain.base.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; import com.sap.sailing.server.gateway.serialization.JsonSerializer; public class DeviceConfigurationJsonSerializer implements JsonSerializer { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/ConfigurationJsonGetServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/ConfigurationJsonGetServlet.java index 4c40c6f348e..3a07b84e60e 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/ConfigurationJsonGetServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/ConfigurationJsonGetServlet.java @@ -9,9 +9,9 @@ import javax.servlet.http.HttpServletResponse; import org.json.simple.JSONObject; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; -import com.sap.sailing.domain.base.impl.DeviceConfigurationIdentifierImpl; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationIdentifierImpl; import com.sap.sailing.server.gateway.AbstractJsonHttpServlet; import com.sap.sailing.server.gateway.serialization.JsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.DeviceConfigurationJsonSerializer; @@ -37,10 +37,13 @@ public class ConfigurationJsonGetServlet extends AbstractJsonHttpServlet { logger.fine(String.format("Configuration requested by client %s.", identifier)); DeviceConfiguration configuration = getService().getDeviceConfiguration(identifier); - - JsonSerializer serializer = new DeviceConfigurationJsonSerializer(); - JSONObject json = serializer.serialize(configuration); - json.writeJSONString(response.getWriter()); + if (configuration != null) { + JsonSerializer serializer = new DeviceConfigurationJsonSerializer(); + JSONObject json = serializer.serialize(configuration); + json.writeJSONString(response.getWriter()); + } else { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "No configuration for given identifier."); + } } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java index 134bfe4d296..f29c4c030e1 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/RacingEventService.java @@ -26,8 +26,9 @@ import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.RegattaRegistry; import com.sap.sailing.domain.base.Series; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; import com.sap.sailing.domain.common.RaceFetcher; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaFetcher; @@ -555,10 +556,29 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch void setPersistentRegattaForRaceIDs(Regatta regatta, Iterable raceIdStrings, boolean override); /** - * Returns a tablet's configuration. + * Returns a mobile device's configuration. * @param identifier of the client (may include event) * @return the {@link DeviceConfiguration} */ DeviceConfiguration getDeviceConfiguration(DeviceConfigurationIdentifier identifier); + + /** + * Adds a device configuration. + * @param matcher defining for which the configuration applies. + * @param configuration of the device. + */ + void addDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration); + + /** + * Removes a configuration by its matching object. + * @param matcher + */ + void removeDeviceConfiguration(DeviceConfigurationMatcher matcher); + + /** + * Returns all configurations and their matching objects. + * @return the {@link DeviceConfiguration}s. + */ + Map getAllDeviceConfigurations(); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 1ab708b0c8f..d5c01c60841 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -34,8 +34,6 @@ import java.util.logging.Logger; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.ControlPoint; import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Mark; @@ -47,7 +45,14 @@ import com.sap.sailing.domain.base.RegattaListener; import com.sap.sailing.domain.base.Series; import com.sap.sailing.domain.base.Sideline; import com.sap.sailing.domain.base.Waypoint; -import com.sap.sailing.domain.base.impl.DeviceConfigurationImpl; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationMatcher; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationImpl; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMapImpl; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherAny; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherMulti; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationMatcherSingle; import com.sap.sailing.domain.base.impl.EventImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.common.LeaderboardNameConstants; @@ -191,7 +196,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen /** * Leaderboards managed by this racing event service - */ + */ private final ConcurrentHashMap leaderboardsByName; private final ConcurrentHashMap leaderboardGroupsByName; @@ -229,6 +234,8 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen private final MediaDB mediaDB; private final MediaLibrary mediaLibrary; + + protected final DeviceConfigurationMapImpl configurationMap; public RacingEventServiceImpl() { this(MongoFactory.INSTANCE.getDefaultDomainObjectFactory(), MongoFactory.INSTANCE @@ -272,6 +279,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen this.raceLogScoringReplicator = new RaceLogScoringReplicator(this); this.mediaDB = mediaDb; this.mediaLibrary = new MediaLibrary(); + this.configurationMap = new DeviceConfigurationMapImpl(); // Add one default leaderboard that aggregates all races currently tracked by this service. // This is more for debugging purposes than for anything else. @@ -282,6 +290,7 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen loadRaceIDToRegattaAssociations(); loadStoredLeaderboardsAndGroups(); loadMediaLibary(); + loadStoredDeviceConfigurations(); } public RacingEventServiceImpl(MongoDBService mongoDBService) { @@ -347,6 +356,30 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen mediaTrackAdded(mediaTrack); } } + + private void loadStoredDeviceConfigurations() { + DeviceConfigurationMatcher anyMatcher = DeviceConfigurationMatcherAny.INSTANCE; + DeviceConfigurationImpl configuration1 = new DeviceConfigurationImpl(); + configuration1.setAllowedCourseAreaNames(Arrays.asList("Alpha", "Beta", "Stadium")); + configuration1.setMaximumRoundsForCourse(3); + configuration1.setResultsMailRecipient("lukas.niemeier@sap.com"); + + DeviceConfigurationMatcher multiIdentifier = new DeviceConfigurationMatcherMulti(Arrays.asList("2", "3")); + DeviceConfigurationImpl configuration2 = new DeviceConfigurationImpl(); + configuration2.setAllowedCourseAreaNames(Arrays.asList("GAMMA")); + configuration2.setMaximumRoundsForCourse(3); + + DeviceConfigurationMatcher identifier = new DeviceConfigurationMatcherSingle("3"); + DeviceConfigurationImpl configuration3 = new DeviceConfigurationImpl(); + configuration3.setAllowedCourseAreaNames(Arrays.asList("Timo")); + configuration3.setMaximumRoundsForCourse(1); + + synchronized (configurationMap) { + configurationMap.put(anyMatcher, configuration1); + configurationMap.put(identifier, configuration3); + configurationMap.put(multiIdentifier, configuration2); + } + } @Override public void addLeaderboard(Leaderboard leaderboard) { @@ -1769,7 +1802,14 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen for (MediaTrack lg : mediaLibrary.allTracks()) { logoutput.append(String.format("%3s\n", lg.toString())); } - + + logger.info("Serializing configuration map..."); + oos.writeObject(configurationMap); + logoutput.append("Serialized " + configurationMap.size() + " configuration entries\n"); + for (DeviceConfigurationMatcher matcher : configurationMap.keySet()) { + logoutput.append(String.format("%3s\n", matcher.toString())); + } + logger.info(logoutput.toString()); } @@ -1851,6 +1891,12 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen for (MediaTrack mediatrack : mediaLibrary.allTracks()) { logoutput.append(String.format("%3s\n", mediatrack.toString())); } + + configurationMap.putAll((DeviceConfigurationMapImpl) ois.readObject()); + logoutput.append("Received " + configurationMap.size() + " NEW configuration entries\n"); + for (DeviceConfigurationMatcher matcher : configurationMap.keySet()) { + logoutput.append(String.format("%3s\n", matcher.toString())); + } logger.info(logoutput.toString()); logger.info("Done with initial replication on " + this); @@ -2098,11 +2144,26 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen @Override public DeviceConfiguration getDeviceConfiguration(DeviceConfigurationIdentifier identifier) { - DeviceConfigurationImpl configuration = new DeviceConfigurationImpl(); - configuration.setAllowedCourseAreaNames(Arrays.asList("Alpha", "Beta", "Stadium")); - configuration.setMaximumRoundsForCourse(3); - configuration.setResultsMailRecipient("lukas.niemeier@sap.com"); - return configuration; + return configurationMap.getByMatch(identifier); + } + + @Override + public void addDeviceConfiguration(DeviceConfigurationMatcher matcher, DeviceConfiguration configuration) { + synchronized (configurationMap) { + configurationMap.put(matcher, configuration); + } + } + + @Override + public void removeDeviceConfiguration(DeviceConfigurationMatcher matcher) { + synchronized (configurationMap) { + configurationMap.remove(matcher); + } + } + + @Override + public Map getAllDeviceConfigurations() { + return new HashMap(configurationMap); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java index 09efb191d0a..4eb22f77f07 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/DataStore.java @@ -7,7 +7,7 @@ import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.Mark; -import com.sap.sailing.domain.base.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; import com.sap.sailing.racecommittee.app.domain.ManagedRace; public interface DataStore { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java index 17a4ba841f3..4b301afe3d6 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/InMemoryDataStore.java @@ -8,7 +8,7 @@ import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.Mark; -import com.sap.sailing.domain.base.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; import com.sap.sailing.racecommittee.app.domain.ManagedRace; import com.sap.sailing.racecommittee.app.utils.CollectionUtils; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java index 4798e682b79..1eec293471d 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OfflineDataManager.java @@ -15,10 +15,10 @@ import android.content.Context; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.Mark; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; import com.sap.sailing.domain.base.impl.BoatClassImpl; import com.sap.sailing.domain.base.impl.CompetitorImpl; import com.sap.sailing.domain.base.impl.CourseAreaImpl; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java index 3ef500967fd..105d964bef5 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/OnlineDataManager.java @@ -15,11 +15,11 @@ import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.Mark; import com.sap.sailing.domain.base.SharedDomainFactory; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; import com.sap.sailing.racecommittee.app.AppPreferences; import com.sap.sailing.racecommittee.app.data.clients.LoadClient; import com.sap.sailing.racecommittee.app.data.handlers.CompetitorsDataHandler; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java index f26bcbabb8d..b3d08039945 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/ReadonlyDataManager.java @@ -9,10 +9,10 @@ import android.app.LoaderManager.LoaderCallbacks; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.CourseBase; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; import com.sap.sailing.domain.base.EventBase; import com.sap.sailing.domain.base.Mark; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; import com.sap.sailing.racecommittee.app.data.clients.LoadClient; import com.sap.sailing.racecommittee.app.data.loaders.DataLoaderResult; import com.sap.sailing.racecommittee.app.domain.ManagedRace; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/DeviceConfigurationDataHandler.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/DeviceConfigurationDataHandler.java index e51da1085fb..0d189ba0a4f 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/DeviceConfigurationDataHandler.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/handlers/DeviceConfigurationDataHandler.java @@ -1,6 +1,6 @@ package com.sap.sailing.racecommittee.app.data.handlers; -import com.sap.sailing.domain.base.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; import com.sap.sailing.racecommittee.app.data.OnlineDataManager; public class DeviceConfigurationDataHandler extends DataHandler { diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/DeviceConfigurationParser.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/DeviceConfigurationParser.java index 11c42cc0318..d910f50b972 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/DeviceConfigurationParser.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/data/parsers/DeviceConfigurationParser.java @@ -5,7 +5,7 @@ import java.io.Reader; import org.json.simple.JSONObject; import org.json.simple.JSONValue; -import com.sap.sailing.domain.base.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; import com.sap.sailing.server.gateway.deserialization.impl.Helpers; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/LoginActivity.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/LoginActivity.java index e5b2bd39c00..450822814d6 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/LoginActivity.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/activities/LoginActivity.java @@ -11,10 +11,10 @@ import android.view.Window; import android.widget.Toast; import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.DeviceConfiguration; -import com.sap.sailing.domain.base.DeviceConfigurationIdentifier; import com.sap.sailing.domain.base.EventBase; -import com.sap.sailing.domain.base.impl.DeviceConfigurationIdentifierImpl; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfigurationIdentifier; +import com.sap.sailing.domain.base.configuration.impl.DeviceConfigurationIdentifierImpl; import com.sap.sailing.racecommittee.app.AppConstants; import com.sap.sailing.racecommittee.app.AppPreferences; import com.sap.sailing.racecommittee.app.R; diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/DeviceConfigurationHelper.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/DeviceConfigurationHelper.java index d24d4f41f82..127114b67e0 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/DeviceConfigurationHelper.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/utils/DeviceConfigurationHelper.java @@ -2,7 +2,7 @@ package com.sap.sailing.racecommittee.app.utils; import android.content.Context; -import com.sap.sailing.domain.base.DeviceConfiguration; +import com.sap.sailing.domain.base.configuration.DeviceConfiguration; import com.sap.sailing.racecommittee.app.AppPreferences; import com.sap.sailing.racecommittee.app.logging.ExLog;