From fbd665186616b6e0a546e3fb92d3701336677b1d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 11:11:43 +0100 Subject: [PATCH 001/259] bug 2775: Initial changes for reflection-free settings and serialization --- .../test/SettingsJsonSerializationTest.java | 194 ++++++++++------ java/com.sap.sse.common/META-INF/MANIFEST.MF | 3 + .../sse/common/settings/AbstractSetting.java | 14 ++ .../sse/common/settings/AbstractSettings.java | 107 ++++++--- .../common/settings/DecimalListSetting.java | 12 + .../sse/common/settings/DecimalSetting.java | 17 ++ .../common/settings/DoubleListSetting.java | 10 + .../sse/common/settings/DoubleSetting.java | 15 ++ .../sse/common/settings/EnumListSetting.java | 10 + .../sap/sse/common/settings/EnumSetting.java | 52 +---- .../common/settings/HasSettingsFactory.java | 5 + .../sse/common/settings/HasValueSetting.java | 5 + .../sap/sse/common/settings/ListSetting.java | 75 +------ .../sap/sse/common/settings/MapSettings.java | 16 -- .../sse/common/settings/NumberSetting.java | 79 ------- .../com/sap/sse/common/settings/Setting.java | 4 +- .../sap/sse/common/settings/SettingType.java | 0 .../com/sap/sse/common/settings/Settings.java | 2 +- .../sse/common/settings/SettingsFactory.java | 5 + .../sap/sse/common/settings/SettingsList.java | 23 ++ .../common/settings/SettingsListSetting.java | 4 + .../common/settings/StringListSetting.java | 10 + .../sse/common/settings/StringSetting.java | 71 +----- .../settings/StringToEnumConverter.java | 5 + .../sse/common/settings/ValueConverter.java | 13 ++ .../sse/common/settings/ValueListSetting.java | 5 + .../sap/sse/common/settings/ValueSetting.java | 7 + .../base/AbstractHasValueSetting.java | 21 ++ .../settings/base/AbstractListSetting.java | 68 ++++++ .../base/AbstractValueListSetting.java | 71 ++++++ .../settings/base/AbstractValueSetting.java | 71 ++++++ .../settings/converter/DecimalConverter.java | 33 +++ .../settings/converter/DoubleConverter.java | 31 +++ .../settings/converter/EnumConverter.java | 33 +++ .../settings/converter/StringConverter.java | 32 +++ .../AbstractSettingsToJsonSerializer.java | 134 +++++++++++ .../settings/SettingsToJsonSerializer.java | 210 ++---------------- 37 files changed, 913 insertions(+), 554 deletions(-) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java mode change 100755 => 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java mode change 100755 => 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/HasValueSetting.java mode change 100755 => 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java delete mode 100755 java/com.sap.sse.common/src/com/sap/sse/common/settings/MapSettings.java delete mode 100755 java/com.sap.sse.common/src/com/sap/sse/common/settings/NumberSetting.java mode change 100755 => 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java mode change 100755 => 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingType.java mode change 100755 => 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java mode change 100755 => 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/SettingsJsonSerializationTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/SettingsJsonSerializationTest.java index 58b82e1e8c9..82d14b428db 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/SettingsJsonSerializationTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/SettingsJsonSerializationTest.java @@ -3,106 +3,156 @@ package com.sap.sailing.server.gateway.serialization.test; import static org.junit.Assert.assertEquals; import java.math.BigDecimal; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import org.junit.Test; import com.sap.sse.common.filter.TextOperator; import com.sap.sse.common.filter.TextOperator.Operators; +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.DecimalListSetting; +import com.sap.sse.common.settings.DecimalSetting; +import com.sap.sse.common.settings.EnumListSetting; import com.sap.sse.common.settings.EnumSetting; -import com.sap.sse.common.settings.ListSetting; -import com.sap.sse.common.settings.MapSettings; -import com.sap.sse.common.settings.NumberSetting; -import com.sap.sse.common.settings.Setting; -import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.StringSetting; +import com.sap.sse.common.settings.StringToEnumConverter; import com.sap.sse.settings.SettingsToJsonSerializer; public class SettingsJsonSerializationTest { + + private static class TestOuterSettings extends AbstractSettings { + private TestSettings nested = new TestSettings("nested", this); + + } + + private static class TestSettings extends AbstractSettings { + private final StringSetting humba = new StringSetting("humba", this); + // TODO user lambda: TextOperator.Operators::valueOf + private final EnumSetting trala = new EnumSetting<>("trala", this, new StringToEnumConverter() { + @Override + public Operators fromString(String stringValue) { + return TextOperator.Operators.valueOf(stringValue); + } + }); + private final DecimalSetting num = new DecimalSetting("num", this); + private final DecimalListSetting l = new DecimalListSetting("l", this); + + public TestSettings() { + } + public TestSettings(String name, AbstractSettings settings) { + super(name, settings); + } + } + + private static class TestEnumListSettings extends AbstractSettings { + private final EnumListSetting l = new EnumListSetting<>("l", this, new StringToEnumConverter() { + @Override + public Operators fromString(String stringValue) { + return TextOperator.Operators.valueOf(stringValue); + } + }); + } + + private static class DuplicateFieldSettings extends AbstractSettings { + @SuppressWarnings("unused") + private final StringSetting humba = new StringSetting("humba", this); + @SuppressWarnings("unused") + private final DecimalSetting bumba = new DecimalSetting("humba", this); + } + + private final SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); + + private JSONObject serializeAndDeserialize(JSONObject jsonObject) { + String serializedJson = jsonObject.toJSONString(); + try { + return (JSONObject) new JSONParser().parse(serializedJson); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + @Test - public void testFlatJsonSerialization() throws ClassNotFoundException { - final Map settingsMap = new HashMap<>(); - settingsMap.put("humba", new StringSetting("trala")); - settingsMap.put("trala", new EnumSetting<>(TextOperator.Operators.Contains)); - settingsMap.put("num", new NumberSetting(BigDecimal.TEN)); - settingsMap.put("l", new ListSetting(Arrays.asList(new NumberSetting(1), new NumberSetting(2), new NumberSetting(3)))); - Settings settings = new MapSettings(settingsMap); - SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); - JSONObject json = serializer.serialize(settings); - Settings deserializedSettings = serializer.deserialize(json); - assertEquals(settingsMap, deserializedSettings.getNonDefaultSettings()); + public void testFlatJsonSerialization() { + final TestSettings settings = new TestSettings(); + settings.humba.setValue("trala"); + settings.trala.setValue(TextOperator.Operators.Contains); + settings.num.setValue(BigDecimal.TEN); + settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); + + final TestSettings deserializedSettings = serializer.deserialize(new TestSettings(), serializeAndDeserialize(serializer.serialize(settings))); + assertEquals(settings, deserializedSettings); } @Test - public void testNestedJsonSerialization() throws ClassNotFoundException { - final Map settingsMap = new HashMap<>(); - final Map innerMap = new HashMap<>(); - settingsMap.put("humba", new StringSetting("trala")); - innerMap.put("num", new NumberSetting(123.4)); - settingsMap.put("map", new MapSettings(innerMap)); - Settings settings = new MapSettings(settingsMap); - SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); - JSONObject json = serializer.serialize(settings); - Settings deserializedSettings = serializer.deserialize(json); - assertEquals(settingsMap, deserializedSettings.getNonDefaultSettings()); + public void testNestedJsonSerialization() { + final TestOuterSettings outerSettings = new TestOuterSettings(); + final TestSettings settings = outerSettings.nested; + settings.humba.setValue("trala"); + settings.trala.setValue(TextOperator.Operators.Contains); + settings.num.setValue(BigDecimal.TEN); + settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); + + final TestOuterSettings deserializedSettings = serializer.deserialize(new TestOuterSettings(), serializeAndDeserialize(serializer.serialize(outerSettings))); + assertEquals(outerSettings, deserializedSettings); } - + /** - * A white-box test that tests property name escaping in case the property name conflicts with how type - * names (used particularly for enum settings) are represented in JSON. + * Verifies that it is not possible to have two equally named child settings that would cause conflicts on serialization. */ - @Test - public void testJsonSerializationWithFunnyPropertyName() throws ClassNotFoundException { - final Map settingsMap = new HashMap<>(); - settingsMap.put("humba___TYPE", new StringSetting("trala")); - settingsMap.put("trala___TYPE___TYPE", new EnumSetting<>(TextOperator.Operators.Contains)); - Settings settings = new MapSettings(settingsMap); - SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); - JSONObject json = serializer.serialize(settings); - Settings deserializedSettings = serializer.deserialize(json); - assertEquals(settingsMap, deserializedSettings.getNonDefaultSettings()); + @Test(expected = RuntimeException.class) + public void testDuplicateSetting() { + new DuplicateFieldSettings(); } +// /** +// * A white-box test that tests property name escaping in case the property name conflicts with how type +// * names (used particularly for enum settings) are represented in JSON. +// */ +// @Test +// public void testJsonSerializationWithFunnyPropertyName() throws ClassNotFoundException { +// final Map settingsMap = new HashMap<>(); +// settingsMap.put("humba___TYPE", new StringSetting("trala")); +// settingsMap.put("trala___TYPE___TYPE", new EnumSetting<>(TextOperator.Operators.Contains)); +// Settings settings = new MapSettings(settingsMap); +// SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); +// JSONObject json = serializer.serialize(settings); +// Settings deserializedSettings = serializer.deserialize(json); +// assertEquals(settingsMap, deserializedSettings.getNonDefaultSettings()); +// } + /** * A white-box test that tests property name escaping in case the property name conflicts with how type * names (used particularly for enum settings) are represented in JSON. */ @Test public void testJsonSerializationWithEnumTypedList() throws ClassNotFoundException { - final Map settingsMap = new HashMap<>(); - final List> list = new ArrayList<>(); - list.add(new EnumSetting(Operators.Contains)); - list.add(new EnumSetting(Operators.EndsWith)); - settingsMap.put("l", new ListSetting>(list)); - Settings settings = new MapSettings(settingsMap); - SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); - JSONObject json = serializer.serialize(settings); - Settings deserializedSettings = serializer.deserialize(json); - assertEquals(settingsMap, deserializedSettings.getNonDefaultSettings()); + final TestEnumListSettings settings = new TestEnumListSettings(); + settings.l.setValues(Arrays.asList(Operators.Contains, Operators.EndsWith)); + + final TestEnumListSettings deserializedSettings = serializer.deserialize(new TestEnumListSettings(), serializeAndDeserialize(serializer.serialize(settings))); + assertEquals(settings, deserializedSettings); } - /** - * A white-box test that tests property name escaping in case the property name conflicts with how type - * names (used particularly for enum settings) are represented in JSON. - */ - @Test - public void testJsonSerializationWithStringifiedEnum() throws ClassNotFoundException { - final Map settingsMap = new HashMap<>(); - final List list = new ArrayList<>(); - list.add(new StringSetting(Operators.Contains)); - list.add(new StringSetting(Operators.EndsWith)); - settingsMap.put("l", new ListSetting(list)); - Settings settings = new MapSettings(settingsMap); - SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); - JSONObject json = serializer.serialize(settings); - Settings deserializedSettings = serializer.deserialize(json); - ListSetting l = (ListSetting) deserializedSettings.getNonDefaultSettings().get("l"); - assertEquals(Arrays.asList(Operators.Contains, Operators.EndsWith), l.getEnumList(Operators.class)); - } +// /** +// * A white-box test that tests property name escaping in case the property name conflicts with how type +// * names (used particularly for enum settings) are represented in JSON. +// */ +// @Test +// public void testJsonSerializationWithStringifiedEnum() throws ClassNotFoundException { +// final Map settingsMap = new HashMap<>(); +// final List list = new ArrayList<>(); +// list.add(new StringSetting(Operators.Contains)); +// list.add(new StringSetting(Operators.EndsWith)); +// settingsMap.put("l", new ListSetting(list)); +// Settings settings = new MapSettings(settingsMap); +// SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); +// JSONObject json = serializer.serialize(settings); +// Settings deserializedSettings = serializer.deserialize(json); +// ListSetting l = (ListSetting) deserializedSettings.getNonDefaultSettings().get("l"); +// assertEquals(Arrays.asList(Operators.Contains, Operators.EndsWith), l.getEnumList(Operators.class)); +// } } diff --git a/java/com.sap.sse.common/META-INF/MANIFEST.MF b/java/com.sap.sse.common/META-INF/MANIFEST.MF index d8f1e10697a..72652028026 100644 --- a/java/com.sap.sse.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.common/META-INF/MANIFEST.MF @@ -13,6 +13,9 @@ Export-Package: com.sap.sse.common, com.sap.sse.common.scalablevalue, com.sap.sse.common.search, com.sap.sse.common.settings, + com.sap.sse.common.settings.base, + com.sap.sse.common.settings.converter, + com.sap.sse.common.settings.serializer, com.sap.sse.common.util Require-Bundle: org.json.simple;bundle-version="1.1.0", com.sap.sse.datamining.annotations diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java new file mode 100644 index 00000000000..6331ae82298 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java @@ -0,0 +1,14 @@ +package com.sap.sse.common.settings; + + + +public abstract class AbstractSetting implements Setting { + + public AbstractSetting(String name, AbstractSettings settings) { + settings.addSetting(name, this); + } + + public AbstractSetting() { + } + +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java old mode 100755 new mode 100644 index 12a815e7385..59a7bacde6b --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -1,28 +1,79 @@ -package com.sap.sse.common.settings; - -import java.util.Collections; -import java.util.Map; - -public abstract class AbstractSettings implements Settings { - @Override - public SettingType getType() { - return SettingType.MAP; - } - - /** - * This default implementation returns an empty map. - */ - @Override - public Map getNonDefaultSettings() { - return Collections.emptyMap(); - } - - public boolean equals(Object other) { - return getNonDefaultSettings().equals(((Settings) other).getNonDefaultSettings()); - } - - @Override - public String toString() { - return getNonDefaultSettings().toString(); - } -} +package com.sap.sse.common.settings; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractSettings extends AbstractSetting implements Settings { + + private Map childSettings = new HashMap<>(); + + public AbstractSettings() { + } + + public AbstractSettings(String name, AbstractSettings settings) { + super(name, settings); + } + + protected void addSetting(String name, Setting setting) { + if(childSettings.containsKey(name)) { + throw new IllegalArgumentException("setting with name " + name + " already added to setting type " + getClass().getSimpleName()); + } + childSettings.put(name, setting); + } + + @Override + public boolean isDefaultValue() { + for(Setting setting : childSettings.values()) { + if(!setting.isDefaultValue()) { + return false; + } + } + return true; + } + + @Override + public Map getChildSettings() { + return Collections.unmodifiableMap(childSettings); + } + + public String toString() { + StringBuilder sb = new StringBuilder("{(").append(this.getClass().getSimpleName()).append(")"); + boolean first = true; + for(Map.Entry childSetting : childSettings.entrySet()) { + if(!first) { + sb.append("; "); + } + sb.append(childSetting.getKey() + "=" + childSetting.getValue()); + + first = false; + } + sb.append("}"); + return sb.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((childSettings == null) ? 0 : childSettings.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; + AbstractSettings other = (AbstractSettings) obj; + if (childSettings == null) { + if (other.childSettings != null) + return false; + } else if (!childSettings.equals(other.childSettings)) + return false; + return true; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java new file mode 100644 index 00000000000..c7454c7453b --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java @@ -0,0 +1,12 @@ +package com.sap.sse.common.settings; + +import java.math.BigDecimal; + +import com.sap.sse.common.settings.base.AbstractValueListSetting; +import com.sap.sse.common.settings.converter.DecimalConverter; + +public class DecimalListSetting extends AbstractValueListSetting { + public DecimalListSetting(String name, AbstractSettings settings) { + super(name, settings, DecimalConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java new file mode 100644 index 00000000000..0ba4220690e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java @@ -0,0 +1,17 @@ +package com.sap.sse.common.settings; + +import java.math.BigDecimal; + +import com.sap.sse.common.settings.base.AbstractValueSetting; +import com.sap.sse.common.settings.converter.DecimalConverter; + +public class DecimalSetting extends AbstractValueSetting { + + public DecimalSetting(String name, AbstractSettings settings) { + this(name, settings, null); + } + + public DecimalSetting(String name, AbstractSettings settings, BigDecimal defaultValue) { + super(name, settings, defaultValue, DecimalConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java new file mode 100644 index 00000000000..03569717e46 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.settings; + +import com.sap.sse.common.settings.base.AbstractValueListSetting; +import com.sap.sse.common.settings.converter.DoubleConverter; + +public class DoubleListSetting extends AbstractValueListSetting { + public DoubleListSetting(String name, AbstractSettings settings) { + super(name, settings, DoubleConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java new file mode 100644 index 00000000000..b214e5e8808 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java @@ -0,0 +1,15 @@ +package com.sap.sse.common.settings; + +import com.sap.sse.common.settings.base.AbstractValueSetting; +import com.sap.sse.common.settings.converter.DoubleConverter; + +public class DoubleSetting extends AbstractValueSetting { + + public DoubleSetting(String name, AbstractSettings settings) { + this(name, settings, null); + } + + public DoubleSetting(String name, AbstractSettings settings, Double defaultValue) { + super(name, settings, defaultValue, DoubleConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java new file mode 100644 index 00000000000..428a87dc425 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.settings; + +import com.sap.sse.common.settings.base.AbstractValueListSetting; +import com.sap.sse.common.settings.converter.EnumConverter; + +public class EnumListSetting> extends AbstractValueListSetting { + public EnumListSetting(String name, AbstractSettings settings, StringToEnumConverter stringToEnumConverter) { + super(name, settings, new EnumConverter<>(stringToEnumConverter)); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java old mode 100755 new mode 100644 index 2b1a593dfe0..7968c295642 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java @@ -1,49 +1,15 @@ package com.sap.sse.common.settings; -public class EnumSetting> implements Setting { - private final Enum value; +import com.sap.sse.common.settings.base.AbstractValueSetting; +import com.sap.sse.common.settings.converter.EnumConverter; - public EnumSetting(Enum value) { - super(); - this.value = value; +public class EnumSetting> extends AbstractValueSetting { + + public EnumSetting(String name, AbstractSettings settings, StringToEnumConverter stringToEnumConverter) { + this(name, settings, null, stringToEnumConverter); } - - public Enum getValue() { - return value; - } - - @Override - public SettingType getType() { - return SettingType.ENUM; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((value == null) ? 0 : value.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; - EnumSetting other = (EnumSetting) obj; - if (value == null) { - if (other.value != null) - return false; - } else if (!value.equals(other.value)) - return false; - return true; - } - - @Override - public String toString() { - return value.name(); + + public EnumSetting(String name, AbstractSettings settings, T defaultValue, StringToEnumConverter stringToEnumConverter) { + super(name, settings, defaultValue, new EnumConverter<>(stringToEnumConverter)); } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java new file mode 100644 index 00000000000..6d5b7c03639 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java @@ -0,0 +1,5 @@ +package com.sap.sse.common.settings; + +public interface HasSettingsFactory { + SettingsFactory getSettingsFactory(); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasValueSetting.java new file mode 100644 index 00000000000..9400363627b --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasValueSetting.java @@ -0,0 +1,5 @@ +package com.sap.sse.common.settings; + +public interface HasValueSetting extends Setting { + ValueConverter getValueConverter(); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java old mode 100755 new mode 100644 index aedafdc2a62..81de66af233 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java @@ -1,65 +1,10 @@ -package com.sap.sse.common.settings; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public class ListSetting implements Iterable, Setting { - private final Iterable list; - - public ListSetting(Iterable list) { - super(); - this.list = list; - } - - @Override - public Iterator iterator() { - return list.iterator(); - } - - /** - * Precondition: this list holds {@link StringSetting}s. Otherwise, a {@link ClassCastException} will be thrown. - */ - public > List> getEnumList(Class enumClass) { - final List> result = new ArrayList<>(); - for (T t : this) { - result.add(((StringSetting) t).getEnum(enumClass)); - } - return result; - } - - @Override - public SettingType getType() { - return SettingType.LIST; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((list == null) ? 0 : list.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; - ListSetting other = (ListSetting) obj; - if (list == null) { - if (other.list != null) - return false; - } else if (!list.equals(other.list)) - return false; - return true; - } - - @Override - public String toString() { - return list.toString(); - } -} +package com.sap.sse.common.settings; + + +public interface ListSetting extends Setting { + + void setValues(Iterable values); + + Iterable getValues(); + +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/MapSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/MapSettings.java deleted file mode 100755 index 5fab975bac5..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/MapSettings.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.sap.sse.common.settings; - -import java.util.Map; - -public class MapSettings extends AbstractSettings { - private final Map settingsMap; - - public MapSettings(Map settingsMap) { - this.settingsMap = settingsMap; - } - - @Override - public Map getNonDefaultSettings() { - return settingsMap; - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/NumberSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/NumberSetting.java deleted file mode 100755 index e0fa2c42f1e..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/NumberSetting.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.sap.sse.common.settings; - -import java.math.BigDecimal; -import java.math.BigInteger; - -public class NumberSetting implements Setting { - private final BigDecimal number; - - public NumberSetting(BigDecimal number) { - this.number = number; - } - - public NumberSetting(double number) { - this.number = new BigDecimal(number); - } - - public NumberSetting(long number) { - this.number = new BigDecimal(number); - } - - public NumberSetting(int number) { - this.number = new BigDecimal(number); - } - - public NumberSetting(BigInteger number) { - this.number = new BigDecimal(number); - } - - public NumberSetting(Number obj) { - if (obj instanceof BigDecimal) { - this.number = (BigDecimal) obj; - } else if (obj instanceof BigInteger) { - this.number = new BigDecimal((BigInteger) obj); - } else if (obj instanceof Double || obj instanceof Float) { - this.number = new BigDecimal(((Number) obj).doubleValue()); - } else { - this.number = new BigDecimal(obj.longValue()); - } - } - - public BigDecimal getNumber() { - return number; - } - - @Override - public SettingType getType() { - return SettingType.NUMBER; - } - - @Override - public String toString() { - return ""+number; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((number == null) ? 0 : number.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; - NumberSetting other = (NumberSetting) obj; - if (number == null) { - if (other.number != null) - return false; - } else if (!number.equals(other.number)) - return false; - return true; - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java old mode 100755 new mode 100644 index 27aad725a2f..dc90ae57692 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java @@ -1,5 +1,7 @@ package com.sap.sse.common.settings; + + /** * A setting as contained as values in the map returned by {@link AbstractSettings#getSettings()}. This generic * view on a {@link AbstractSettings} object can then be used by one or more serializer / de-serializer combos @@ -10,5 +12,5 @@ package com.sap.sse.common.settings; * */ public interface Setting { - SettingType getType(); + boolean isDefaultValue(); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingType.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingType.java old mode 100755 new mode 100644 diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java old mode 100755 new mode 100644 index 9419ffea7c5..b2e0d7836fe --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java @@ -28,5 +28,5 @@ public interface Settings extends Setting { * Obtains all settings that have non-default values and therefore are required for the later re-construction * of the settings object when passed the resulting map. */ - Map getNonDefaultSettings(); + Map getChildSettings(); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java new file mode 100644 index 00000000000..15fcbd8c53e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java @@ -0,0 +1,5 @@ +package com.sap.sse.common.settings; + +public interface SettingsFactory { + T newInstance(); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java new file mode 100644 index 00000000000..4d07d0f2a79 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java @@ -0,0 +1,23 @@ +package com.sap.sse.common.settings; + +import com.sap.sse.common.settings.base.AbstractListSetting; + + +public class SettingsList extends AbstractListSetting implements SettingsListSetting { + + private SettingsFactory settingsFactory; + + public SettingsList(SettingsFactory settingsFactory) { + this.settingsFactory = settingsFactory; + } + + @Override + public SettingsFactory getSettingsFactory() { + return settingsFactory; + } + + @Override + public String toString() { + return getValues().toString(); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java new file mode 100644 index 00000000000..b94b1880959 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java @@ -0,0 +1,4 @@ +package com.sap.sse.common.settings; + +public interface SettingsListSetting extends ListSetting, HasSettingsFactory { +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java new file mode 100644 index 00000000000..eed33b568e6 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.settings; + +import com.sap.sse.common.settings.base.AbstractValueListSetting; +import com.sap.sse.common.settings.converter.StringConverter; + +public class StringListSetting extends AbstractValueListSetting { + public StringListSetting(String name, AbstractSettings settings) { + super(name, settings, StringConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java old mode 100755 new mode 100644 index 9d5dfc5af93..c020d5e88f5 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java @@ -1,70 +1,15 @@ package com.sap.sse.common.settings; -public class StringSetting implements Setting { - private final String string; +import com.sap.sse.common.settings.base.AbstractValueSetting; +import com.sap.sse.common.settings.converter.StringConverter; - public StringSetting(String string) { - this.string = string; +public class StringSetting extends AbstractValueSetting { + + public StringSetting(String name, AbstractSettings settings) { + this(name, settings, null); } - public StringSetting(Enum literal) { - this.string = literal.name(); - } - - public String getString() { - return string; - } - - public > Enum getEnum(Class enumClass) { - Enum value = null; - if (getString() != null) { - boolean found = false; - for (Enum literal : enumClass.getEnumConstants()) { - if (literal.name().equals(getString())) { - value = literal; - found = true; - break; - } - } - if (!found) { - throw new IllegalArgumentException("Couldn't find literal "+getString()+" in enum "+enumClass.getName()); - } - } - return value; - } - - @Override - public SettingType getType() { - return SettingType.STRING; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((string == null) ? 0 : string.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; - StringSetting other = (StringSetting) obj; - if (string == null) { - if (other.string != null) - return false; - } else if (!string.equals(other.string)) - return false; - return true; - } - - @Override - public String toString() { - return "\""+string+"\""; + public StringSetting(String name, AbstractSettings settings, String defaultValue) { + super(name, settings, defaultValue, StringConverter.INSTANCE); } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java new file mode 100644 index 00000000000..c99dcdbcb15 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java @@ -0,0 +1,5 @@ +package com.sap.sse.common.settings; + +public interface StringToEnumConverter> { + T fromString(String stringValue); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java new file mode 100644 index 00000000000..06abd876db0 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java @@ -0,0 +1,13 @@ +package com.sap.sse.common.settings; + +public interface ValueConverter { + + Object toJSONValue(T value); + + T fromJSONValue(Object jsonValue); + + String toStringValue(T value); + + T fromStringValue(String stringValue); + +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java new file mode 100644 index 00000000000..66c97eb4a34 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java @@ -0,0 +1,5 @@ +package com.sap.sse.common.settings; + + +public interface ValueListSetting extends HasValueSetting, ListSetting { +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetting.java new file mode 100644 index 00000000000..75385c4472b --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetting.java @@ -0,0 +1,7 @@ +package com.sap.sse.common.settings; + +public interface ValueSetting extends HasValueSetting { + T getValue(); + + void setValue(T value); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java new file mode 100644 index 00000000000..3947245fb69 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java @@ -0,0 +1,21 @@ +package com.sap.sse.common.settings.base; + +import com.sap.sse.common.settings.AbstractSetting; +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.HasValueSetting; +import com.sap.sse.common.settings.ValueConverter; + +public abstract class AbstractHasValueSetting extends AbstractSetting implements HasValueSetting { + + private ValueConverter valueConverter; + + public AbstractHasValueSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + super(name, settings); + this.valueConverter = valueConverter; + } + + @Override + public ValueConverter getValueConverter() { + return valueConverter; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java new file mode 100644 index 00000000000..382e5171506 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java @@ -0,0 +1,68 @@ +package com.sap.sse.common.settings.base; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.sap.sse.common.settings.AbstractSetting; +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.ListSetting; + +public abstract class AbstractListSetting extends AbstractSetting implements ListSetting { + + private List values = new ArrayList<>(); + + public AbstractListSetting(String name, AbstractSettings settings) { + super(name, settings); + } + + public AbstractListSetting() { + } + + @Override + public boolean isDefaultValue() { + // TODO implement + return values.isEmpty(); + } + + @Override + public Iterable getValues() { + return Collections.unmodifiableCollection(values); + } + + @Override + public void setValues(Iterable values) { + this.values.clear(); + if(values != null) { + for(T value : values) { + this.values.add(value); + } + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((values == null) ? 0 : values.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; + @SuppressWarnings("rawtypes") + AbstractListSetting other = (AbstractListSetting) obj; + if (values == null) { + if (other.values != null) + return false; + } else if (!values.equals(other.values)) + return false; + return true; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java new file mode 100644 index 00000000000..77b04493f9e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java @@ -0,0 +1,71 @@ +package com.sap.sse.common.settings.base; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.ValueListSetting; + +public abstract class AbstractValueListSetting extends AbstractHasValueSetting implements ValueListSetting { + + private List values = new ArrayList<>(); + + public AbstractValueListSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + super(name, settings, valueConverter); + } + + @Override + public boolean isDefaultValue() { + // explicit default values are possible to implement + // currently, empty is always default + return values.isEmpty(); + } + + @Override + public Iterable getValues() { + return Collections.unmodifiableCollection(values); + } + + @Override + public void setValues(Iterable values) { + this.values.clear(); + if(values != null) { + for(T value : values) { + this.values.add(value); + } + } + } + + @Override + public String toString() { + return values.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((values == null) ? 0 : values.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; + @SuppressWarnings("rawtypes") + AbstractValueListSetting other = (AbstractValueListSetting) obj; + if (values == null) { + if (other.values != null) + return false; + } else if (!values.equals(other.values)) + return false; + return true; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java new file mode 100644 index 00000000000..1f998214be3 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java @@ -0,0 +1,71 @@ +package com.sap.sse.common.settings.base; + +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.ValueSetting; + +public class AbstractValueSetting extends AbstractHasValueSetting implements ValueSetting { + + private T defaultValue; + + private T value; + + protected AbstractValueSetting(String name, AbstractSettings settings, T defaultValue, ValueConverter valueConverter) { + super(name, settings, valueConverter); + this.defaultValue = defaultValue; + this.value = defaultValue; + } + + @Override + public T getValue() { + return value; + } + + @Override + public void setValue(T value) { + this.value = value; + } + + @Override + public boolean isDefaultValue() { + if(value == defaultValue) { + return true; + } + if(value != null) { + return value.equals(defaultValue); + } + // value == null && defaultValue != null => value isn't default + return false; + } + + @Override + public String toString() { + return "" + value; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((value == null) ? 0 : value.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; + @SuppressWarnings("rawtypes") + AbstractValueSetting other = (AbstractValueSetting) obj; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java new file mode 100644 index 00000000000..da905f2e8d4 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java @@ -0,0 +1,33 @@ +package com.sap.sse.common.settings.converter; + +import java.math.BigDecimal; + +import com.sap.sse.common.settings.ValueConverter; + +public class DecimalConverter implements ValueConverter { + + public static final DecimalConverter INSTANCE = new DecimalConverter(); + + private DecimalConverter() { + } + + @Override + public Object toJSONValue(BigDecimal value) { + return toStringValue(value); + } + + @Override + public BigDecimal fromJSONValue(Object jsonValue) { + return fromStringValue((String) jsonValue); + } + + @Override + public String toStringValue(BigDecimal value) { + return value == null ? null : value.toString(); + } + + @Override + public BigDecimal fromStringValue(String stringValue) { + return stringValue == null ? null : new BigDecimal(stringValue); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java new file mode 100644 index 00000000000..a8c0be66ac2 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java @@ -0,0 +1,31 @@ +package com.sap.sse.common.settings.converter; + +import com.sap.sse.common.settings.ValueConverter; + +public class DoubleConverter implements ValueConverter { + + public static final DoubleConverter INSTANCE = new DoubleConverter(); + + private DoubleConverter() { + } + + @Override + public Object toJSONValue(Double value) { + return value; + } + + @Override + public Double fromJSONValue(Object jsonValue) { + return (Double) jsonValue; + } + + @Override + public String toStringValue(Double value) { + return value == null ? null : value.toString(); + } + + @Override + public Double fromStringValue(String stringValue) { + return stringValue == null ? null : Double.valueOf(stringValue); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java new file mode 100644 index 00000000000..672c56c3197 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java @@ -0,0 +1,33 @@ +package com.sap.sse.common.settings.converter; + +import com.sap.sse.common.settings.StringToEnumConverter; +import com.sap.sse.common.settings.ValueConverter; + +public class EnumConverter> implements ValueConverter { + + private StringToEnumConverter stringToEnumConverter; + + public EnumConverter(StringToEnumConverter stringToEnumConverter) { + this.stringToEnumConverter = stringToEnumConverter; + } + + @Override + public Object toJSONValue(T value) { + return value == null ? null : value.name(); + } + + @Override + public T fromJSONValue(Object jsonValue) { + return fromStringValue((String) jsonValue); + } + + @Override + public String toStringValue(T value) { + return value == null ? null : value.name(); + } + + @Override + public T fromStringValue(String stringValue) { + return stringValue == null ? null : stringToEnumConverter.fromString(stringValue); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java new file mode 100644 index 00000000000..3e58eeb9e1d --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java @@ -0,0 +1,32 @@ +package com.sap.sse.common.settings.converter; + +import com.sap.sse.common.settings.ValueConverter; + +public class StringConverter implements ValueConverter { + + public static final StringConverter INSTANCE = new StringConverter(); + + private StringConverter() { + } + + @Override + public Object toJSONValue(String value) { + return value; + } + + @Override + public String fromJSONValue(Object jsonValue) { + return (String) jsonValue; + } + + @Override + public String toStringValue(String value) { + return value; + } + + @Override + public String fromStringValue(String stringValue) { + return stringValue; + } + +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java new file mode 100644 index 00000000000..4f2bd148803 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java @@ -0,0 +1,134 @@ +package com.sap.sse.common.settings.serializer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.sap.sse.common.settings.ListSetting; +import com.sap.sse.common.settings.Setting; +import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.SettingsListSetting; +import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.ValueListSetting; +import com.sap.sse.common.settings.ValueSetting; + +public abstract class AbstractSettingsToJsonSerializer { + + protected abstract OBJECT newOBJECT(); + + protected abstract void set(OBJECT jsonObject, String property, Object value); + + protected abstract Object get(OBJECT jsonObject, String property); + + protected abstract boolean hasProperty(OBJECT jsonObject, String property); + + protected abstract ARRAY ToJsonArray(Iterable values); + + protected abstract Iterable fromJsonArray(ARRAY jsonArray); + + public OBJECT serialize(Settings settings) { + final OBJECT jsonObject = newOBJECT(); + for (Map.Entry entry : settings.getChildSettings().entrySet()) { + Setting setting = entry.getValue(); + if (!setting.isDefaultValue()) { + set(jsonObject, entry.getKey(), serialize(setting)); + } + } + return jsonObject; + } + + private Object serialize(Setting setting) { + if (setting instanceof ValueSetting) { + return serializeValueSetting((ValueSetting) setting); + } else if (setting instanceof ListSetting) { + return serializeListSetting((ListSetting) setting); + } else if (setting instanceof Settings) { + return serialize((Settings) setting); + } else { + throw new IllegalStateException("Unknown Setting type"); + } + } + + private Object serializeValueSetting(ValueSetting valueSetting) { + return valueSetting.getValueConverter().toJSONValue(valueSetting.getValue()); + } + + private Object serializeListSetting(ListSetting listSetting) { + List jsonValues = new ArrayList<>(); + if (listSetting instanceof ValueListSetting) { + ValueListSetting valueListSetting = (ValueListSetting) listSetting; + ValueConverter converter = valueListSetting.getValueConverter(); + for (T value : valueListSetting.getValues()) { + jsonValues.add(converter.toJSONValue(value)); + } + } else if (listSetting instanceof SettingsListSetting) { + SettingsListSetting settingsListSetting = (SettingsListSetting) listSetting; + for (Settings value : settingsListSetting.getValues()) { + jsonValues.add(serialize(value)); + } + } else { + throw new IllegalStateException("Unknown ListSetting type"); + } + return ToJsonArray(jsonValues); + } + + public T deserialize(T settings, OBJECT json) { + if (json != null) { + for (Map.Entry entry : settings.getChildSettings().entrySet()) { + Setting setting = entry.getValue(); + if(hasProperty(json, entry.getKey())) { + Object jsonValue = get(json, entry.getKey()); + deserialize(setting, jsonValue); + } + } + } + return settings; + } + + private void deserialize(Setting setting, Object jsonValue) { + if (setting instanceof ValueSetting) { + deserializeValueSetting(jsonValue, (ValueSetting) setting); + } else if (setting instanceof ListSetting) { + deserializeListSetting(jsonValue, (ListSetting) setting); + } else if (setting instanceof Settings) { + deserializeObject((Settings) setting, jsonValue); + } else { + throw new IllegalStateException("Unknown Setting type"); + } + } + + @SuppressWarnings("unchecked") + private T deserializeObject(T setting, Object jsonValue) { + return deserialize(setting, (OBJECT) jsonValue); + } + + private void deserializeValueSetting(Object jsonValue, ValueSetting valueSetting) { + valueSetting.setValue(valueSetting.getValueConverter().fromJSONValue(jsonValue)); + } + + private void deserializeListSetting(Object jsonValue, ListSetting listSetting) { + @SuppressWarnings("unchecked") + ARRAY jsonArray = (ARRAY) jsonValue; + if (listSetting instanceof ValueListSetting) { + ValueListSetting valueListSetting = (ValueListSetting) listSetting; + ValueConverter converter = valueListSetting.getValueConverter(); + List values = new ArrayList<>(); + for (Object value : fromJsonArray(jsonArray)) { + values.add(converter.fromJSONValue(value)); + } + valueListSetting.setValues(values); + } else if (listSetting instanceof SettingsListSetting) { + deserializeSettingsListSetting(jsonArray, (SettingsListSetting) listSetting); + } else { + throw new IllegalStateException("Unknown ListSetting type"); + } + } + + private void deserializeSettingsListSetting(ARRAY jsonArray, SettingsListSetting settingsListSetting) { + List values = new ArrayList<>(); + for (Object value : fromJsonArray(jsonArray)) { + values.add(deserializeObject(settingsListSetting.getSettingsFactory().newInstance(), value)); + } + settingsListSetting.setValues(values); + } +} diff --git a/java/com.sap.sse/src/com/sap/sse/settings/SettingsToJsonSerializer.java b/java/com.sap.sse/src/com/sap/sse/settings/SettingsToJsonSerializer.java index c5e3adb5344..40e14e2afcc 100755 --- a/java/com.sap.sse/src/com/sap/sse/settings/SettingsToJsonSerializer.java +++ b/java/com.sap.sse/src/com/sap/sse/settings/SettingsToJsonSerializer.java @@ -1,24 +1,12 @@ package com.sap.sse.settings; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.common.settings.EnumSetting; import com.sap.sse.common.settings.ListSetting; -import com.sap.sse.common.settings.MapSettings; -import com.sap.sse.common.settings.NumberSetting; -import com.sap.sse.common.settings.Setting; -import com.sap.sse.common.settings.SettingType; import com.sap.sse.common.settings.Settings; -import com.sap.sse.common.settings.StringSetting; +import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; /** * Serializes a {@link Settings} object to a {@link JSONObject}. All setting types are supported as top-level entities. @@ -35,189 +23,39 @@ import com.sap.sse.common.settings.StringSetting; * @author Axel Uhl (D043530) * */ -public class SettingsToJsonSerializer { - private final static String TYPE_PROPERTY_SUFFIX = "___TYPE"; - private final static char TYPE_PROPERTY_SUFFIX_ESCAPE = ':'; - - public JSONObject serialize(Settings settings) { - final Map settingsToSerialize = settings.getNonDefaultSettings(); - JSONObject jsonObject = new JSONObject(); - for (Entry e : settingsToSerialize.entrySet()) { - Object settingAsJson = serialize(e.getValue()); - jsonObject.put(escapePropertyName(e.getKey()), settingAsJson); - final String typePropertyName = getTypePropertyName(e.getKey()); - if (e.getValue() instanceof EnumSetting) { - jsonObject.put(typePropertyName, getEnumTypeName((EnumSetting) e.getValue())); - } else if (e.getValue() instanceof ListSetting) { - Iterator i = ((ListSetting) e.getValue()).iterator(); - if (i.hasNext()) { - Object o = i.next(); - if (o instanceof EnumSetting) { - jsonObject.put(typePropertyName, getEnumListTypeName(((EnumSetting) o).getValue())); - } - } - } - } - return jsonObject; +public class SettingsToJsonSerializer extends AbstractSettingsToJsonSerializer { + + @Override + protected JSONObject newOBJECT() { + return new JSONObject(); } - /** - * A list containing enum literals shall be represented as simply holding these literals as strings. However, - * when de-serializing, the list elements need to be constructed as the proper enum's literals again, so we need - * to store the enumeration class name together with the information that it's a list. - */ - private Object getEnumListTypeName(Enum literal) { - return SettingType.LIST.name()+"/"+literal.getClass().getName(); + @Override + protected void set(JSONObject jsonObject, String property, Object value) { + jsonObject.put(property, value); } - private Object getEnumTypeName(EnumSetting value) { - return SettingType.ENUM.name()+"/"+value.getValue().getClass().getName(); - } - - private String getTypePropertyName(String unescapedKey) { - return unescapedKey+TYPE_PROPERTY_SUFFIX; - } - - private boolean isTypePropertyName(String unescapedKey) { - return unescapedKey.endsWith(TYPE_PROPERTY_SUFFIX) && !unescapedKey.endsWith(TYPE_PROPERTY_SUFFIX_ESCAPE+TYPE_PROPERTY_SUFFIX); + @Override + protected Object get(JSONObject jsonObject, String property) { + return jsonObject.get(property); } - /** - * If key looks like a result of {@link #getTypePropertyName(String)}, the string is escaped such that - * it does not more and that {@link #unescapePropertyName} will return key.

- */ - String escapePropertyName(String key) { - return key.replaceAll(TYPE_PROPERTY_SUFFIX, TYPE_PROPERTY_SUFFIX_ESCAPE+TYPE_PROPERTY_SUFFIX); + @Override + protected boolean hasProperty(JSONObject jsonObject, String property) { + return jsonObject.containsKey(property); } - String unescapePropertyName(String escapedKey) { - return escapedKey.replaceAll(TYPE_PROPERTY_SUFFIX_ESCAPE+TYPE_PROPERTY_SUFFIX, TYPE_PROPERTY_SUFFIX); - } - - private Object serialize(Setting setting) { - switch (setting.getType()) { - case ENUM: - return serialize((EnumSetting) setting); - case LIST: - return serialize((ListSetting) setting); - case MAP: - return serialize((Settings) setting); - case NUMBER: - return serialize((NumberSetting) setting); - case STRING: - return serialize((StringSetting) setting); - default: - throw new IllegalArgumentException("Don't know setting of type "+setting.getType()); + @Override + protected JSONArray ToJsonArray(Iterable values) { + JSONArray jsonArray = new JSONArray(); + for(Object value : values) { + jsonArray.add(value); } - } - - private > String serialize(EnumSetting enumSetting) { - return enumSetting.getValue().name(); + return jsonArray; } - private JSONArray serialize(ListSetting listSetting) { - JSONArray result = new JSONArray(); - for (T t : listSetting) { - result.add(serialize(t)); - } - return result; - } - - private Number serialize(NumberSetting numberSetting) { - return numberSetting.getNumber(); - } - - private String serialize(StringSetting stringSetting) { - return stringSetting.getString(); - } - - public Settings deserialize(JSONObject json) throws ClassNotFoundException { - final Map settings = new HashMap<>(); - for (Entry e : json.entrySet()) { - String escapedKey = (String) e.getKey(); - String unescapedKey = unescapePropertyName(escapedKey); - if (!isTypePropertyName(escapedKey)) { - final Object value = e.getValue(); - String typePropertyName = getTypePropertyName(unescapedKey); - // all properties must specify their type unless they are of type String, JSONArray or Number; - // however, properties of type enum will be represented as strings - final SettingType type; - final Class clazz; - if (json.containsKey(typePropertyName)) { - String[] typeNameAndClassName = ((String) json.get(typePropertyName)).split("/"); - type = SettingType.valueOf(typeNameAndClassName[0]); - if (typeNameAndClassName.length > 1) { - clazz = Class.forName(typeNameAndClassName[1]); - } else { - clazz = null; - } - } else { - type = getSettingType(value); - clazz = null; - } - Setting setting = createSettingFromObjectAndType(value, type, clazz); - settings.put(unescapePropertyName(escapedKey), setting); - } - } - return new AbstractSettings() { - @Override - public Map getNonDefaultSettings() { - return settings; - } - }; - } - - private SettingType getSettingType(final Object value) { - final SettingType type; - if (value instanceof String) { - type = SettingType.STRING; - } else if (value instanceof Number){ - type = SettingType.NUMBER; - } else if (value instanceof JSONArray) { - type = SettingType.LIST; - } else if (value instanceof JSONObject) { - type = SettingType.MAP; - } else { - throw new IllegalArgumentException("Don't know how to de-serialize setting "+value+" of type "+value.getClass()); - } - return type; - } - - private Setting createSettingFromObjectAndType(Object obj, final SettingType type, Class clazz) - throws ClassNotFoundException { - final Setting setting; - switch (type) { - case ENUM: - Enum value = null; - @SuppressWarnings("unchecked") - Class> enumClass = (Class>) clazz; - for (Enum literal : enumClass.getEnumConstants()) { - if (literal.name().equals((String) obj)) { - value = literal; - } - } - setting = new EnumSetting<>(value); - break; - case LIST: - JSONArray array = (JSONArray) obj; - List settingList = new ArrayList<>(); - for (Object o : array) { - settingList.add(createSettingFromObjectAndType(o, clazz==null?getSettingType(o):SettingType.ENUM, clazz)); - } - setting = new ListSetting<>(settingList); - break; - case MAP: - setting = deserialize((JSONObject) obj); - break; - case NUMBER: - setting = new NumberSetting((Number) obj); - break; - case STRING: - setting = new StringSetting((String) obj); - break; - default: - throw new IllegalArgumentException("Don't know how to de-serialize setting "+obj+" of type "+obj.getClass()); - } - return setting; + @Override + protected Iterable fromJsonArray(JSONArray jsonArray) { + return jsonArray; } } From 619f213517a89b7d3f6112b6efab37d0071bfca9 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 15 Mar 2016 13:37:08 +0100 Subject: [PATCH 002/259] GWT implementation of the serializer --- .../src/com/sap/sse/gwt/Settings.gwt.xml | 6 ++ .../settings/SettingsToJsonSerializerGWT.java | 89 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/Settings.gwt.xml create mode 100755 java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/Settings.gwt.xml b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/Settings.gwt.xml new file mode 100644 index 00000000000..8d65cd9293e --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/Settings.gwt.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java new file mode 100755 index 00000000000..751631a4597 --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java @@ -0,0 +1,89 @@ +package com.sap.sse.gwt.settings; + +import java.util.ArrayList; + +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONBoolean; +import com.google.gwt.json.client.JSONNumber; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONString; +import com.google.gwt.json.client.JSONValue; +import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; + +/** + * This is a GWT implementation of an {@link AbstractSettingsToJsonSerializer} that uses the json api library available + * on the client side. + * + */ +public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerializer { + @Override + protected JSONObject newOBJECT() { + return new JSONObject(); + } + + @Override + protected void set(JSONObject jsonObject, String property, Object value) { + + if (value instanceof String) { + jsonObject.put(property, new JSONString((String) value)); + } else if (value instanceof Number) { + jsonObject.put(property, new JSONNumber(((Number) value).doubleValue())); + } else if (value instanceof Boolean) { + jsonObject.put(property, JSONBoolean.getInstance((Boolean) value)); + } + + } + + @Override + protected Object get(JSONObject jsonObject, String property) { + return jsonObject.get(property); + } + + @Override + protected boolean hasProperty(JSONObject jsonObject, String property) { + return jsonObject.containsKey(property); + } + + @Override + protected JSONArray ToJsonArray(Iterable values) { + JSONArray jsonArray = new JSONArray(); + for (Object value : values) { + JSONValue jsonValue = null; + if (value instanceof String) { + jsonValue = new JSONString((String) value); + } else if (value instanceof Number) { + jsonValue = new JSONNumber(((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + jsonValue = JSONBoolean.getInstance((Boolean) value); + } + if (jsonValue != null) { + jsonArray.set(jsonArray.size(), jsonValue); + } + } + return jsonArray; + } + + @Override + protected Iterable fromJsonArray(JSONArray jsonArray) { + final ArrayList result = new ArrayList(jsonArray.size()); + toLoop: for (int i = 0; i < jsonArray.size(); i++) { + JSONValue jsonValue = jsonArray.get(i); + JSONString jS; + if ((jS = jsonValue.isString()) != null) { + result.add(jS.stringValue()); + continue toLoop; + } + JSONBoolean jB; + if ((jB = jsonValue.isBoolean()) != null) { + result.add(jB.booleanValue()); + continue toLoop; + } + JSONNumber jN; + if ((jN = jsonValue.isNumber()) != null) { + result.add(jN.doubleValue()); + continue toLoop; + } + } + return result; + } +} From 477f81fefbae3b688e1e57078ebbe347f33c6f75 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 14:01:23 +0100 Subject: [PATCH 003/259] bug 2775: Initial implementation regarding URL serialization of Settings --- .../SettingsToStringMapSerializer.java | 196 ++++++++++++++++++ .../gwt/settings/SettingsToUrlSerializer.java | 35 ++++ 2 files changed, 231 insertions(+) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java new file mode 100644 index 00000000000..4a55a045826 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java @@ -0,0 +1,196 @@ +package com.sap.sse.common.settings.serializer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import com.sap.sse.common.settings.HasValueSetting; +import com.sap.sse.common.settings.Setting; +import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.SettingsListSetting; +import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.ValueListSetting; +import com.sap.sse.common.settings.ValueSetting; + +public class SettingsToStringMapSerializer { + private static final String PATH_SEPARATOR = "."; + + public Map> serialize(Settings settings) { + final Map> result = new HashMap<>(); + serialize("", settings, result); + return result; + } + + private void serialize(String prefix, Settings settings, Map> serialized) { + for (Map.Entry entry : settings.getChildSettings().entrySet()) { + final Setting setting = entry.getValue(); + if (!setting.isDefaultValue()) { + String key = prefix + entry.getKey(); + serialize(key, setting, serialized); + } + } + } + + private void serialize(String key, Setting setting, Map> serialized) { + if (setting instanceof ValueSetting) { + serialized.put(key, serializeValueSetting(key, (ValueSetting) setting)); + } else if (setting instanceof ValueListSetting) { + serialized.put(key, serializeValueListSetting(key, (ValueListSetting) setting)); + } else { + String prefix = key + PATH_SEPARATOR; + if (setting instanceof Settings) { + serialize(prefix, (Settings) setting, serialized); + } else if (setting instanceof SettingsListSetting) { + serializeSettingsListSetting(prefix, (SettingsListSetting) setting, serialized); + } else { + throw new IllegalStateException("Unknown Setting type"); + } + } + } + + private void serializeSettingsListSetting(String prefix, SettingsListSetting setting, + Map> serialized) { + int index = 0; + for (T childSettings : setting.getValues()) { + String nestedPrefix = prefix + index + PATH_SEPARATOR; + serialize(nestedPrefix, childSettings, serialized); + index++; + } + } + + private Iterable serializeValueSetting(String key, ValueSetting valueSetting) { + return Collections.singleton(valueSetting.getValueConverter().toStringValue(valueSetting.getValue())); + } + + private Iterable serializeValueListSetting(String key, ValueListSetting valueSetting) { + List result = new ArrayList<>(); + ValueConverter valueConverter = valueSetting.getValueConverter(); + for (T value : valueSetting.getValues()) { + result.add(valueConverter.toStringValue(value)); + } + return result; + } + + public T deserialize(T settings, Map> values) { + Map>> mappedInnerValues = mapNested(values); + for (Map.Entry entry : settings.getChildSettings().entrySet()) { + final String key = entry.getKey(); + final Setting setting = entry.getValue(); + deserialize(key, setting, values, mappedInnerValues); + } + return settings; + } + + private void deserialize(String key, Setting setting, Map> values, + Map>> mappedInnerValues) { + if (setting instanceof HasValueSetting) { + final Iterable settingValues = values.get(key); + if (settingValues != null) { + if (setting instanceof ValueSetting) { + deserializeValueSetting((ValueSetting) setting, settingValues); + } else if (setting instanceof ValueListSetting) { + deserializeValueListSetting((ValueListSetting) setting, settingValues); + } else { + throw new IllegalStateException("Unknown HasValueSetting type"); + } + } + } else { + final Map> innerValues = mappedInnerValues.get(key); + if (innerValues != null) { + if (setting instanceof Settings) { + deserialize((Settings) setting, innerValues); + } else if (setting instanceof SettingsListSetting) { + deserializeSettingsListSetting((SettingsListSetting) setting, innerValues); + } else { + throw new IllegalStateException("Unknown Setting type"); + } + } + } + } + + private void deserializeValueSetting(ValueSetting valueSetting, Iterable values) { + Iterator iterator = values.iterator(); + if (iterator.hasNext()) { + // Additional values are currently silently skipped. + // This should only happen if somebody manipulates the data or a List setting is changed to a single setting + // value. + valueSetting.setValue(valueSetting.getValueConverter().fromStringValue(iterator.next())); + } + } + + private void deserializeValueListSetting(ValueListSetting valueSetting, Iterable values) { + List deserializedValues = new ArrayList<>(); + for (String stringValue : values) { + deserializedValues.add(valueSetting.getValueConverter().fromStringValue(stringValue)); + } + valueSetting.setValues(deserializedValues); + } + + private void deserializeSettingsListSetting(SettingsListSetting valueSetting, + Map> values) { + Map>> mappedNestedListValues = mapNestedWithIndexOrder(values); + List deserializedValues = new ArrayList<>(); + for (Map.Entry>> entry : mappedNestedListValues.entrySet()) { + deserializedValues.add(deserialize(valueSetting.getSettingsFactory().newInstance(), entry.getValue())); + } + valueSetting.setValues(deserializedValues); + } + + private Map>> mapNestedWithIndexOrder(Map> values) { + Map>> result = new TreeMap<>(new IndexComparator()); + result.putAll(mapNested(values)); + return result; + } + + private Map>> mapNested(Map> values) { + Map>> result = new HashMap<>(); + for (Map.Entry> entry : values.entrySet()) { + String key = entry.getKey(); + int separatorIndex = key.indexOf(PATH_SEPARATOR); + if (separatorIndex > 0) { + String group = key.substring(0, separatorIndex); + String nestedKey = key.substring(separatorIndex + 1); + + Map> inner = result.get(group); + if (inner == null) { + inner = new HashMap<>(); + result.put(group, inner); + } + inner.put(nestedKey, entry.getValue()); + } + } + return result; + } + + private static class IndexComparator implements Comparator { + @Override + public int compare(String o1, String o2) { + boolean o1error = false; + boolean o2error = false; + int o1int = 0; + int o2int = 0; + try { + o1int = Integer.parseInt(o1); + } catch (NumberFormatException e) { + o1error = true; + } + try { + o2int = Integer.parseInt(o1); + } catch (NumberFormatException e) { + o1error = true; + } + if (o1error && o2error) { + return o1.compareTo(o2); + } + if (!o1error && !o2error) { + return Integer.compare(o1int, o2int); + } + return o1error ? 1 : -1; + } + } +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java new file mode 100644 index 00000000000..51f18be888b --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java @@ -0,0 +1,35 @@ +package com.sap.sse.gwt.settings; + +import java.util.Map; + +import com.google.gwt.http.client.UrlBuilder; +import com.google.gwt.user.client.Window; +import com.sap.sse.common.Util; +import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer; + +public class SettingsToUrlSerializer { + + private final SettingsToStringMapSerializer settingsToStringMapSerializer = new SettingsToStringMapSerializer(); + + public void serializeBasedOnCurrentLocation(Settings settings) { + final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); + serializeToUrlBuilder(settings, urlBuilder); + } + + public void serializeToUrlBuilder(Settings settings, UrlBuilder urlBuilder) { + Map> serializedValues = settingsToStringMapSerializer.serialize(settings); + for(Map.Entry> entry : serializedValues.entrySet()) { + Iterable parameterValues = entry.getValue(); + String[] parameterValuesAsArray = Util.toArray(parameterValues, new String[Util.size(parameterValues)]); + urlBuilder.setParameter(entry.getKey(), parameterValuesAsArray); + } + } + + public void deserializeFromCurrentLocation(Settings settings) { + @SuppressWarnings({ "rawtypes", "unchecked" }) + Map> values = (Map) Window.Location.getParameterMap(); + settingsToStringMapSerializer.deserialize(settings, values); + } + +} From 50b61179650bee4dafd48b8c018c1a655da78a52 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 14:58:41 +0100 Subject: [PATCH 004/259] Removed org.json.simple as dependency of com.sap.sse.common because it doesn't seem to be used there. org.json.simple isn't compatible with GWT and all code that is in this bundle is shared between Backend/Android/GWT --- java/com.sap.sse.common/META-INF/MANIFEST.MF | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/com.sap.sse.common/META-INF/MANIFEST.MF b/java/com.sap.sse.common/META-INF/MANIFEST.MF index 72652028026..5265a8e68f2 100644 --- a/java/com.sap.sse.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.common/META-INF/MANIFEST.MF @@ -17,6 +17,5 @@ Export-Package: com.sap.sse.common, com.sap.sse.common.settings.converter, com.sap.sse.common.settings.serializer, com.sap.sse.common.util -Require-Bundle: org.json.simple;bundle-version="1.1.0", - com.sap.sse.datamining.annotations +Require-Bundle: com.sap.sse.datamining.annotations Bundle-ActivationPolicy: lazy From 142505760d340cd653d870ca87a9679d74ff56ce Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:00:38 +0100 Subject: [PATCH 005/259] bug 2775: Added org.json.simple dependency to com.sap.sse.shared.android to make an implementation of the JSON serializer possible here --- java/com.sap.sse.shared.android/META-INF/MANIFEST.MF | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF index 179cf981850..8af0ee93656 100644 --- a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF @@ -5,7 +5,8 @@ Bundle-SymbolicName: com.sap.sse.shared.android Bundle-Version: 1.0.0.qualifier Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.7 -Require-Bundle: com.sap.sse.common +Require-Bundle: com.sap.sse.common, + org.json.simple;bundle-version="1.1.0" Export-Package: com.sap.sse.concurrent, com.sap.sse.shared.media, com.sap.sse.shared.media.impl, From c651316031e10dc4e926ddda0cfcde21dce22a1d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:02:07 +0100 Subject: [PATCH 006/259] Moved SettingsToJsonSerializer to com.sap.sse.shared.android and added com.sap.sse.shared.android.test --- .../.classpath | 7 +++++ .../.gitignore | 2 ++ java/com.sap.sse.shared.android.test/.project | 28 +++++++++++++++++++ .../.settings/org.eclipse.jdt.core.prefs | 12 ++++++++ .../.settings/org.eclipse.pde.core.prefs | 3 ++ .../META-INF/MANIFEST.MF | 13 +++++++++ .../build.properties | 4 +++ java/com.sap.sse.shared.android.test/pom.xml | 12 ++++++++ .../test/SettingsJsonSerializationTest.java | 4 +-- .../META-INF/MANIFEST.MF | 4 +++ .../settings/SettingsToJsonSerializer.java | 2 +- java/com.sap.sse/META-INF/MANIFEST.MF | 1 - java/pom.xml | 1 + 13 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 java/com.sap.sse.shared.android.test/.classpath create mode 100644 java/com.sap.sse.shared.android.test/.gitignore create mode 100644 java/com.sap.sse.shared.android.test/.project create mode 100644 java/com.sap.sse.shared.android.test/.settings/org.eclipse.jdt.core.prefs create mode 100644 java/com.sap.sse.shared.android.test/.settings/org.eclipse.pde.core.prefs create mode 100644 java/com.sap.sse.shared.android.test/META-INF/MANIFEST.MF create mode 100644 java/com.sap.sse.shared.android.test/build.properties create mode 100644 java/com.sap.sse.shared.android.test/pom.xml rename java/{com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization => com.sap.sse.shared.android.test/src/com/sap/sse/shared/android}/test/SettingsJsonSerializationTest.java (96%) mode change 100755 => 100644 rename java/{com.sap.sse/src/com/sap/sse => com.sap.sse.shared.android/src/com/sap/sse/shared}/settings/SettingsToJsonSerializer.java (96%) mode change 100755 => 100644 diff --git a/java/com.sap.sse.shared.android.test/.classpath b/java/com.sap.sse.shared.android.test/.classpath new file mode 100644 index 00000000000..eca7bdba8f0 --- /dev/null +++ b/java/com.sap.sse.shared.android.test/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/java/com.sap.sse.shared.android.test/.gitignore b/java/com.sap.sse.shared.android.test/.gitignore new file mode 100644 index 00000000000..743bbf5b315 --- /dev/null +++ b/java/com.sap.sse.shared.android.test/.gitignore @@ -0,0 +1,2 @@ +bin +/bin/ diff --git a/java/com.sap.sse.shared.android.test/.project b/java/com.sap.sse.shared.android.test/.project new file mode 100644 index 00000000000..a32b5afbd2d --- /dev/null +++ b/java/com.sap.sse.shared.android.test/.project @@ -0,0 +1,28 @@ + + + com.sap.sse.shared.android.test + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/java/com.sap.sse.shared.android.test/.settings/org.eclipse.jdt.core.prefs b/java/com.sap.sse.shared.android.test/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..a698e59674f --- /dev/null +++ b/java/com.sap.sse.shared.android.test/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/java/com.sap.sse.shared.android.test/.settings/org.eclipse.pde.core.prefs b/java/com.sap.sse.shared.android.test/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 00000000000..f29e940a005 --- /dev/null +++ b/java/com.sap.sse.shared.android.test/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/java/com.sap.sse.shared.android.test/META-INF/MANIFEST.MF b/java/com.sap.sse.shared.android.test/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..40e6dcd56b5 --- /dev/null +++ b/java/com.sap.sse.shared.android.test/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Tests for SSE Shared Android +Bundle-SymbolicName: com.sap.sse.shared.android.test +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: SAP +Fragment-Host: com.sap.sse.shared.android +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.mockito.mockito-core;bundle-version="1.9.5", + org.hamcrest;bundle-version="1.1.0", + org.objenesis;bundle-version="1.3.0", + org.junit4;bundle-version="4.8.2" +Export-Package: com.sap.sse.shared.android.test diff --git a/java/com.sap.sse.shared.android.test/build.properties b/java/com.sap.sse.shared.android.test/build.properties new file mode 100644 index 00000000000..34d2e4d2dad --- /dev/null +++ b/java/com.sap.sse.shared.android.test/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/java/com.sap.sse.shared.android.test/pom.xml b/java/com.sap.sse.shared.android.test/pom.xml new file mode 100644 index 00000000000..b3e8f6a5910 --- /dev/null +++ b/java/com.sap.sse.shared.android.test/pom.xml @@ -0,0 +1,12 @@ + + + 4.0.0 + + root + com.sap.sailing + 1.0.0-SNAPSHOT + + com.sap.sse.shared.android.test + eclipse-test-plugin + diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/SettingsJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java old mode 100755 new mode 100644 similarity index 96% rename from java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/SettingsJsonSerializationTest.java rename to java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java index 82d14b428db..5c6874698f0 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/SettingsJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java @@ -1,4 +1,4 @@ -package com.sap.sailing.server.gateway.serialization.test; +package com.sap.sse.shared.android.test; import static org.junit.Assert.assertEquals; @@ -19,7 +19,7 @@ import com.sap.sse.common.settings.EnumListSetting; import com.sap.sse.common.settings.EnumSetting; import com.sap.sse.common.settings.StringSetting; import com.sap.sse.common.settings.StringToEnumConverter; -import com.sap.sse.settings.SettingsToJsonSerializer; +import com.sap.sse.shared.settings.SettingsToJsonSerializer; public class SettingsJsonSerializationTest { diff --git a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF index 8af0ee93656..289d7b06dcd 100644 --- a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF @@ -11,3 +11,7 @@ Export-Package: com.sap.sse.concurrent, com.sap.sse.shared.media, com.sap.sse.shared.media.impl, com.sap.sse.util.impl +Import-Package: com.sap.sse.common.settings, + com.sap.sse.common.settings.base, + com.sap.sse.common.settings.converter, + com.sap.sse.common.settings.serializer diff --git a/java/com.sap.sse/src/com/sap/sse/settings/SettingsToJsonSerializer.java b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java old mode 100755 new mode 100644 similarity index 96% rename from java/com.sap.sse/src/com/sap/sse/settings/SettingsToJsonSerializer.java rename to java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java index 40e14e2afcc..59d8f9b43af --- a/java/com.sap.sse/src/com/sap/sse/settings/SettingsToJsonSerializer.java +++ b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java @@ -1,4 +1,4 @@ -package com.sap.sse.settings; +package com.sap.sse.shared.settings; import org.json.simple.JSONArray; import org.json.simple.JSONObject; diff --git a/java/com.sap.sse/META-INF/MANIFEST.MF b/java/com.sap.sse/META-INF/MANIFEST.MF index c1d1ed3529f..3adeecda510 100644 --- a/java/com.sap.sse/META-INF/MANIFEST.MF +++ b/java/com.sap.sse/META-INF/MANIFEST.MF @@ -11,7 +11,6 @@ Export-Package: com.sap.sse, com.sap.sse.i18n.impl, com.sap.sse.osgi, com.sap.sse.qrcode, - com.sap.sse.settings, com.sap.sse.util, com.sap.sse.util.impl, com.sap.sse.util.kmeans diff --git a/java/pom.xml b/java/pom.xml index ab62aa66585..be9ded598a8 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -142,6 +142,7 @@ com.sap.sse.security.test com.sap.sse.operationaltransformation.test com.sap.sse.common.test + com.sap.sse.shared.android.test com.sap.sse.filestorage.test com.sap.sailing.datamining.test com.sap.sailing.domain.deckmanadapter.test From 65e6802fb22232a76d31945908fe143bed33a5ba Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:30:35 +0100 Subject: [PATCH 007/259] bug 2775: Extended Settings serialization test to also test SettingsToStringMapSerializer with the same set of test cases by introducing a abstract test class --- .../AbstractSettingsToJsonSerializer.java | 4 +- .../test/AbstractJsonSerializationTest.java | 129 +++++++++++++++ .../test/SettingsJsonSerializationTest.java | 154 ++---------------- .../SettingsToStringMapSerializationTest.java | 21 +++ 4 files changed, 162 insertions(+), 146 deletions(-) create mode 100644 java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java create mode 100644 java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java index 4f2bd148803..dbcac6615a3 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java @@ -78,14 +78,14 @@ public abstract class AbstractSettingsToJsonSerializer { Setting setting = entry.getValue(); if(hasProperty(json, entry.getKey())) { Object jsonValue = get(json, entry.getKey()); - deserialize(setting, jsonValue); + deserializeSetting(setting, jsonValue); } } } return settings; } - private void deserialize(Setting setting, Object jsonValue) { + private void deserializeSetting(Setting setting, Object jsonValue) { if (setting instanceof ValueSetting) { deserializeValueSetting(jsonValue, (ValueSetting) setting); } else if (setting instanceof ListSetting) { diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java new file mode 100644 index 00000000000..3763c5f6ad5 --- /dev/null +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java @@ -0,0 +1,129 @@ +package com.sap.sse.shared.android.test; + +import static org.junit.Assert.assertEquals; + +import java.math.BigDecimal; +import java.util.Arrays; + +import org.junit.Test; + +import com.sap.sse.common.filter.TextOperator; +import com.sap.sse.common.filter.TextOperator.Operators; +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.DecimalListSetting; +import com.sap.sse.common.settings.DecimalSetting; +import com.sap.sse.common.settings.EnumListSetting; +import com.sap.sse.common.settings.EnumSetting; +import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.StringSetting; +import com.sap.sse.common.settings.StringToEnumConverter; + +public abstract class AbstractJsonSerializationTest { + + private static class TestOuterSettings extends AbstractSettings { + private TestSettings nested = new TestSettings("nested", this); + public TestOuterSettings() { + } + } + + private static class TestSettings extends AbstractSettings { + private final StringSetting humba = new StringSetting("humba", this); + // TODO user lambda: TextOperator.Operators::valueOf + private final EnumSetting trala = new EnumSetting<>("trala", this, new StringToEnumConverter() { + @Override + public Operators fromString(String stringValue) { + return TextOperator.Operators.valueOf(stringValue); + } + }); + private final DecimalSetting num = new DecimalSetting("num", this); + private final DecimalListSetting l = new DecimalListSetting("l", this); + + public TestSettings() { + } + public TestSettings(String name, AbstractSettings settings) { + super(name, settings); + } + } + + private static class TestEnumListSettings extends AbstractSettings { + private final EnumListSetting l = new EnumListSetting<>("l", this, new StringToEnumConverter() { + @Override + public Operators fromString(String stringValue) { + return TextOperator.Operators.valueOf(stringValue); + } + }); + public TestEnumListSettings() { + } + } + + private static class DuplicateFieldSettings extends AbstractSettings { + @SuppressWarnings("unused") + private final StringSetting humba = new StringSetting("humba", this); + @SuppressWarnings("unused") + private final DecimalSetting bumba = new DecimalSetting("humba", this); + } + + protected abstract SOT serialize(T settings) throws Exception; + + protected abstract T deserialize(SOT serializedObject, T settings) throws Exception; + + private T serializeAndDeserialize(T objectToSerialize) { + try { + SOT serialized = serialize(objectToSerialize); + + @SuppressWarnings("unchecked") + Class settingsType = (Class) objectToSerialize.getClass(); + T deserializedInstance = settingsType.newInstance(); + + return deserialize(serialized, deserializedInstance); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + public void testFlatJsonSerialization() { + final TestSettings settings = new TestSettings(); + settings.humba.setValue("trala"); + settings.trala.setValue(TextOperator.Operators.Contains); + settings.num.setValue(BigDecimal.TEN); + settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); + + final TestSettings deserializedSettings = serializeAndDeserialize(settings); + assertEquals(settings, deserializedSettings); + } + + @Test + public void testNestedJsonSerialization() { + final TestOuterSettings outerSettings = new TestOuterSettings(); + final TestSettings settings = outerSettings.nested; + settings.humba.setValue("trala"); + settings.trala.setValue(TextOperator.Operators.Contains); + settings.num.setValue(BigDecimal.TEN); + settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); + + final TestOuterSettings deserializedSettings = serializeAndDeserialize(outerSettings); + assertEquals(outerSettings, deserializedSettings); + } + + /** + * Verifies that it is not possible to have two equally named child settings that would cause conflicts on serialization. + */ + @Test(expected = RuntimeException.class) + public void testDuplicateSetting() { + new DuplicateFieldSettings(); + } + + /** + * A white-box test that tests property name escaping in case the property name conflicts with how type + * names (used particularly for enum settings) are represented in JSON. + */ + @Test + public void testJsonSerializationWithEnumTypedList() throws ClassNotFoundException { + final TestEnumListSettings settings = new TestEnumListSettings(); + settings.l.setValues(Arrays.asList(Operators.Contains, Operators.EndsWith)); + + final TestEnumListSettings deserializedSettings = serializeAndDeserialize(settings); + assertEquals(settings, deserializedSettings); + } +} diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java index 5c6874698f0..e5db9feded4 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java @@ -1,158 +1,24 @@ package com.sap.sse.shared.android.test; -import static org.junit.Assert.assertEquals; - -import java.math.BigDecimal; -import java.util.Arrays; - import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; -import org.junit.Test; -import com.sap.sse.common.filter.TextOperator; -import com.sap.sse.common.filter.TextOperator.Operators; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.DecimalListSetting; -import com.sap.sse.common.settings.DecimalSetting; -import com.sap.sse.common.settings.EnumListSetting; -import com.sap.sse.common.settings.EnumSetting; -import com.sap.sse.common.settings.StringSetting; -import com.sap.sse.common.settings.StringToEnumConverter; +import com.sap.sse.common.settings.Settings; import com.sap.sse.shared.settings.SettingsToJsonSerializer; -public class SettingsJsonSerializationTest { - - private static class TestOuterSettings extends AbstractSettings { - private TestSettings nested = new TestSettings("nested", this); - - } - - private static class TestSettings extends AbstractSettings { - private final StringSetting humba = new StringSetting("humba", this); - // TODO user lambda: TextOperator.Operators::valueOf - private final EnumSetting trala = new EnumSetting<>("trala", this, new StringToEnumConverter() { - @Override - public Operators fromString(String stringValue) { - return TextOperator.Operators.valueOf(stringValue); - } - }); - private final DecimalSetting num = new DecimalSetting("num", this); - private final DecimalListSetting l = new DecimalListSetting("l", this); - - public TestSettings() { - } - public TestSettings(String name, AbstractSettings settings) { - super(name, settings); - } - } - - private static class TestEnumListSettings extends AbstractSettings { - private final EnumListSetting l = new EnumListSetting<>("l", this, new StringToEnumConverter() { - @Override - public Operators fromString(String stringValue) { - return TextOperator.Operators.valueOf(stringValue); - } - }); - } - - private static class DuplicateFieldSettings extends AbstractSettings { - @SuppressWarnings("unused") - private final StringSetting humba = new StringSetting("humba", this); - @SuppressWarnings("unused") - private final DecimalSetting bumba = new DecimalSetting("humba", this); - } +public class SettingsJsonSerializationTest extends AbstractJsonSerializationTest { private final SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); - private JSONObject serializeAndDeserialize(JSONObject jsonObject) { - String serializedJson = jsonObject.toJSONString(); - try { - return (JSONObject) new JSONParser().parse(serializedJson); - } catch (ParseException e) { - throw new RuntimeException(e); - } + @Override + protected String serialize(T settings) throws Exception { + // Do not change this to return a JSONOBject instance. + // JSONOBject is just a HashMap and you only know if it is really JSON serializable if you do it! + return serializer.serialize(settings).toJSONString(); } - @Test - public void testFlatJsonSerialization() { - final TestSettings settings = new TestSettings(); - settings.humba.setValue("trala"); - settings.trala.setValue(TextOperator.Operators.Contains); - settings.num.setValue(BigDecimal.TEN); - settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); - - final TestSettings deserializedSettings = serializer.deserialize(new TestSettings(), serializeAndDeserialize(serializer.serialize(settings))); - assertEquals(settings, deserializedSettings); + @Override + protected T deserialize(String serializedObject, T settings) throws Exception { + return serializer.deserialize(settings, (JSONObject) new JSONParser().parse(serializedObject)); } - - @Test - public void testNestedJsonSerialization() { - final TestOuterSettings outerSettings = new TestOuterSettings(); - final TestSettings settings = outerSettings.nested; - settings.humba.setValue("trala"); - settings.trala.setValue(TextOperator.Operators.Contains); - settings.num.setValue(BigDecimal.TEN); - settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); - - final TestOuterSettings deserializedSettings = serializer.deserialize(new TestOuterSettings(), serializeAndDeserialize(serializer.serialize(outerSettings))); - assertEquals(outerSettings, deserializedSettings); - } - - /** - * Verifies that it is not possible to have two equally named child settings that would cause conflicts on serialization. - */ - @Test(expected = RuntimeException.class) - public void testDuplicateSetting() { - new DuplicateFieldSettings(); - } - -// /** -// * A white-box test that tests property name escaping in case the property name conflicts with how type -// * names (used particularly for enum settings) are represented in JSON. -// */ -// @Test -// public void testJsonSerializationWithFunnyPropertyName() throws ClassNotFoundException { -// final Map settingsMap = new HashMap<>(); -// settingsMap.put("humba___TYPE", new StringSetting("trala")); -// settingsMap.put("trala___TYPE___TYPE", new EnumSetting<>(TextOperator.Operators.Contains)); -// Settings settings = new MapSettings(settingsMap); -// SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); -// JSONObject json = serializer.serialize(settings); -// Settings deserializedSettings = serializer.deserialize(json); -// assertEquals(settingsMap, deserializedSettings.getNonDefaultSettings()); -// } - - /** - * A white-box test that tests property name escaping in case the property name conflicts with how type - * names (used particularly for enum settings) are represented in JSON. - */ - @Test - public void testJsonSerializationWithEnumTypedList() throws ClassNotFoundException { - final TestEnumListSettings settings = new TestEnumListSettings(); - settings.l.setValues(Arrays.asList(Operators.Contains, Operators.EndsWith)); - - final TestEnumListSettings deserializedSettings = serializer.deserialize(new TestEnumListSettings(), serializeAndDeserialize(serializer.serialize(settings))); - assertEquals(settings, deserializedSettings); - } - -// /** -// * A white-box test that tests property name escaping in case the property name conflicts with how type -// * names (used particularly for enum settings) are represented in JSON. -// */ -// @Test -// public void testJsonSerializationWithStringifiedEnum() throws ClassNotFoundException { -// final Map settingsMap = new HashMap<>(); -// final List list = new ArrayList<>(); -// list.add(new StringSetting(Operators.Contains)); -// list.add(new StringSetting(Operators.EndsWith)); -// settingsMap.put("l", new ListSetting(list)); -// Settings settings = new MapSettings(settingsMap); -// SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); -// JSONObject json = serializer.serialize(settings); -// Settings deserializedSettings = serializer.deserialize(json); -// ListSetting l = (ListSetting) deserializedSettings.getNonDefaultSettings().get("l"); -// assertEquals(Arrays.asList(Operators.Contains, Operators.EndsWith), l.getEnumList(Operators.class)); -// } - } diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java new file mode 100644 index 00000000000..23e21833dbc --- /dev/null +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java @@ -0,0 +1,21 @@ +package com.sap.sse.shared.android.test; + +import java.util.Map; + +import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer; + +public class SettingsToStringMapSerializationTest extends AbstractJsonSerializationTest>> { + + private final SettingsToStringMapSerializer serializer = new SettingsToStringMapSerializer(); + + @Override + protected Map> serialize(T settings) throws Exception { + return serializer.serialize(settings); + } + + @Override + protected T deserialize(Map> serializedObject, T settings) throws Exception { + return serializer.deserialize(settings, serializedObject); + } +} From c61af77f26c09c5e98d53eee8e7e1e4230afe68e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:50:25 +0100 Subject: [PATCH 008/259] Fixed SettingsToStringMapSerializer for nested SettingsList --- .../settings/serializer/SettingsToStringMapSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java index 4a55a045826..fcf3b7084af 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java @@ -180,7 +180,7 @@ public class SettingsToStringMapSerializer { o1error = true; } try { - o2int = Integer.parseInt(o1); + o2int = Integer.parseInt(o2); } catch (NumberFormatException e) { o1error = true; } From 1fe52232c74282bacf8bbc4e172877e2d428cd5c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:51:13 +0100 Subject: [PATCH 009/259] bug 2775: Changed SettingsList constructor for Setting nesting --- .../src/com/sap/sse/common/settings/SettingsList.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java index 4d07d0f2a79..d42cafcb6fa 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java @@ -6,8 +6,9 @@ import com.sap.sse.common.settings.base.AbstractListSetting; public class SettingsList extends AbstractListSetting implements SettingsListSetting { private SettingsFactory settingsFactory; - - public SettingsList(SettingsFactory settingsFactory) { + + public SettingsList(String name, AbstractSettings settings, SettingsFactory settingsFactory) { + super(name, settings); this.settingsFactory = settingsFactory; } From ce1c96d48dd0cbbd994211a585e4aa1ef6821f97 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:51:44 +0100 Subject: [PATCH 010/259] bug 2775: Added test case for nested SettingsList --- .../test/AbstractJsonSerializationTest.java | 119 +++++++++++------- 1 file changed, 74 insertions(+), 45 deletions(-) diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java index 3763c5f6ad5..ea945872fe5 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java @@ -15,72 +15,92 @@ import com.sap.sse.common.settings.DecimalSetting; import com.sap.sse.common.settings.EnumListSetting; import com.sap.sse.common.settings.EnumSetting; import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.SettingsList; import com.sap.sse.common.settings.StringSetting; import com.sap.sse.common.settings.StringToEnumConverter; public abstract class AbstractJsonSerializationTest { - + private static class TestOuterSettings extends AbstractSettings { - private TestSettings nested = new TestSettings("nested", this); + private SimpleTestSettings nested = new SimpleTestSettings("nested", this); + public TestOuterSettings() { } } - - private static class TestSettings extends AbstractSettings { - private final StringSetting humba = new StringSetting("humba", this); - // TODO user lambda: TextOperator.Operators::valueOf - private final EnumSetting trala = new EnumSetting<>("trala", this, new StringToEnumConverter() { - @Override - public Operators fromString(String stringValue) { - return TextOperator.Operators.valueOf(stringValue); - } - }); - private final DecimalSetting num = new DecimalSetting("num", this); - private final DecimalListSetting l = new DecimalListSetting("l", this); - - public TestSettings() { - } - public TestSettings(String name, AbstractSettings settings) { - super(name, settings); + + private static class TestListSettings extends AbstractSettings { + private SettingsList l = new SettingsList<>("l", this, SimpleTestSettings::new); + + public TestListSettings() { } } - + + private static class SimpleTestSettings extends AbstractSettings { + private final StringSetting string = new StringSetting("string", this); + private final DecimalSetting num = new DecimalSetting("num", this); + + public SimpleTestSettings() { + } + + public SimpleTestSettings(String string, BigDecimal num) { + this.string.setValue(string); + this.num.setValue(num); + } + + public SimpleTestSettings(String name, AbstractSettings parent) { + super(name, parent); + } + } + + private static class TestSettings extends AbstractSettings { + private final StringSetting humba = new StringSetting("humba", this); + private final EnumSetting trala = new EnumSetting<>("trala", this, + TextOperator.Operators::valueOf); + private final DecimalSetting num = new DecimalSetting("num", this); + private final DecimalListSetting l = new DecimalListSetting("l", this); + + public TestSettings() { + } + } + private static class TestEnumListSettings extends AbstractSettings { - private final EnumListSetting l = new EnumListSetting<>("l", this, new StringToEnumConverter() { - @Override - public Operators fromString(String stringValue) { - return TextOperator.Operators.valueOf(stringValue); - } - }); + private final EnumListSetting l = new EnumListSetting<>("l", this, + new StringToEnumConverter() { + @Override + public Operators fromString(String stringValue) { + return TextOperator.Operators.valueOf(stringValue); + } + }); + public TestEnumListSettings() { } } - + private static class DuplicateFieldSettings extends AbstractSettings { @SuppressWarnings("unused") private final StringSetting humba = new StringSetting("humba", this); @SuppressWarnings("unused") private final DecimalSetting bumba = new DecimalSetting("humba", this); } - + protected abstract SOT serialize(T settings) throws Exception; - + protected abstract T deserialize(SOT serializedObject, T settings) throws Exception; - + private T serializeAndDeserialize(T objectToSerialize) { try { SOT serialized = serialize(objectToSerialize); - + @SuppressWarnings("unchecked") Class settingsType = (Class) objectToSerialize.getClass(); T deserializedInstance = settingsType.newInstance(); - + return deserialize(serialized, deserializedInstance); } catch (Exception e) { throw new RuntimeException(e); } } - + @Test public void testFlatJsonSerialization() { final TestSettings settings = new TestSettings(); @@ -88,7 +108,7 @@ public abstract class AbstractJsonSerializationTest { settings.trala.setValue(TextOperator.Operators.Contains); settings.num.setValue(BigDecimal.TEN); settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); - + final TestSettings deserializedSettings = serializeAndDeserialize(settings); assertEquals(settings, deserializedSettings); } @@ -96,18 +116,17 @@ public abstract class AbstractJsonSerializationTest { @Test public void testNestedJsonSerialization() { final TestOuterSettings outerSettings = new TestOuterSettings(); - final TestSettings settings = outerSettings.nested; - settings.humba.setValue("trala"); - settings.trala.setValue(TextOperator.Operators.Contains); + final SimpleTestSettings settings = outerSettings.nested; + settings.string.setValue("trala"); settings.num.setValue(BigDecimal.TEN); - settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); - + final TestOuterSettings deserializedSettings = serializeAndDeserialize(outerSettings); assertEquals(outerSettings, deserializedSettings); } - + /** - * Verifies that it is not possible to have two equally named child settings that would cause conflicts on serialization. + * Verifies that it is not possible to have two equally named child settings that would cause conflicts on + * serialization. */ @Test(expected = RuntimeException.class) public void testDuplicateSetting() { @@ -115,15 +134,25 @@ public abstract class AbstractJsonSerializationTest { } /** - * A white-box test that tests property name escaping in case the property name conflicts with how type - * names (used particularly for enum settings) are represented in JSON. + * A white-box test that tests property name escaping in case the property name conflicts with how type names (used + * particularly for enum settings) are represented in JSON. */ @Test - public void testJsonSerializationWithEnumTypedList() throws ClassNotFoundException { + public void testJsonSerializationWithEnumTypedList() { final TestEnumListSettings settings = new TestEnumListSettings(); settings.l.setValues(Arrays.asList(Operators.Contains, Operators.EndsWith)); - + final TestEnumListSettings deserializedSettings = serializeAndDeserialize(settings); assertEquals(settings, deserializedSettings); } + + @Test + public void testJsonSerializationWithNestedSettingsList() { + final TestListSettings settings = new TestListSettings(); + settings.l.setValues(Arrays.asList(new SimpleTestSettings("blubb", BigDecimal.TEN), new SimpleTestSettings( + "bla", BigDecimal.ONE))); + + final TestListSettings deserializedSettings = serializeAndDeserialize(settings); + assertEquals(settings, deserializedSettings); + } } From 161c8fa45532e88faffdcba05b1ad69fef614e7b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:54:41 +0100 Subject: [PATCH 011/259] bug 2775: Added missing BooleanSetting --- .../sse/common/settings/BooleanSetting.java | 15 +++++++++ .../settings/converter/BooleanConverter.java | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java new file mode 100644 index 00000000000..4914d179301 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java @@ -0,0 +1,15 @@ +package com.sap.sse.common.settings; + +import com.sap.sse.common.settings.base.AbstractValueSetting; +import com.sap.sse.common.settings.converter.BooleanConverter; + +public class BooleanSetting extends AbstractValueSetting { + + public BooleanSetting(String name, AbstractSettings settings) { + this(name, settings, null); + } + + public BooleanSetting(String name, AbstractSettings settings, Boolean defaultValue) { + super(name, settings, defaultValue, BooleanConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java new file mode 100644 index 00000000000..9a81059a863 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java @@ -0,0 +1,31 @@ +package com.sap.sse.common.settings.converter; + +import com.sap.sse.common.settings.ValueConverter; + +public class BooleanConverter implements ValueConverter { + + public static final BooleanConverter INSTANCE = new BooleanConverter(); + + private BooleanConverter() { + } + + @Override + public Object toJSONValue(Boolean value) { + return value; + } + + @Override + public Boolean fromJSONValue(Object jsonValue) { + return (Boolean) jsonValue; + } + + @Override + public String toStringValue(Boolean value) { + return value == null ? null : value.toString(); + } + + @Override + public Boolean fromStringValue(String stringValue) { + return stringValue == null ? null : Boolean.valueOf(stringValue); + } +} From 0800ded071e7848147bfd080434435459cf95f1c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 15:56:25 +0100 Subject: [PATCH 012/259] bug 2775: Extended test case to include BooleanSetting --- .../sse/shared/android/test/AbstractJsonSerializationTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java index ea945872fe5..333c8c2c539 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java @@ -10,6 +10,7 @@ import org.junit.Test; import com.sap.sse.common.filter.TextOperator; import com.sap.sse.common.filter.TextOperator.Operators; import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.BooleanSetting; import com.sap.sse.common.settings.DecimalListSetting; import com.sap.sse.common.settings.DecimalSetting; import com.sap.sse.common.settings.EnumListSetting; @@ -54,6 +55,7 @@ public abstract class AbstractJsonSerializationTest { private static class TestSettings extends AbstractSettings { private final StringSetting humba = new StringSetting("humba", this); + private final BooleanSetting bumpa = new BooleanSetting("bumpa", this); private final EnumSetting trala = new EnumSetting<>("trala", this, TextOperator.Operators::valueOf); private final DecimalSetting num = new DecimalSetting("num", this); @@ -105,6 +107,7 @@ public abstract class AbstractJsonSerializationTest { public void testFlatJsonSerialization() { final TestSettings settings = new TestSettings(); settings.humba.setValue("trala"); + settings.bumpa.setValue(true); settings.trala.setValue(TextOperator.Operators.Contains); settings.num.setValue(BigDecimal.TEN); settings.l.setValues(Arrays.asList(BigDecimal.ONE, BigDecimal.valueOf(2), BigDecimal.valueOf(3))); From a3e0545cddcf5d301a99bff2b753499de85e3518 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 16:40:20 +0100 Subject: [PATCH 013/259] bug 2775: Consistent/better naming of test classes --- ...lizationTest.java => AbstractSettingsSerializationTest.java} | 2 +- ...ializationTest.java => SettingsToJsonSerializationTest.java} | 2 +- .../android/test/SettingsToStringMapSerializationTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/{AbstractJsonSerializationTest.java => AbstractSettingsSerializationTest.java} (96%) rename java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/{SettingsJsonSerializationTest.java => SettingsToJsonSerializationTest.java} (88%) diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java similarity index 96% rename from java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java rename to java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java index 333c8c2c539..ca9011426d4 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java @@ -20,7 +20,7 @@ import com.sap.sse.common.settings.SettingsList; import com.sap.sse.common.settings.StringSetting; import com.sap.sse.common.settings.StringToEnumConverter; -public abstract class AbstractJsonSerializationTest { +public abstract class AbstractSettingsSerializationTest { private static class TestOuterSettings extends AbstractSettings { private SimpleTestSettings nested = new SimpleTestSettings("nested", this); diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java similarity index 88% rename from java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java rename to java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java index e5db9feded4..b2c9d84dc83 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java @@ -6,7 +6,7 @@ import org.json.simple.parser.JSONParser; import com.sap.sse.common.settings.Settings; import com.sap.sse.shared.settings.SettingsToJsonSerializer; -public class SettingsJsonSerializationTest extends AbstractJsonSerializationTest { +public class SettingsToJsonSerializationTest extends AbstractSettingsSerializationTest { private final SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java index 23e21833dbc..46a2fa66fe5 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java @@ -5,7 +5,7 @@ import java.util.Map; import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer; -public class SettingsToStringMapSerializationTest extends AbstractJsonSerializationTest>> { +public class SettingsToStringMapSerializationTest extends AbstractSettingsSerializationTest>> { private final SettingsToStringMapSerializer serializer = new SettingsToStringMapSerializer(); From aa98ae70ecfe1aa18ed8b928b200fb3d8b61687d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 16:44:35 +0100 Subject: [PATCH 014/259] bug 2775: Using "." in Setting names is now disallowed to prevent problems while parsing settings from URLs --- .../sse/common/settings/AbstractSettings.java | 31 +++++++++++-------- .../com/sap/sse/common/settings/Settings.java | 3 ++ .../SettingsToStringMapSerializer.java | 7 ++--- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index 59a7bacde6b..51a03279cab 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -5,47 +5,52 @@ import java.util.HashMap; import java.util.Map; public abstract class AbstractSettings extends AbstractSetting implements Settings { - + private Map childSettings = new HashMap<>(); - + public AbstractSettings() { } - + public AbstractSettings(String name, AbstractSettings settings) { super(name, settings); } - + protected void addSetting(String name, Setting setting) { - if(childSettings.containsKey(name)) { - throw new IllegalArgumentException("setting with name " + name + " already added to setting type " + getClass().getSimpleName()); + if (name.contains(Settings.PATH_SEPARATOR)) { + throw new IllegalArgumentException("\"" + Settings.PATH_SEPARATOR + + "\" is currently not allowed for setting names"); + } + if (childSettings.containsKey(name)) { + throw new IllegalArgumentException("setting with name " + name + " already added to setting type " + + getClass().getSimpleName()); } childSettings.put(name, setting); } @Override public boolean isDefaultValue() { - for(Setting setting : childSettings.values()) { - if(!setting.isDefaultValue()) { + for (Setting setting : childSettings.values()) { + if (!setting.isDefaultValue()) { return false; } } return true; } - + @Override public Map getChildSettings() { return Collections.unmodifiableMap(childSettings); } - + public String toString() { StringBuilder sb = new StringBuilder("{(").append(this.getClass().getSimpleName()).append(")"); boolean first = true; - for(Map.Entry childSetting : childSettings.entrySet()) { - if(!first) { + for (Map.Entry childSetting : childSettings.entrySet()) { + if (!first) { sb.append("; "); } sb.append(childSetting.getKey() + "=" + childSetting.getValue()); - + first = false; } sb.append("}"); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java index b2e0d7836fe..6f7df127e71 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java @@ -24,6 +24,9 @@ import java.util.Map; * */ public interface Settings extends Setting { + + public static final String PATH_SEPARATOR = "."; + /** * Obtains all settings that have non-default values and therefore are required for the later re-construction * of the settings object when passed the resulting map. diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java index fcf3b7084af..82cc97e3506 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java @@ -18,7 +18,6 @@ import com.sap.sse.common.settings.ValueListSetting; import com.sap.sse.common.settings.ValueSetting; public class SettingsToStringMapSerializer { - private static final String PATH_SEPARATOR = "."; public Map> serialize(Settings settings) { final Map> result = new HashMap<>(); @@ -42,7 +41,7 @@ public class SettingsToStringMapSerializer { } else if (setting instanceof ValueListSetting) { serialized.put(key, serializeValueListSetting(key, (ValueListSetting) setting)); } else { - String prefix = key + PATH_SEPARATOR; + String prefix = key + Settings.PATH_SEPARATOR; if (setting instanceof Settings) { serialize(prefix, (Settings) setting, serialized); } else if (setting instanceof SettingsListSetting) { @@ -57,7 +56,7 @@ public class SettingsToStringMapSerializer { Map> serialized) { int index = 0; for (T childSettings : setting.getValues()) { - String nestedPrefix = prefix + index + PATH_SEPARATOR; + String nestedPrefix = prefix + index + Settings.PATH_SEPARATOR; serialize(nestedPrefix, childSettings, serialized); index++; } @@ -151,7 +150,7 @@ public class SettingsToStringMapSerializer { Map>> result = new HashMap<>(); for (Map.Entry> entry : values.entrySet()) { String key = entry.getKey(); - int separatorIndex = key.indexOf(PATH_SEPARATOR); + int separatorIndex = key.indexOf(Settings.PATH_SEPARATOR); if (separatorIndex > 0) { String group = key.substring(0, separatorIndex); String nestedKey = key.substring(separatorIndex + 1); From 44572505e8a770d0700253e36601361b8c467d8e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 16:46:51 +0100 Subject: [PATCH 015/259] bug 2775: Added test to prevent "." in Setting names --- .../test/AbstractSettingsSerializationTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java index ca9011426d4..6dd52eedbbd 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java @@ -84,6 +84,11 @@ public abstract class AbstractSettingsSerializationTest { @SuppressWarnings("unused") private final DecimalSetting bumba = new DecimalSetting("humba", this); } + + private static class DisallowedKeySettings extends AbstractSettings { + @SuppressWarnings("unused") + private final StringSetting disallowedKey= new StringSetting("disallowed.key", this); + } protected abstract SOT serialize(T settings) throws Exception; @@ -135,6 +140,14 @@ public abstract class AbstractSettingsSerializationTest { public void testDuplicateSetting() { new DuplicateFieldSettings(); } + + /** + * Verifies that it is not possible to have setting names with ".". + */ + @Test(expected = RuntimeException.class) + public void testDisallowedSettingNameSetting() { + new DisallowedKeySettings(); + } /** * A white-box test that tests property name escaping in case the property name conflicts with how type names (used From 14a5eb2c5b7ab339317af1d1e0f3f71912b96d34 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 16:54:14 +0100 Subject: [PATCH 016/259] bug 2775: Added setting type for UUID --- .../sse/common/settings/UUIDListSetting.java | 12 +++++++ .../sap/sse/common/settings/UUIDSetting.java | 17 ++++++++++ .../settings/converter/UUIDConverter.java | 33 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java new file mode 100644 index 00000000000..083a92368ec --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java @@ -0,0 +1,12 @@ +package com.sap.sse.common.settings; + +import java.util.UUID; + +import com.sap.sse.common.settings.base.AbstractValueListSetting; +import com.sap.sse.common.settings.converter.UUIDConverter; + +public class UUIDListSetting extends AbstractValueListSetting { + public UUIDListSetting(String name, AbstractSettings settings) { + super(name, settings, UUIDConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java new file mode 100644 index 00000000000..784393c627d --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java @@ -0,0 +1,17 @@ +package com.sap.sse.common.settings; + +import java.util.UUID; + +import com.sap.sse.common.settings.base.AbstractValueSetting; +import com.sap.sse.common.settings.converter.UUIDConverter; + +public class UUIDSetting extends AbstractValueSetting { + + public UUIDSetting(String name, AbstractSettings settings) { + this(name, settings, null); + } + + public UUIDSetting(String name, AbstractSettings settings, UUID defaultValue) { + super(name, settings, defaultValue, UUIDConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java new file mode 100644 index 00000000000..9ef5c3e7044 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java @@ -0,0 +1,33 @@ +package com.sap.sse.common.settings.converter; + +import java.util.UUID; + +import com.sap.sse.common.settings.ValueConverter; + +public class UUIDConverter implements ValueConverter { + + public static final UUIDConverter INSTANCE = new UUIDConverter(); + + private UUIDConverter() { + } + + @Override + public Object toJSONValue(UUID value) { + return toStringValue(value); + } + + @Override + public UUID fromJSONValue(Object jsonValue) { + return fromStringValue((String) jsonValue); + } + + @Override + public String toStringValue(UUID value) { + return value == null ? null : value.toString(); + } + + @Override + public UUID fromStringValue(String stringValue) { + return stringValue == null ? null : UUID.fromString(stringValue); + } +} From 0b56796e76d6b44b5d4005abf0b395eea5fee474 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 15 Mar 2016 17:27:08 +0100 Subject: [PATCH 017/259] Migrated RegattaRaceStatesSettings to new settings api --- .../client/RegattaRaceStatesComponent.java | 24 +++---- .../client/RegattaRaceStatesSettings.java | 70 ++++++++++++------- ...attaRaceStatesSettingsDialogComponent.java | 4 +- ...ttaRaceStatesSettingsJsonDeSerializer.java | 9 +-- .../src/com/sap/sse/common/Util.java | 6 ++ .../base/AbstractValueListSetting.java | 8 +++ 6 files changed, 79 insertions(+), 42 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 270c0c2d8d2..b599103009b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -66,6 +66,7 @@ import com.sap.sailing.gwt.ui.shared.RaceGroupSeriesDTO; import com.sap.sailing.gwt.ui.shared.RaceInfoDTO; import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO; import com.sap.sailing.gwt.ui.shared.WaypointDTO; +import com.sap.sse.common.Util; import com.sap.sse.common.util.NaturalComparator; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.async.MarkedAsyncCallback; @@ -359,8 +360,9 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component return; } final long clientTimeWhenRequestWasSent = System.currentTimeMillis(); - sailingService.getRaceStateEntriesForRaceGroup(eventId, settings.getVisibleCourseAreas(), settings - .getVisibleRegattas(), settings.isShowOnlyCurrentlyRunningRaces(), settings.isShowOnlyRacesOfSameDay(), + sailingService.getRaceStateEntriesForRaceGroup(eventId, Util.asList(settings.getVisibleCourseAreas()), + Util.asList(settings.getVisibleRegattas()), settings.isShowOnlyCurrentlyRunningRaces(), settings + .isShowOnlyRacesOfSameDay(), new MarkedAsyncCallback>( new AsyncCallback>() { @Override @@ -743,16 +745,14 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component @Override public void updateSettings(RegattaRaceStatesSettings newSettings) { - if (settings.getVisibleCourseAreas().isEmpty() + if (Util.isEmpty(settings.getVisibleCourseAreas()) || !settings.getVisibleCourseAreas().equals(newSettings.getVisibleCourseAreas())) { - settings.getVisibleCourseAreas().clear(); - settings.getVisibleCourseAreas().addAll(newSettings.getVisibleCourseAreas()); + settings.setVisibleCourseAreas(newSettings.getVisibleCourseAreas()); fillVisibleCourseAreasInSettingsIfEmpty(); } - if (settings.getVisibleRegattas().isEmpty() + if (Util.isEmpty(settings.getVisibleRegattas()) || !settings.getVisibleRegattas().equals(newSettings.getVisibleRegattas())) { - settings.getVisibleRegattas().clear(); - settings.getVisibleRegattas().addAll(newSettings.getVisibleRegattas()); + settings.setVisibleRegattas(newSettings.getVisibleRegattas()); fillVisibleRegattasInSettingsIfEmpty(); } if (settings.isShowOnlyRacesOfSameDay() != newSettings.isShowOnlyRacesOfSameDay()) { @@ -772,17 +772,17 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } private void fillVisibleRegattasInSettingsIfEmpty() { - if (settings.getVisibleRegattas().isEmpty() && raceGroupDTOs != null) { + if (Util.isEmpty(settings.getVisibleRegattas()) && raceGroupDTOs != null) { for (RaceGroupDTO raceGroup : raceGroupDTOs) { - settings.getVisibleRegattas().add(raceGroup.getName()); + settings.addVisibleRegatta(raceGroup.getName()); } } } private void fillVisibleCourseAreasInSettingsIfEmpty() { - if (settings.getVisibleCourseAreas().isEmpty() && eventDTO != null) { + if (Util.isEmpty(settings.getVisibleCourseAreas()) && eventDTO != null) { for (CourseAreaDTO courseArea : eventDTO.venue.getCourseAreas()) { - settings.getVisibleCourseAreas().add(courseArea.id); + settings.addVisibleCourseArea(courseArea.id); } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java index 6f576eceb3a..70640f9d349 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java @@ -1,54 +1,76 @@ package com.sap.sailing.gwt.regattaoverview.client; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.BooleanSetting; +import com.sap.sse.common.settings.StringListSetting; +import com.sap.sse.common.settings.UUIDListSetting; public class RegattaRaceStatesSettings extends AbstractSettings { - private List visibleCourseAreas; - private List visibleRegattas; - - private boolean showOnlyRacesOfSameDay; - private boolean showOnlyCurrentlyRunningRaces; + private UUIDListSetting visibleCourseAreas = new UUIDListSetting("visibleCourseAreas", this); + private StringListSetting visibleRegattas = new StringListSetting("visibleRegattas", this); + private BooleanSetting showOnlyRacesOfSameDay = new BooleanSetting("showOnlyRacesOfSameDay", this, false); + private BooleanSetting showOnlyCurrentlyRunningRaces = new BooleanSetting("showOnlyCurrentlyRunningRaces", this, + true); public RegattaRaceStatesSettings() { - this.visibleCourseAreas = new ArrayList(); - this.visibleRegattas = new ArrayList(); - this.showOnlyRacesOfSameDay = false; - this.showOnlyCurrentlyRunningRaces = true; } - public RegattaRaceStatesSettings(List visibleCourseAreas, List visibleRegattas, + public RegattaRaceStatesSettings(Iterable visibleCourseAreas, Iterable visibleRegattas, boolean showOnlyRacesOfSameDay, boolean showOnlyCurrentlyRunningRaces) { - this.visibleCourseAreas = visibleCourseAreas; - this.visibleRegattas = visibleRegattas; - this.showOnlyRacesOfSameDay = showOnlyRacesOfSameDay; - this.showOnlyCurrentlyRunningRaces = showOnlyCurrentlyRunningRaces; + this.visibleCourseAreas.setValues(visibleCourseAreas); + this.visibleRegattas.setValues(visibleRegattas); + this.showOnlyRacesOfSameDay.setValue(showOnlyRacesOfSameDay); + this.showOnlyCurrentlyRunningRaces.setValue(showOnlyCurrentlyRunningRaces); } - public List getVisibleCourseAreas() { - return visibleCourseAreas; + public Iterable getVisibleCourseAreas() { + return visibleCourseAreas.getValues(); } - public List getVisibleRegattas() { - return visibleRegattas; + public Iterable getVisibleRegattas() { + return visibleRegattas.getValues(); + } + + public void setVisibleCourseAreas(Iterable visibleCourseAreas) { + this.visibleCourseAreas.setValues(visibleCourseAreas); + } + + public void addVisibleCourseArea(UUID value) { + visibleCourseAreas.addValue(value); + } + + public void clearVisibleCourseAreas() { + visibleCourseAreas.clear(); + } + + public void setVisibleRegattas(Iterable visibleRegattas) { + this.visibleRegattas.setValues(visibleRegattas); + } + + public void addVisibleRegatta(String value) { + visibleRegattas.addValue(value); + } + + public void clearVisibleRegattas() { + visibleRegattas.clear(); } public boolean isShowOnlyRacesOfSameDay() { - return showOnlyRacesOfSameDay; + return showOnlyRacesOfSameDay.getValue(); } public void setShowOnlyRaceOfSameDay(boolean newValue) { - showOnlyRacesOfSameDay = newValue; + showOnlyRacesOfSameDay.setValue(newValue); } public boolean isShowOnlyCurrentlyRunningRaces() { - return showOnlyCurrentlyRunningRaces; + return showOnlyCurrentlyRunningRaces.getValue(); } public void setShowOnlyCurrentlyRunningRaces(boolean newValue) { - showOnlyCurrentlyRunningRaces = newValue; + showOnlyCurrentlyRunningRaces.setValue(newValue); } + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java index c51f5966fce..244ac38b82b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java @@ -265,10 +265,10 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC private void updateLinkUrl(UUID eventId, RegattaRaceStatesSettings settings) { boolean isSetVisibleCourseAreasInUrl = true; boolean isSetVisibleRegattasInUrl = true; - if (settings.getVisibleCourseAreas().size() == courseAreas.size()) { + if (Util.size(settings.getVisibleCourseAreas()) == courseAreas.size()) { isSetVisibleCourseAreasInUrl = false; } - if (settings.getVisibleRegattas().size() == raceGroups.size()) { + if (Util.size(settings.getVisibleRegattas()) == raceGroups.size()) { isSetVisibleRegattasInUrl = false; } resultingLink.setHref(RegattaOverviewEntryPoint.getUrl(eventId, settings, isSetVisibleCourseAreasInUrl, isSetVisibleRegattasInUrl)); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java index 7cb7e55da8a..faf5947fabe 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java @@ -9,6 +9,7 @@ import com.google.gwt.json.client.JSONBoolean; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; import com.sap.sailing.gwt.ui.client.GwtJsonDeSerializer; +import com.sap.sse.common.Util; public class RegattaRaceStatesSettingsJsonDeSerializer implements GwtJsonDeSerializer { @@ -24,14 +25,14 @@ public class RegattaRaceStatesSettingsJsonDeSerializer implements GwtJsonDeSeria result.put(FIELD_SHOW_ONLY_RACES_OF_SAME_DAY, JSONBoolean.getInstance(settings.isShowOnlyRacesOfSameDay())); JSONArray visibleCourseAreas = new JSONArray(); - for (int i = 0 ; i < settings.getVisibleCourseAreas().size() ; i++) { - visibleCourseAreas.set(i, new JSONString(settings.getVisibleCourseAreas().get(i).toString())); + for (int i = 0; i < Util.size(settings.getVisibleCourseAreas()); i++) { + visibleCourseAreas.set(i, new JSONString(Util.get(settings.getVisibleCourseAreas(), i).toString())); } result.put(FIELD_VISIBLE_COURSE_AREAS, visibleCourseAreas); JSONArray visibleRegattas = new JSONArray(); - for (int i = 0 ; i < settings.getVisibleRegattas().size() ; i++) { - visibleRegattas.set(i, new JSONString(settings.getVisibleRegattas().get(i))); + for (int i = 0; i < Util.size(settings.getVisibleRegattas()); i++) { + visibleRegattas.set(i, new JSONString(Util.get(settings.getVisibleRegattas(), i))); } result.put(FIELD_VISIBLE_REGATTAS, visibleRegattas); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java index 624d09fbc0b..b37ceb69152 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java @@ -457,4 +457,10 @@ public class Util { } return result; } + + public static List asList(Iterable visibleCourseAreas) { + ArrayList list = new ArrayList(); + addAll(visibleCourseAreas, list); + return list; + } } \ No newline at end of file diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java index 77b04493f9e..21dadac852f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java @@ -38,6 +38,14 @@ public abstract class AbstractValueListSetting extends AbstractHasValueSettin } } + public void addValue(T value) { + this.values.add(value); + } + + public void clear() { + this.values.clear(); + } + @Override public String toString() { return values.toString(); From 4e9a26452039d0642d373a945e0f5f5e28056894 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 17:55:21 +0100 Subject: [PATCH 018/259] bug 2775: Exporting serializer for GWT UI --- java/com.sap.sse.gwt/META-INF/MANIFEST.MF | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.gwt/META-INF/MANIFEST.MF b/java/com.sap.sse.gwt/META-INF/MANIFEST.MF index 59f798364a0..380af12c155 100644 --- a/java/com.sap.sse.gwt/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.gwt/META-INF/MANIFEST.MF @@ -52,5 +52,6 @@ Export-Package: com.google.gwt.user.client.rpc.core.java.util, com.sap.sse.gwt.resources, com.sap.sse.gwt.server, com.sap.sse.gwt.server.filestorage, + com.sap.sse.gwt.settings, com.sap.sse.gwt.shared, com.sap.sse.gwt.shared.filestorage From 9d0d792b9b6a8fcaa2e43c2f316b58946ec982d2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 17:55:51 +0100 Subject: [PATCH 019/259] bug 2775: Improved functionality of SettingsToUrlSerializer --- .../gwt/settings/SettingsToUrlSerializer.java | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java index 51f18be888b..41f8c649326 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java @@ -12,9 +12,38 @@ public class SettingsToUrlSerializer { private final SettingsToStringMapSerializer settingsToStringMapSerializer = new SettingsToStringMapSerializer(); - public void serializeBasedOnCurrentLocation(Settings settings) { + public String serializeBasedOnCurrentLocation(Settings settings) { final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); serializeToUrlBuilder(settings, urlBuilder); + return urlBuilder.buildString(); + } + + public String serializeBasedOnCurrentLocationWithCleanParameters(Settings settings) { + final UrlBuilder urlBuilder = createUrlBuilderFromCurrentLocationWithCleanParameters(); + serializeToUrlBuilder(settings, urlBuilder); + return urlBuilder.buildString(); + } + + public UrlBuilder serializeUrlBuilderBasedOnCurrentLocation(Settings settings) { + final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); + serializeToUrlBuilder(settings, urlBuilder); + return urlBuilder; + } + + public UrlBuilder serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(Settings settings) { + final UrlBuilder urlBuilder = createUrlBuilderFromCurrentLocationWithCleanParameters(); + serializeToUrlBuilder(settings, urlBuilder); + return urlBuilder; + } + + private UrlBuilder createUrlBuilderFromCurrentLocationWithCleanParameters() { + final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); + for(String parameterName : Window.Location.getParameterMap().keySet()) { + if("gwt.codesvr".equals(parameterName)) { + urlBuilder.removeParameter(parameterName); + } + } + return urlBuilder; } public void serializeToUrlBuilder(Settings settings, UrlBuilder urlBuilder) { @@ -26,10 +55,10 @@ public class SettingsToUrlSerializer { } } - public void deserializeFromCurrentLocation(Settings settings) { + public T deserializeFromCurrentLocation(T settings) { @SuppressWarnings({ "rawtypes", "unchecked" }) Map> values = (Map) Window.Location.getParameterMap(); - settingsToStringMapSerializer.deserialize(settings, values); + return settingsToStringMapSerializer.deserialize(settings, values); } } From 6d201193938955eedcedcb400a7f0124873254bd Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 17:56:39 +0100 Subject: [PATCH 020/259] bug 2775: Initial changes to (de)serialize RegattaOverview Settings from/to URL using the Settings framework --- .../client/RegattaOverviewEntryPoint.java | 63 +++---------------- 1 file changed, 7 insertions(+), 56 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index 9816dfb46b1..25565fbd849 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -1,7 +1,5 @@ package com.sap.sailing.gwt.regattaoverview.client; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; import com.google.gwt.dom.client.Style.Unit; @@ -19,7 +17,7 @@ import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.regattaoverview.client.RegattaRaceStatesComponent.EntryHandler; import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint; import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO; -import com.sap.sse.gwt.client.URLEncoder; +import com.sap.sse.gwt.settings.SettingsToUrlSerializer; import com.sap.sse.security.ui.authentication.generic.sapheader.SAPHeaderWithAuthentication; public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { @@ -132,60 +130,13 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { } public static RegattaRaceStatesSettings createRegattaRaceStatesSettingsFromURL() { - List visibleCourseAreas = new ArrayList(); - List visibleRegattas = new ArrayList(); - - boolean showOnlyCurrentlyRunningRaces = Window.Location.getParameter(PARAM_ONLY_RUNNING_RACES) == null - || !Window.Location.getParameter(PARAM_ONLY_RUNNING_RACES).equalsIgnoreCase("false"); - - boolean showOnlyRacesOfSameDay = Window.Location.getParameter(PARAM_ONLY_RACES_OF_SAME_DAY) != null - && Window.Location.getParameter(PARAM_ONLY_RACES_OF_SAME_DAY).equalsIgnoreCase("true"); - - if (Window.Location.getParameterMap().containsKey(PARAM_COURSE_AREA)) { - for (String value : Window.Location.getParameterMap().get(PARAM_COURSE_AREA)) { - visibleCourseAreas.add(UUID.fromString(value)); - } - } - - if (Window.Location.getParameterMap().containsKey(PARAM_REGATTA)) { - visibleRegattas.addAll(Window.Location.getParameterMap().get(PARAM_REGATTA)); - } - - return new RegattaRaceStatesSettings(visibleCourseAreas, visibleRegattas, showOnlyRacesOfSameDay, showOnlyCurrentlyRunningRaces); + return new SettingsToUrlSerializer().deserializeFromCurrentLocation(new RegattaRaceStatesSettings()); } - public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings, - boolean isSetVisibleCourseAreasInUrl, boolean isSetVisibleRegattasInUrl) { - String debugParam = Window.Location.getParameter("gwt.codesvr"); - String showOnlyCurrentlyRunningRaces = "&" + PARAM_ONLY_RUNNING_RACES + "=" + (settings.isShowOnlyCurrentlyRunningRaces() ? "true" : "false"); - String showOnlyRacesOfSameDay = "&" + PARAM_ONLY_RACES_OF_SAME_DAY + "=" + (settings.isShowOnlyRacesOfSameDay() ? "true" : "false"); - String ignoreLocalSettings = "&" + PARAM_IGNORE_LOCAL_SETTINGS + "=true"; - - StringBuilder visibleCourseAreas = new StringBuilder(); - if (isSetVisibleCourseAreasInUrl) { - for (UUID visibleCourseArea : settings.getVisibleCourseAreas()) { - visibleCourseAreas.append('&'); - visibleCourseAreas.append(PARAM_COURSE_AREA); - visibleCourseAreas.append('='); - visibleCourseAreas.append(visibleCourseArea.toString()); - } - } - StringBuilder visibleRegattas = new StringBuilder(); - if (isSetVisibleRegattasInUrl) { - for (String visibleRegatta : settings.getVisibleRegattas()) { - visibleRegattas.append('&'); - visibleRegattas.append(PARAM_REGATTA); - visibleRegattas.append('='); - visibleRegattas.append(visibleRegatta); - } - } - String link = URLEncoder.encode("/gwt/RegattaOverview.html?" + PARAM_EVENT+ "=" + eventId.toString() - + visibleCourseAreas.toString() - + visibleRegattas.toString() - + showOnlyCurrentlyRunningRaces - + showOnlyRacesOfSameDay - + ignoreLocalSettings - + (debugParam != null && !debugParam.isEmpty() ? "&gwt.codesvr=" + debugParam : "")); - return link; + public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings, boolean isSetVisibleCourseAreasInUrl, + boolean isSetVisibleRegattasInUrl) { + return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(settings) + .setParameter(PARAM_IGNORE_LOCAL_SETTINGS, "true").setParameter(PARAM_EVENT, eventId.toString()) + .buildString(); } } \ No newline at end of file From 330cb741423d27b0c3fb70a108b50db51eb7c218 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 15 Mar 2016 19:20:30 +0100 Subject: [PATCH 021/259] bug 2775: Improvements for serialization of RegattaOverview Settings to URL --- .../client/RegattaOverviewEntryPoint.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index 25565fbd849..a364cde2bb1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -1,5 +1,6 @@ package com.sap.sailing.gwt.regattaoverview.client; +import java.util.Collections; import java.util.UUID; import com.google.gwt.dom.client.Style.Unit; @@ -135,6 +136,15 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings, boolean isSetVisibleCourseAreasInUrl, boolean isSetVisibleRegattasInUrl) { + RegattaRaceStatesSettings copiedSettings = new RegattaRaceStatesSettings(settings.getVisibleCourseAreas(), + settings.getVisibleRegattas(), settings.isShowOnlyRacesOfSameDay(), + settings.isShowOnlyCurrentlyRunningRaces()); + if (!isSetVisibleCourseAreasInUrl) { + copiedSettings.setVisibleCourseAreas(Collections. emptyList()); + } + if (!isSetVisibleRegattasInUrl) { + copiedSettings.setVisibleRegattas(Collections. emptyList()); + } return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(settings) .setParameter(PARAM_IGNORE_LOCAL_SETTINGS, "true").setParameter(PARAM_EVENT, eventId.toString()) .buildString(); From 7b54139389a6bfe7081eed8df37c39f92ce09a86 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 08:11:22 +0100 Subject: [PATCH 022/259] bug 2775: Added GWT module inherit from RegattaOverview to Settings --- .../com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml index ea9bcc3a60c..005c459d00d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml @@ -42,6 +42,7 @@ + From e1563f2abcec79dc4dfddf5a114a08b7913da260 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 08:21:12 +0100 Subject: [PATCH 023/259] bug 2775: Improvements for serialization of RegattaOverview Settings to URL --- .../gwt/regattaoverview/client/RegattaOverviewEntryPoint.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index a364cde2bb1..480627de902 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.regattaoverview.client; import java.util.Collections; import java.util.UUID; +import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; @@ -145,7 +146,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { if (!isSetVisibleRegattasInUrl) { copiedSettings.setVisibleRegattas(Collections. emptyList()); } - return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(settings) + return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(copiedSettings) .setParameter(PARAM_IGNORE_LOCAL_SETTINGS, "true").setParameter(PARAM_EVENT, eventId.toString()) .buildString(); } From efd134dbd95ecdc0350504e096962c824d277805 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 09:36:59 +0100 Subject: [PATCH 024/259] bug 2775: Introduced Set based settings --- ...istSetting.java => CollectionSetting.java} | 2 +- .../common/settings/SettingsListSetting.java | 2 +- .../sse/common/settings/StringSetSetting.java | 10 +++ .../sse/common/settings/UUIDSetSetting.java | 12 +++ .../settings/ValueCollectionSetting.java | 5 ++ .../sse/common/settings/ValueListSetting.java | 5 -- .../settings/base/AbstractListSetting.java | 4 +- .../base/AbstractValueCollectionSetting.java | 78 +++++++++++++++++++ .../base/AbstractValueListSetting.java | 65 +--------------- .../base/AbstractValueSetSetting.java | 42 ++++++++++ .../AbstractSettingsToJsonSerializer.java | 24 +++--- .../SettingsToStringMapSerializer.java | 14 ++-- .../settings/SettingsToJsonSerializer.java | 1 - 13 files changed, 174 insertions(+), 90 deletions(-) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ListSetting.java => CollectionSetting.java} (68%) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueCollectionSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/CollectionSetting.java similarity index 68% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/CollectionSetting.java index 81de66af233..8a3ab82c555 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/CollectionSetting.java @@ -1,7 +1,7 @@ package com.sap.sse.common.settings; -public interface ListSetting extends Setting { +public interface CollectionSetting extends Setting { void setValues(Iterable values); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java index b94b1880959..d1b9ffadf3e 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java @@ -1,4 +1,4 @@ package com.sap.sse.common.settings; -public interface SettingsListSetting extends ListSetting, HasSettingsFactory { +public interface SettingsListSetting extends CollectionSetting, HasSettingsFactory { } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java new file mode 100644 index 00000000000..aa4a1c12806 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.settings; + +import com.sap.sse.common.settings.base.AbstractValueSetSetting; +import com.sap.sse.common.settings.converter.StringConverter; + +public class StringSetSetting extends AbstractValueSetSetting { + public StringSetSetting(String name, AbstractSettings settings) { + super(name, settings, StringConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java new file mode 100644 index 00000000000..05ed7aaea03 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java @@ -0,0 +1,12 @@ +package com.sap.sse.common.settings; + +import java.util.UUID; + +import com.sap.sse.common.settings.base.AbstractValueSetSetting; +import com.sap.sse.common.settings.converter.UUIDConverter; + +public class UUIDSetSetting extends AbstractValueSetSetting { + public UUIDSetSetting(String name, AbstractSettings settings) { + super(name, settings, UUIDConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueCollectionSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueCollectionSetting.java new file mode 100644 index 00000000000..ab192d42e2e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueCollectionSetting.java @@ -0,0 +1,5 @@ +package com.sap.sse.common.settings; + + +public interface ValueCollectionSetting extends HasValueSetting, CollectionSetting { +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java deleted file mode 100644 index 66c97eb4a34..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueListSetting.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.sap.sse.common.settings; - - -public interface ValueListSetting extends HasValueSetting, ListSetting { -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java index 382e5171506..d5bcbb94fe6 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java @@ -6,9 +6,9 @@ import java.util.List; import com.sap.sse.common.settings.AbstractSetting; import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.ListSetting; +import com.sap.sse.common.settings.CollectionSetting; -public abstract class AbstractListSetting extends AbstractSetting implements ListSetting { +public abstract class AbstractListSetting extends AbstractSetting implements CollectionSetting { private List values = new ArrayList<>(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java new file mode 100644 index 00000000000..66a680f432e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java @@ -0,0 +1,78 @@ +package com.sap.sse.common.settings.base; + +import java.util.Collection; +import java.util.Collections; + +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.ValueCollectionSetting; +import com.sap.sse.common.settings.ValueConverter; + +public abstract class AbstractValueCollectionSetting extends AbstractHasValueSetting implements ValueCollectionSetting { + + public AbstractValueCollectionSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + super(name, settings, valueConverter); + } + + protected abstract Collection getInnerCollection(); + + @Override + public boolean isDefaultValue() { + // explicit default values are possible to implement + // currently, empty is always default + return getInnerCollection().isEmpty(); + } + + @Override + public Iterable getValues() { + return Collections.unmodifiableCollection(getInnerCollection()); + } + + @Override + public final void setValues(Iterable values) { + this.getInnerCollection().clear(); + if(values != null) { + for(T value : values) { + this.getInnerCollection().add(value); + } + } + } + + public void addValue(T value) { + this.getInnerCollection().add(value); + } + + public void clear() { + this.getInnerCollection().clear(); + } + + @Override + public String toString() { + return getInnerCollection().toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((getInnerCollection() == null) ? 0 : getInnerCollection().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; + @SuppressWarnings("rawtypes") + AbstractValueCollectionSetting other = (AbstractValueCollectionSetting) obj; + if (getInnerCollection() == null) { + if (other.getInnerCollection() != null) + return false; + } else if (!getInnerCollection().equals(other.getInnerCollection())) + return false; + return true; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java index 21dadac852f..f25de63cdf8 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java @@ -1,14 +1,13 @@ package com.sap.sse.common.settings.base; import java.util.ArrayList; -import java.util.Collections; +import java.util.Collection; import java.util.List; import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.common.settings.ValueConverter; -import com.sap.sse.common.settings.ValueListSetting; -public abstract class AbstractValueListSetting extends AbstractHasValueSetting implements ValueListSetting { +public abstract class AbstractValueListSetting extends AbstractValueCollectionSetting { private List values = new ArrayList<>(); @@ -17,63 +16,7 @@ public abstract class AbstractValueListSetting extends AbstractHasValueSettin } @Override - public boolean isDefaultValue() { - // explicit default values are possible to implement - // currently, empty is always default - return values.isEmpty(); - } - - @Override - public Iterable getValues() { - return Collections.unmodifiableCollection(values); - } - - @Override - public void setValues(Iterable values) { - this.values.clear(); - if(values != null) { - for(T value : values) { - this.values.add(value); - } - } - } - - public void addValue(T value) { - this.values.add(value); - } - - public void clear() { - this.values.clear(); - } - - @Override - public String toString() { - return values.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((values == null) ? 0 : values.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; - @SuppressWarnings("rawtypes") - AbstractValueListSetting other = (AbstractValueListSetting) obj; - if (values == null) { - if (other.values != null) - return false; - } else if (!values.equals(other.values)) - return false; - return true; + protected Collection getInnerCollection() { + return values; } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java new file mode 100644 index 00000000000..d880cfaa18e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java @@ -0,0 +1,42 @@ +package com.sap.sse.common.settings.base; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.sap.sse.common.Util; +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.ValueConverter; + +public abstract class AbstractValueSetSetting extends AbstractValueCollectionSetting { + + private Set values = new HashSet<>(); + private Set defaultValues = new HashSet<>(); + + public AbstractValueSetSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + super(name, settings, valueConverter); + } + + public AbstractValueSetSetting(String name, AbstractSettings settings, Iterable defaultValues, ValueConverter valueConverter) { + this(name, settings, valueConverter); + setDefaultValues(defaultValues); + setValues(defaultValues); + } + + @Override + protected Collection getInnerCollection() { + return values; + } + + @Override + public boolean isDefaultValue() { + return values.size() == defaultValues.size() && values.containsAll(defaultValues); + } + + public final void setDefaultValues(Iterable defaultValues) { + this.defaultValues.clear(); + if(defaultValues != null) { + Util.addAll(defaultValues, this.defaultValues); + } + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java index dbcac6615a3..e4d83fe4f02 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java @@ -4,12 +4,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import com.sap.sse.common.settings.ListSetting; +import com.sap.sse.common.settings.CollectionSetting; import com.sap.sse.common.settings.Setting; import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.SettingsListSetting; +import com.sap.sse.common.settings.ValueCollectionSetting; import com.sap.sse.common.settings.ValueConverter; -import com.sap.sse.common.settings.ValueListSetting; import com.sap.sse.common.settings.ValueSetting; public abstract class AbstractSettingsToJsonSerializer { @@ -40,8 +40,8 @@ public abstract class AbstractSettingsToJsonSerializer { private Object serialize(Setting setting) { if (setting instanceof ValueSetting) { return serializeValueSetting((ValueSetting) setting); - } else if (setting instanceof ListSetting) { - return serializeListSetting((ListSetting) setting); + } else if (setting instanceof CollectionSetting) { + return serializeListSetting((CollectionSetting) setting); } else if (setting instanceof Settings) { return serialize((Settings) setting); } else { @@ -53,10 +53,10 @@ public abstract class AbstractSettingsToJsonSerializer { return valueSetting.getValueConverter().toJSONValue(valueSetting.getValue()); } - private Object serializeListSetting(ListSetting listSetting) { + private Object serializeListSetting(CollectionSetting listSetting) { List jsonValues = new ArrayList<>(); - if (listSetting instanceof ValueListSetting) { - ValueListSetting valueListSetting = (ValueListSetting) listSetting; + if (listSetting instanceof ValueCollectionSetting) { + ValueCollectionSetting valueListSetting = (ValueCollectionSetting) listSetting; ValueConverter converter = valueListSetting.getValueConverter(); for (T value : valueListSetting.getValues()) { jsonValues.add(converter.toJSONValue(value)); @@ -88,8 +88,8 @@ public abstract class AbstractSettingsToJsonSerializer { private void deserializeSetting(Setting setting, Object jsonValue) { if (setting instanceof ValueSetting) { deserializeValueSetting(jsonValue, (ValueSetting) setting); - } else if (setting instanceof ListSetting) { - deserializeListSetting(jsonValue, (ListSetting) setting); + } else if (setting instanceof CollectionSetting) { + deserializeListSetting(jsonValue, (CollectionSetting) setting); } else if (setting instanceof Settings) { deserializeObject((Settings) setting, jsonValue); } else { @@ -106,11 +106,11 @@ public abstract class AbstractSettingsToJsonSerializer { valueSetting.setValue(valueSetting.getValueConverter().fromJSONValue(jsonValue)); } - private void deserializeListSetting(Object jsonValue, ListSetting listSetting) { + private void deserializeListSetting(Object jsonValue, CollectionSetting listSetting) { @SuppressWarnings("unchecked") ARRAY jsonArray = (ARRAY) jsonValue; - if (listSetting instanceof ValueListSetting) { - ValueListSetting valueListSetting = (ValueListSetting) listSetting; + if (listSetting instanceof ValueCollectionSetting) { + ValueCollectionSetting valueListSetting = (ValueCollectionSetting) listSetting; ValueConverter converter = valueListSetting.getValueConverter(); List values = new ArrayList<>(); for (Object value : fromJsonArray(jsonArray)) { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java index 82cc97e3506..d07251ba2da 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java @@ -14,7 +14,7 @@ import com.sap.sse.common.settings.Setting; import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.SettingsListSetting; import com.sap.sse.common.settings.ValueConverter; -import com.sap.sse.common.settings.ValueListSetting; +import com.sap.sse.common.settings.ValueCollectionSetting; import com.sap.sse.common.settings.ValueSetting; public class SettingsToStringMapSerializer { @@ -38,8 +38,8 @@ public class SettingsToStringMapSerializer { private void serialize(String key, Setting setting, Map> serialized) { if (setting instanceof ValueSetting) { serialized.put(key, serializeValueSetting(key, (ValueSetting) setting)); - } else if (setting instanceof ValueListSetting) { - serialized.put(key, serializeValueListSetting(key, (ValueListSetting) setting)); + } else if (setting instanceof ValueCollectionSetting) { + serialized.put(key, serializeValueListSetting(key, (ValueCollectionSetting) setting)); } else { String prefix = key + Settings.PATH_SEPARATOR; if (setting instanceof Settings) { @@ -66,7 +66,7 @@ public class SettingsToStringMapSerializer { return Collections.singleton(valueSetting.getValueConverter().toStringValue(valueSetting.getValue())); } - private Iterable serializeValueListSetting(String key, ValueListSetting valueSetting) { + private Iterable serializeValueListSetting(String key, ValueCollectionSetting valueSetting) { List result = new ArrayList<>(); ValueConverter valueConverter = valueSetting.getValueConverter(); for (T value : valueSetting.getValues()) { @@ -92,8 +92,8 @@ public class SettingsToStringMapSerializer { if (settingValues != null) { if (setting instanceof ValueSetting) { deserializeValueSetting((ValueSetting) setting, settingValues); - } else if (setting instanceof ValueListSetting) { - deserializeValueListSetting((ValueListSetting) setting, settingValues); + } else if (setting instanceof ValueCollectionSetting) { + deserializeValueListSetting((ValueCollectionSetting) setting, settingValues); } else { throw new IllegalStateException("Unknown HasValueSetting type"); } @@ -122,7 +122,7 @@ public class SettingsToStringMapSerializer { } } - private void deserializeValueListSetting(ValueListSetting valueSetting, Iterable values) { + private void deserializeValueListSetting(ValueCollectionSetting valueSetting, Iterable values) { List deserializedValues = new ArrayList<>(); for (String stringValue : values) { deserializedValues.add(valueSetting.getValueConverter().fromStringValue(stringValue)); diff --git a/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java index 59d8f9b43af..52f78b17b2d 100644 --- a/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java +++ b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java @@ -4,7 +4,6 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; import com.sap.sse.common.settings.EnumSetting; -import com.sap.sse.common.settings.ListSetting; import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; From d4f7c328ab05be84f0c354c35d66cbf3ecfac125 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 09:43:08 +0100 Subject: [PATCH 025/259] bug 2775: Added constructors with default values to Set based settings --- .../src/com/sap/sse/common/settings/StringSetSetting.java | 4 ++++ .../src/com/sap/sse/common/settings/UUIDSetSetting.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java index aa4a1c12806..2fa0a472f5e 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java @@ -7,4 +7,8 @@ public class StringSetSetting extends AbstractValueSetSetting { public StringSetSetting(String name, AbstractSettings settings) { super(name, settings, StringConverter.INSTANCE); } + + public StringSetSetting(String name, AbstractSettings settings, Iterable defaultValues) { + super(name, settings, defaultValues, StringConverter.INSTANCE); + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java index 05ed7aaea03..3caceeb4eff 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java @@ -9,4 +9,8 @@ public class UUIDSetSetting extends AbstractValueSetSetting { public UUIDSetSetting(String name, AbstractSettings settings) { super(name, settings, UUIDConverter.INSTANCE); } + + public UUIDSetSetting(String name, AbstractSettings settings, Iterable defaultValues) { + super(name, settings, defaultValues, UUIDConverter.INSTANCE); + } } From be51da6647d7e481ef76bb2f01460edc6cf45d1f Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 09:44:24 +0100 Subject: [PATCH 026/259] bug 2775: Introduced resetToDefault for settings --- .../sap/sse/common/settings/AbstractSettings.java | 7 +++++++ .../src/com/sap/sse/common/settings/Setting.java | 2 ++ .../common/settings/base/AbstractListSetting.java | 10 ++++++++-- .../base/AbstractValueCollectionSetting.java | 7 ------- .../settings/base/AbstractValueListSetting.java | 14 +++++++++++++- .../settings/base/AbstractValueSetSetting.java | 11 ++++++++--- .../common/settings/base/AbstractValueSetting.java | 7 ++++++- 7 files changed, 44 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index 51a03279cab..7fa7ba06675 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -36,6 +36,13 @@ public abstract class AbstractSettings extends AbstractSetting implements Settin } return true; } + + @Override + public void resetToDefault() { + for (Setting setting : childSettings.values()) { + setting.resetToDefault(); + } + } @Override public Map getChildSettings() { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java index dc90ae57692..a95f280d0d1 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java @@ -13,4 +13,6 @@ package com.sap.sse.common.settings; */ public interface Setting { boolean isDefaultValue(); + + void resetToDefault(); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java index d5bcbb94fe6..e25d667fb9a 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java @@ -10,7 +10,7 @@ import com.sap.sse.common.settings.CollectionSetting; public abstract class AbstractListSetting extends AbstractSetting implements CollectionSetting { - private List values = new ArrayList<>(); + private final List values = new ArrayList<>(); public AbstractListSetting(String name, AbstractSettings settings) { super(name, settings); @@ -21,10 +21,16 @@ public abstract class AbstractListSetting extends AbstractSetting implements @Override public boolean isDefaultValue() { - // TODO implement + // explicit default values are possible to implement + // currently, empty is always default return values.isEmpty(); } + @Override + public void resetToDefault() { + this.values.clear(); + } + @Override public Iterable getValues() { return Collections.unmodifiableCollection(values); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java index 66a680f432e..33ff758fe1f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java @@ -15,13 +15,6 @@ public abstract class AbstractValueCollectionSetting extends AbstractHasValue protected abstract Collection getInnerCollection(); - @Override - public boolean isDefaultValue() { - // explicit default values are possible to implement - // currently, empty is always default - return getInnerCollection().isEmpty(); - } - @Override public Iterable getValues() { return Collections.unmodifiableCollection(getInnerCollection()); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java index f25de63cdf8..7e7e64d6c70 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java @@ -9,7 +9,7 @@ import com.sap.sse.common.settings.ValueConverter; public abstract class AbstractValueListSetting extends AbstractValueCollectionSetting { - private List values = new ArrayList<>(); + private final List values = new ArrayList<>(); public AbstractValueListSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { super(name, settings, valueConverter); @@ -19,4 +19,16 @@ public abstract class AbstractValueListSetting extends AbstractValueCollectio protected Collection getInnerCollection() { return values; } + + @Override + public void resetToDefault() { + values.clear(); + } + + @Override + public boolean isDefaultValue() { + // explicit default values are possible to implement + // currently, empty is always default + return getInnerCollection().isEmpty(); + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java index d880cfaa18e..00759d51a23 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java @@ -10,8 +10,8 @@ import com.sap.sse.common.settings.ValueConverter; public abstract class AbstractValueSetSetting extends AbstractValueCollectionSetting { - private Set values = new HashSet<>(); - private Set defaultValues = new HashSet<>(); + private final Set values = new HashSet<>(); + private final Set defaultValues = new HashSet<>(); public AbstractValueSetSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { super(name, settings, valueConverter); @@ -20,7 +20,7 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection public AbstractValueSetSetting(String name, AbstractSettings settings, Iterable defaultValues, ValueConverter valueConverter) { this(name, settings, valueConverter); setDefaultValues(defaultValues); - setValues(defaultValues); + resetToDefault(); } @Override @@ -33,6 +33,11 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection return values.size() == defaultValues.size() && values.containsAll(defaultValues); } + @Override + public void resetToDefault() { + setValues(defaultValues); + } + public final void setDefaultValues(Iterable defaultValues) { this.defaultValues.clear(); if(defaultValues != null) { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java index 1f998214be3..4312a9cf131 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java @@ -4,7 +4,7 @@ import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.common.settings.ValueConverter; import com.sap.sse.common.settings.ValueSetting; -public class AbstractValueSetting extends AbstractHasValueSetting implements ValueSetting { +public abstract class AbstractValueSetting extends AbstractHasValueSetting implements ValueSetting { private T defaultValue; @@ -38,6 +38,11 @@ public class AbstractValueSetting extends AbstractHasValueSetting implemen return false; } + @Override + public void resetToDefault() { + this.value = defaultValue; + } + @Override public String toString() { return "" + value; From b3e91fdf559c888c31790e9f51ec1e6ca457d82e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 09:44:39 +0100 Subject: [PATCH 027/259] Removed unused import --- .../gwt/regattaoverview/client/RegattaOverviewEntryPoint.java | 1 - 1 file changed, 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index 480627de902..fb277dc28ea 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -3,7 +3,6 @@ package com.sap.sailing.gwt.regattaoverview.client; import java.util.Collections; import java.util.UUID; -import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; From 9b38a2be707407e1adcc218906b0729d112ca346 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 09:50:33 +0100 Subject: [PATCH 028/259] bug 2775: Introduced interface ValueSetSetting --- .../src/com/sap/sse/common/settings/ValueSetSetting.java | 5 +++++ .../sse/common/settings/base/AbstractValueSetSetting.java | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetSetting.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetSetting.java new file mode 100644 index 00000000000..fe81decbcd7 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetSetting.java @@ -0,0 +1,5 @@ +package com.sap.sse.common.settings; + +public interface ValueSetSetting extends ValueCollectionSetting { + void setDefaultValues(Iterable defaultValues); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java index 00759d51a23..295ec2893a8 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java @@ -7,8 +7,9 @@ import java.util.Set; import com.sap.sse.common.Util; import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.ValueSetSetting; -public abstract class AbstractValueSetSetting extends AbstractValueCollectionSetting { +public abstract class AbstractValueSetSetting extends AbstractValueCollectionSetting implements ValueSetSetting { private final Set values = new HashSet<>(); private final Set defaultValues = new HashSet<>(); @@ -38,6 +39,7 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection setValues(defaultValues); } + @Override public final void setDefaultValues(Iterable defaultValues) { this.defaultValues.clear(); if(defaultValues != null) { From 47df05d792f0f98c0a8e95fe31e5d055594bc276 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 10:05:36 +0100 Subject: [PATCH 029/259] bug 2775: Implemented conversion from/to json string to SettingsToJsonSerializerGWT --- .../settings/SettingsToJsonSerializerGWT.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java index 751631a4597..305324b08e8 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java @@ -6,8 +6,10 @@ import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONBoolean; import com.google.gwt.json.client.JSONNumber; import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; +import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; /** @@ -16,6 +18,24 @@ import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; * */ public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerializer { + + public String serializeToString(Settings settings) { + return serialize(settings).toString(); + } + + public T deserialize(T settings, String jsonString) { + if (jsonString != null && !jsonString.isEmpty()) { + JSONValue jsonValue = JSONParser.parseStrict(jsonString); + if (jsonValue != null) { + JSONObject jsonObject = jsonValue.isObject(); + if (jsonObject != null) { + deserialize(settings, (JSONObject) jsonObject); + } + } + } + return settings; + } + @Override protected JSONObject newOBJECT() { return new JSONObject(); From 4b8babdea8d4e07cd208b712a37ec0a7bbab9a24 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 10:38:50 +0100 Subject: [PATCH 030/259] bug 2775: Fixed several serialization problems in SettingsToJsonSerializerGWT --- .../settings/SettingsToJsonSerializerGWT.java | 70 +++++++++++-------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java index 305324b08e8..3596f8aecc1 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONBoolean; +import com.google.gwt.json.client.JSONNull; import com.google.gwt.json.client.JSONNumber; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; @@ -43,15 +44,44 @@ public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerialize @Override protected void set(JSONObject jsonObject, String property, Object value) { - - if (value instanceof String) { - jsonObject.put(property, new JSONString((String) value)); + jsonObject.put(property, toJsonValue(value)); + } + + private JSONValue toJsonValue(Object value) { + if(value == null) { + return JSONNull.getInstance(); + } else if (value instanceof JSONArray) { + return (JSONArray) value; + } else if (value instanceof String) { + return new JSONString((String) value); } else if (value instanceof Number) { - jsonObject.put(property, new JSONNumber(((Number) value).doubleValue())); + return new JSONNumber(((Number) value).doubleValue()); } else if (value instanceof Boolean) { - jsonObject.put(property, JSONBoolean.getInstance((Boolean) value)); + return JSONBoolean.getInstance((Boolean) value); } - + throw new IllegalStateException("Non JSON-compatible value found!"); + } + + private Object fromJsonValue(JSONValue jsonValue) { + if(jsonValue.isNull() != null) { + return null; + } + if(jsonValue.isBoolean() != null) { + return jsonValue.isBoolean().booleanValue(); + } + if(jsonValue.isString() != null) { + return jsonValue.isString().stringValue(); + } + if(jsonValue.isNumber() != null) { + return jsonValue.isNumber().doubleValue(); + } + if(jsonValue.isObject() != null) { + return jsonValue.isObject(); + } + if(jsonValue.isArray() != null) { + return jsonValue.isArray(); + } + throw new IllegalStateException("Unexpected JSONValue found!"); } @Override @@ -68,14 +98,7 @@ public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerialize protected JSONArray ToJsonArray(Iterable values) { JSONArray jsonArray = new JSONArray(); for (Object value : values) { - JSONValue jsonValue = null; - if (value instanceof String) { - jsonValue = new JSONString((String) value); - } else if (value instanceof Number) { - jsonValue = new JSONNumber(((Number) value).doubleValue()); - } else if (value instanceof Boolean) { - jsonValue = JSONBoolean.getInstance((Boolean) value); - } + JSONValue jsonValue = toJsonValue(value); if (jsonValue != null) { jsonArray.set(jsonArray.size(), jsonValue); } @@ -86,23 +109,8 @@ public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerialize @Override protected Iterable fromJsonArray(JSONArray jsonArray) { final ArrayList result = new ArrayList(jsonArray.size()); - toLoop: for (int i = 0; i < jsonArray.size(); i++) { - JSONValue jsonValue = jsonArray.get(i); - JSONString jS; - if ((jS = jsonValue.isString()) != null) { - result.add(jS.stringValue()); - continue toLoop; - } - JSONBoolean jB; - if ((jB = jsonValue.isBoolean()) != null) { - result.add(jB.booleanValue()); - continue toLoop; - } - JSONNumber jN; - if ((jN = jsonValue.isNumber()) != null) { - result.add(jN.doubleValue()); - continue toLoop; - } + for (int i = 0; i < jsonArray.size(); i++) { + result.add(fromJsonValue(jsonArray.get(i))); } return result; } From b43efa11e216d9d3746f8d226a741ef76d8cce23 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 10:38:58 +0100 Subject: [PATCH 031/259] bug 2775: Using SettingsToJsonSerializerGWT to (de)serialize json for RegattaOverview --- .../client/RegattaRaceStatesComponent.java | 21 ++---- ...ttaRaceStatesSettingsJsonDeSerializer.java | 69 ------------------- 2 files changed, 7 insertions(+), 83 deletions(-) delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index b599103009b..97f1e88d965 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -19,9 +19,6 @@ import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat; import com.google.gwt.i18n.client.NumberFormat; -import com.google.gwt.json.client.JSONObject; -import com.google.gwt.json.client.JSONParser; -import com.google.gwt.json.client.JSONValue; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.storage.client.Storage; @@ -54,7 +51,6 @@ import com.sap.sailing.domain.common.dto.FleetDTO; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.gwt.ui.client.AnchorCell; import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory; -import com.sap.sailing.gwt.ui.client.GwtJsonDeSerializer; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.ClickableSafeHtmlCell; @@ -74,6 +70,7 @@ import com.sap.sse.gwt.client.celltable.BaseCelltable; import com.sap.sse.gwt.client.player.Timer; import com.sap.sse.gwt.client.shared.components.Component; import com.sap.sse.gwt.client.shared.components.SettingsDialogComponent; +import com.sap.sse.gwt.settings.SettingsToJsonSerializerGWT; /** * This component shows a table displaying the current state of races for a given event. Which races are shown depends @@ -844,29 +841,25 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } private void storeRegattaRaceStatesSettings(RegattaRaceStatesSettings settings) { + GWT.debugger(); Storage localStorage = Storage.getLocalStorageIfSupported(); if (localStorage != null && eventId != null) { // delete old value localStorage.removeItem(localStorageRegattaOverviewEventKey); // store settings - GwtJsonDeSerializer serializer = new RegattaRaceStatesSettingsJsonDeSerializer(); - JSONObject settingsAsJson = serializer.serialize(settings); - localStorage.setItem(localStorageRegattaOverviewEventKey, settingsAsJson.toString()); + localStorage.setItem(localStorageRegattaOverviewEventKey, + new SettingsToJsonSerializerGWT().serializeToString(settings)); } } private RegattaRaceStatesSettings loadRegattaRaceStatesSettings() { + GWT.debugger(); RegattaRaceStatesSettings loadedSettings = null; Storage localStorage = Storage.getLocalStorageIfSupported(); if (localStorage != null) { String jsonAsLocalStore = localStorage.getItem(localStorageRegattaOverviewEventKey); - if (jsonAsLocalStore != null && !jsonAsLocalStore.isEmpty()) { - GwtJsonDeSerializer deserializer = new RegattaRaceStatesSettingsJsonDeSerializer(); - JSONValue value = JSONParser.parseStrict(jsonAsLocalStore); - if (value.isObject() != null) { - loadedSettings = deserializer.deserialize((JSONObject) value); - } - } + loadedSettings = new SettingsToJsonSerializerGWT().deserialize(new RegattaRaceStatesSettings(), + jsonAsLocalStore); } return loadedSettings; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java deleted file mode 100644 index faf5947fabe..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsJsonDeSerializer.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.sap.sailing.gwt.regattaoverview.client; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import com.google.gwt.json.client.JSONArray; -import com.google.gwt.json.client.JSONBoolean; -import com.google.gwt.json.client.JSONObject; -import com.google.gwt.json.client.JSONString; -import com.sap.sailing.gwt.ui.client.GwtJsonDeSerializer; -import com.sap.sse.common.Util; - -public class RegattaRaceStatesSettingsJsonDeSerializer implements GwtJsonDeSerializer { - - private static final String FIELD_VISIBLE_COURSE_AREAS = "visibleCourseAreas"; - private static final String FIELD_VISIBLE_REGATTAS = "visibleRegattas"; - private static final String FIELD_SHOW_ONLY_CURRENTLY_RUNNING_RACES = "showOnlyCurrentlyRunningRaces"; - private static final String FIELD_SHOW_ONLY_RACES_OF_SAME_DAY = "showOnlyRacesOfSameDay"; - - @Override - public JSONObject serialize(RegattaRaceStatesSettings settings) { - JSONObject result = new JSONObject(); - result.put(FIELD_SHOW_ONLY_CURRENTLY_RUNNING_RACES, JSONBoolean.getInstance(settings.isShowOnlyCurrentlyRunningRaces())); - result.put(FIELD_SHOW_ONLY_RACES_OF_SAME_DAY, JSONBoolean.getInstance(settings.isShowOnlyRacesOfSameDay())); - - JSONArray visibleCourseAreas = new JSONArray(); - for (int i = 0; i < Util.size(settings.getVisibleCourseAreas()); i++) { - visibleCourseAreas.set(i, new JSONString(Util.get(settings.getVisibleCourseAreas(), i).toString())); - } - result.put(FIELD_VISIBLE_COURSE_AREAS, visibleCourseAreas); - - JSONArray visibleRegattas = new JSONArray(); - for (int i = 0; i < Util.size(settings.getVisibleRegattas()); i++) { - visibleRegattas.set(i, new JSONString(Util.get(settings.getVisibleRegattas(), i))); - } - result.put(FIELD_VISIBLE_REGATTAS, visibleRegattas); - - return result; - } - - @Override - public RegattaRaceStatesSettings deserialize(JSONObject object) { - if (object == null) { - return null; - } - - JSONBoolean showOnlyCurrentlyRunningRaces = (JSONBoolean) object.get(FIELD_SHOW_ONLY_CURRENTLY_RUNNING_RACES); - JSONBoolean showOnlyRacesOfSameDay = (JSONBoolean) object.get(FIELD_SHOW_ONLY_RACES_OF_SAME_DAY); - - JSONArray jsonVisibleCourseAreas = (JSONArray) object.get(FIELD_VISIBLE_COURSE_AREAS); - List visibleCourseAreas = new ArrayList(); - for (int i = 0 ; i < jsonVisibleCourseAreas.size() ; i++) { - JSONString jsonCourseArea = (JSONString) jsonVisibleCourseAreas.get(i); - visibleCourseAreas.add(UUID.fromString(jsonCourseArea.stringValue())); - } - - JSONArray jsonVisibleRegattas = (JSONArray) object.get(FIELD_VISIBLE_REGATTAS); - List visibleRegattas = new ArrayList(); - for (int i = 0 ; i < jsonVisibleRegattas.size() ; i++) { - JSONString jsonRegatta = (JSONString) jsonVisibleRegattas.get(i); - visibleRegattas.add(jsonRegatta.stringValue()); - } - - return new RegattaRaceStatesSettings(visibleCourseAreas, visibleRegattas, - showOnlyRacesOfSameDay.booleanValue(), showOnlyCurrentlyRunningRaces.booleanValue()); - } - -} From c7aeca2466ebc0dcbb540c0a2a6449d6caaa93b6 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Wed, 16 Mar 2016 10:44:54 +0100 Subject: [PATCH 032/259] Exposing setting instances for direct access --- .../client/RegattaRaceStatesComponent.java | 4 +- .../client/RegattaRaceStatesSettings.java | 38 ++++++++----------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index b599103009b..03d00dc9b4b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -774,7 +774,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private void fillVisibleRegattasInSettingsIfEmpty() { if (Util.isEmpty(settings.getVisibleRegattas()) && raceGroupDTOs != null) { for (RaceGroupDTO raceGroup : raceGroupDTOs) { - settings.addVisibleRegatta(raceGroup.getName()); + settings.getVisibleRegattaSettings().addValue(raceGroup.getName()); } } } @@ -782,7 +782,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component private void fillVisibleCourseAreasInSettingsIfEmpty() { if (Util.isEmpty(settings.getVisibleCourseAreas()) && eventDTO != null) { for (CourseAreaDTO courseArea : eventDTO.venue.getCourseAreas()) { - settings.addVisibleCourseArea(courseArea.id); + settings.getVisibleCourseAreaSettings().addValue(courseArea.id); } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java index 70640f9d349..b4f75818653 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java @@ -4,15 +4,15 @@ import java.util.UUID; import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.common.settings.BooleanSetting; -import com.sap.sse.common.settings.StringListSetting; -import com.sap.sse.common.settings.UUIDListSetting; +import com.sap.sse.common.settings.StringSetSetting; +import com.sap.sse.common.settings.UUIDSetSetting; -public class RegattaRaceStatesSettings extends AbstractSettings { - private UUIDListSetting visibleCourseAreas = new UUIDListSetting("visibleCourseAreas", this); - private StringListSetting visibleRegattas = new StringListSetting("visibleRegattas", this); - private BooleanSetting showOnlyRacesOfSameDay = new BooleanSetting("showOnlyRacesOfSameDay", this, false); - private BooleanSetting showOnlyCurrentlyRunningRaces = new BooleanSetting("showOnlyCurrentlyRunningRaces", this, - true); +public final class RegattaRaceStatesSettings extends AbstractSettings { + private final UUIDSetSetting visibleCourseAreas = new UUIDSetSetting("visibleCourseAreas", this); + private final StringSetSetting visibleRegattas = new StringSetSetting("visibleRegattas", this); + private final BooleanSetting showOnlyRacesOfSameDay = new BooleanSetting("showOnlyRacesOfSameDay", this, false); + private final BooleanSetting showOnlyCurrentlyRunningRaces = new BooleanSetting("showOnlyCurrentlyRunningRaces", + this, true); public RegattaRaceStatesSettings() { } @@ -28,33 +28,25 @@ public class RegattaRaceStatesSettings extends AbstractSettings { public Iterable getVisibleCourseAreas() { return visibleCourseAreas.getValues(); } - - public Iterable getVisibleRegattas() { - return visibleRegattas.getValues(); - } public void setVisibleCourseAreas(Iterable visibleCourseAreas) { this.visibleCourseAreas.setValues(visibleCourseAreas); } - - public void addVisibleCourseArea(UUID value) { - visibleCourseAreas.addValue(value); + + public UUIDSetSetting getVisibleCourseAreaSettings() { + return visibleCourseAreas; } - public void clearVisibleCourseAreas() { - visibleCourseAreas.clear(); + public Iterable getVisibleRegattas() { + return visibleRegattas.getValues(); } public void setVisibleRegattas(Iterable visibleRegattas) { this.visibleRegattas.setValues(visibleRegattas); } - public void addVisibleRegatta(String value) { - visibleRegattas.addValue(value); - } - - public void clearVisibleRegattas() { - visibleRegattas.clear(); + public StringSetSetting getVisibleRegattaSettings() { + return visibleRegattas; } public boolean isShowOnlyRacesOfSameDay() { From 8378cb0b82dc8a1369bcb1eab3d6c37df8231394 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 11:07:27 +0100 Subject: [PATCH 033/259] bug 2775: Fixed serialization problem in SettingsToJsonSerializerGWT --- .../com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java index 3596f8aecc1..5c4d2905aaf 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java @@ -86,7 +86,7 @@ public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerialize @Override protected Object get(JSONObject jsonObject, String property) { - return jsonObject.get(property); + return fromJsonValue(jsonObject.get(property)); } @Override From af84cadaef8425fd5615ca0e16a5e15cc804cf23 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 13:04:53 +0100 Subject: [PATCH 034/259] Removed unintentially committed GWT.debugger() calls --- .../gwt/regattaoverview/client/RegattaRaceStatesComponent.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 281fe7c328a..8e7de9beef9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -841,7 +841,6 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } private void storeRegattaRaceStatesSettings(RegattaRaceStatesSettings settings) { - GWT.debugger(); Storage localStorage = Storage.getLocalStorageIfSupported(); if (localStorage != null && eventId != null) { // delete old value @@ -853,7 +852,6 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } private RegattaRaceStatesSettings loadRegattaRaceStatesSettings() { - GWT.debugger(); RegattaRaceStatesSettings loadedSettings = null; Storage localStorage = Storage.getLocalStorageIfSupported(); if (localStorage != null) { From 5f5e599827b402ff9d898e910ff7f9be2d79c127 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 13:06:52 +0100 Subject: [PATCH 035/259] bug 2775: Set settings are now bound to the default value if it had the default value before --- .../sap/sse/common/settings/base/AbstractValueSetSetting.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java index 295ec2893a8..355cf77a8c8 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java @@ -41,9 +41,13 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection @Override public final void setDefaultValues(Iterable defaultValues) { + boolean wasDefault = isDefaultValue(); this.defaultValues.clear(); if(defaultValues != null) { Util.addAll(defaultValues, this.defaultValues); } + if(wasDefault) { + resetToDefault(); + } } } From d1ec0606b85f0c6478de8a1f6cd9ec539972e3cb Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 13:45:59 +0100 Subject: [PATCH 036/259] bug 2775: Set settings can now optionally be set to interpret empty values as being default --- .../sse/common/settings/StringSetSetting.java | 8 +++++++ .../sse/common/settings/UUIDSetSetting.java | 8 +++++++ .../base/AbstractValueSetSetting.java | 24 +++++++++++++++++-- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java index 2fa0a472f5e..0f229fa66c9 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java @@ -7,8 +7,16 @@ public class StringSetSetting extends AbstractValueSetSetting { public StringSetSetting(String name, AbstractSettings settings) { super(name, settings, StringConverter.INSTANCE); } + + public StringSetSetting(String name, AbstractSettings settings, boolean emptyIsDefault) { + super(name, settings, emptyIsDefault, StringConverter.INSTANCE); + } public StringSetSetting(String name, AbstractSettings settings, Iterable defaultValues) { super(name, settings, defaultValues, StringConverter.INSTANCE); } + + public StringSetSetting(String name, AbstractSettings settings, Iterable defaultValues, boolean emptyIsDefault) { + super(name, settings, defaultValues, emptyIsDefault, StringConverter.INSTANCE); + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java index 3caceeb4eff..c2d759bf21c 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java @@ -9,8 +9,16 @@ public class UUIDSetSetting extends AbstractValueSetSetting { public UUIDSetSetting(String name, AbstractSettings settings) { super(name, settings, UUIDConverter.INSTANCE); } + + public UUIDSetSetting(String name, AbstractSettings settings, boolean emptyIsDefault) { + super(name, settings, emptyIsDefault, UUIDConverter.INSTANCE); + } public UUIDSetSetting(String name, AbstractSettings settings, Iterable defaultValues) { super(name, settings, defaultValues, UUIDConverter.INSTANCE); } + + public UUIDSetSetting(String name, AbstractSettings settings, Iterable defaultValues, boolean emptyIsDefault) { + super(name, settings, defaultValues, emptyIsDefault, UUIDConverter.INSTANCE); + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java index 355cf77a8c8..c1d4c661d60 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java @@ -1,6 +1,7 @@ package com.sap.sse.common.settings.base; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -13,13 +14,23 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection private final Set values = new HashSet<>(); private final Set defaultValues = new HashSet<>(); + private final boolean emptyIsDefault; public AbstractValueSetSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + this(name, settings, false, valueConverter); + } + + public AbstractValueSetSetting(String name, AbstractSettings settings, boolean emptyIsDefault, ValueConverter valueConverter) { super(name, settings, valueConverter); + this.emptyIsDefault = emptyIsDefault; } public AbstractValueSetSetting(String name, AbstractSettings settings, Iterable defaultValues, ValueConverter valueConverter) { - this(name, settings, valueConverter); + this(name, settings, defaultValues, false, valueConverter); + } + + public AbstractValueSetSetting(String name, AbstractSettings settings, Iterable defaultValues, boolean emptyIsDefault, ValueConverter valueConverter) { + this(name, settings, emptyIsDefault, valueConverter); setDefaultValues(defaultValues); resetToDefault(); } @@ -31,7 +42,16 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection @Override public boolean isDefaultValue() { - return values.size() == defaultValues.size() && values.containsAll(defaultValues); + return (emptyIsDefault && values.isEmpty()) + || (values.size() == defaultValues.size() && values.containsAll(defaultValues)); + } + + @Override + public Iterable getValues() { + if(emptyIsDefault && values.isEmpty()) { + return Collections.unmodifiableCollection(defaultValues); + } + return super.getValues(); } @Override From b78877543d5a0192b83f6858ad44ba9223e5d79e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 13:46:58 +0100 Subject: [PATCH 037/259] bug 2775: SettingsToUrlSerializer can't serialize empty values because the underlying UrlBuilder can't do this either --- .../src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java index 41f8c649326..75850b33588 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java @@ -51,7 +51,9 @@ public class SettingsToUrlSerializer { for(Map.Entry> entry : serializedValues.entrySet()) { Iterable parameterValues = entry.getValue(); String[] parameterValuesAsArray = Util.toArray(parameterValues, new String[Util.size(parameterValues)]); - urlBuilder.setParameter(entry.getKey(), parameterValuesAsArray); + if (parameterValuesAsArray.length > 0) { + urlBuilder.setParameter(entry.getKey(), parameterValuesAsArray); + } } } From 457e285f09ec123f4324fa5dc9fc8217b5fed656 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 13:49:18 +0100 Subject: [PATCH 038/259] bug 2775: Simplified RegattaOverview settings handling by adapting default value mechanism --- .../client/RegattaOverviewEntryPoint.java | 12 +---- .../client/RegattaRaceStatesComponent.java | 47 ++++++------------- .../client/RegattaRaceStatesSettings.java | 42 +++++++++++++++-- ...attaRaceStatesSettingsDialogComponent.java | 3 +- 4 files changed, 56 insertions(+), 48 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index fb277dc28ea..25565fbd849 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -1,6 +1,5 @@ package com.sap.sailing.gwt.regattaoverview.client; -import java.util.Collections; import java.util.UUID; import com.google.gwt.dom.client.Style.Unit; @@ -136,16 +135,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings, boolean isSetVisibleCourseAreasInUrl, boolean isSetVisibleRegattasInUrl) { - RegattaRaceStatesSettings copiedSettings = new RegattaRaceStatesSettings(settings.getVisibleCourseAreas(), - settings.getVisibleRegattas(), settings.isShowOnlyRacesOfSameDay(), - settings.isShowOnlyCurrentlyRunningRaces()); - if (!isSetVisibleCourseAreasInUrl) { - copiedSettings.setVisibleCourseAreas(Collections. emptyList()); - } - if (!isSetVisibleRegattasInUrl) { - copiedSettings.setVisibleRegattas(Collections. emptyList()); - } - return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(copiedSettings) + return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(settings) .setParameter(PARAM_IGNORE_LOCAL_SETTINGS, "true").setParameter(PARAM_EVENT, eventId.toString()) .buildString(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 8e7de9beef9..4c374365152 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -54,7 +54,6 @@ import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.ClickableSafeHtmlCell; -import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.RaceCourseDTO; import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; @@ -742,22 +741,12 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component @Override public void updateSettings(RegattaRaceStatesSettings newSettings) { - if (Util.isEmpty(settings.getVisibleCourseAreas()) - || !settings.getVisibleCourseAreas().equals(newSettings.getVisibleCourseAreas())) { - settings.setVisibleCourseAreas(newSettings.getVisibleCourseAreas()); - fillVisibleCourseAreasInSettingsIfEmpty(); - } - if (Util.isEmpty(settings.getVisibleRegattas()) - || !settings.getVisibleRegattas().equals(newSettings.getVisibleRegattas())) { - settings.setVisibleRegattas(newSettings.getVisibleRegattas()); - fillVisibleRegattasInSettingsIfEmpty(); - } - if (settings.isShowOnlyRacesOfSameDay() != newSettings.isShowOnlyRacesOfSameDay()) { - settings.setShowOnlyRaceOfSameDay(newSettings.isShowOnlyRacesOfSameDay()); - } - if (settings.isShowOnlyCurrentlyRunningRaces() != newSettings.isShowOnlyCurrentlyRunningRaces()) { - settings.setShowOnlyCurrentlyRunningRaces(newSettings.isShowOnlyCurrentlyRunningRaces()); - } + setDefaultCourseAreas(); + settings.setVisibleCourseAreas(newSettings.getVisibleCourseAreas()); + setDefaultRegattas(); + settings.setVisibleRegattas(newSettings.getVisibleRegattas()); + settings.setShowOnlyRaceOfSameDay(newSettings.isShowOnlyRacesOfSameDay()); + settings.setShowOnlyCurrentlyRunningRaces(newSettings.isShowOnlyCurrentlyRunningRaces()); refreshTableWithNewSettings(); storeRegattaRaceStatesSettings(settings); } @@ -768,19 +757,13 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component } } - private void fillVisibleRegattasInSettingsIfEmpty() { - if (Util.isEmpty(settings.getVisibleRegattas()) && raceGroupDTOs != null) { - for (RaceGroupDTO raceGroup : raceGroupDTOs) { - settings.getVisibleRegattaSettings().addValue(raceGroup.getName()); - } - } + private void setDefaultRegattas() { + settings.setDefaultRegattas(raceGroupDTOs); } - private void fillVisibleCourseAreasInSettingsIfEmpty() { - if (Util.isEmpty(settings.getVisibleCourseAreas()) && eventDTO != null) { - for (CourseAreaDTO courseArea : eventDTO.venue.getCourseAreas()) { - settings.getVisibleCourseAreaSettings().addValue(courseArea.id); - } + private void setDefaultCourseAreas() { + if(eventDTO != null) { + settings.setDefaultCourseAreas(eventDTO.venue.getCourseAreas()); } } @@ -797,7 +780,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component @Override public void onEventUpdated(EventDTO event) { eventDTO = event; - fillVisibleCourseAreasInSettingsIfEmpty(); + setDefaultCourseAreas(); refreshTableWithNewSettings(); } @@ -836,7 +819,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component // } // } // regattaOverviewTable.redraw(); - fillVisibleRegattasInSettingsIfEmpty(); + setDefaultRegattas(); refreshTableWithNewSettings(); } @@ -856,8 +839,8 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component Storage localStorage = Storage.getLocalStorageIfSupported(); if (localStorage != null) { String jsonAsLocalStore = localStorage.getItem(localStorageRegattaOverviewEventKey); - loadedSettings = new SettingsToJsonSerializerGWT().deserialize(new RegattaRaceStatesSettings(), - jsonAsLocalStore); + loadedSettings = new SettingsToJsonSerializerGWT().deserialize(new RegattaRaceStatesSettings( + eventDTO == null ? null : eventDTO.venue.getCourseAreas(), raceGroupDTOs), jsonAsLocalStore); } return loadedSettings; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java index b4f75818653..ba02c995b7c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java @@ -1,24 +1,36 @@ package com.sap.sailing.gwt.regattaoverview.client; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; +import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; +import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.common.settings.BooleanSetting; import com.sap.sse.common.settings.StringSetSetting; import com.sap.sse.common.settings.UUIDSetSetting; public final class RegattaRaceStatesSettings extends AbstractSettings { - private final UUIDSetSetting visibleCourseAreas = new UUIDSetSetting("visibleCourseAreas", this); - private final StringSetSetting visibleRegattas = new StringSetSetting("visibleRegattas", this); + private final UUIDSetSetting visibleCourseAreas = new UUIDSetSetting("visibleCourseAreas", this, true); + private final StringSetSetting visibleRegattas = new StringSetSetting("visibleRegattas", this, true); private final BooleanSetting showOnlyRacesOfSameDay = new BooleanSetting("showOnlyRacesOfSameDay", this, false); private final BooleanSetting showOnlyCurrentlyRunningRaces = new BooleanSetting("showOnlyCurrentlyRunningRaces", this, true); public RegattaRaceStatesSettings() { } + + public RegattaRaceStatesSettings(Iterable defaultCourseAreas, Iterable defaultRaceGroups) { + setDefaultCourseAreas(defaultCourseAreas); + setDefaultRegattas(defaultRaceGroups); + } - public RegattaRaceStatesSettings(Iterable visibleCourseAreas, Iterable visibleRegattas, - boolean showOnlyRacesOfSameDay, boolean showOnlyCurrentlyRunningRaces) { + public RegattaRaceStatesSettings(Iterable defaultCourseAreas, Iterable visibleCourseAreas, + Iterable defaultRaceGroups, Iterable visibleRegattas, boolean showOnlyRacesOfSameDay, + boolean showOnlyCurrentlyRunningRaces) { + this(defaultCourseAreas, defaultRaceGroups); this.visibleCourseAreas.setValues(visibleCourseAreas); this.visibleRegattas.setValues(visibleRegattas); this.showOnlyRacesOfSameDay.setValue(showOnlyRacesOfSameDay); @@ -64,5 +76,27 @@ public final class RegattaRaceStatesSettings extends AbstractSettings { public void setShowOnlyCurrentlyRunningRaces(boolean newValue) { showOnlyCurrentlyRunningRaces.setValue(newValue); } + + public void setDefaultCourseAreas(Iterable defaultCourseAreas) { + if(defaultCourseAreas == null) { + defaultCourseAreas = Collections.emptySet(); + } + Set courseAreaIds = new HashSet<>(); + for (CourseAreaDTO courseArea : defaultCourseAreas) { + courseAreaIds.add(courseArea.id); + } + visibleCourseAreas.setDefaultValues(courseAreaIds); + } + + public void setDefaultRegattas(Iterable defaultRaceGroups) { + if(defaultRaceGroups == null) { + defaultRaceGroups = Collections.emptySet(); + } + Set regattaIds = new HashSet<>(); + for (RaceGroupDTO raceGroup : defaultRaceGroups) { + regattaIds.add(raceGroup.getName()); + } + visibleRegattas.setDefaultValues(regattaIds); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java index 244ac38b82b..7f2e83da083 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java @@ -240,7 +240,8 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC boolean isShowOnlyRacesOfSameDay = showOnlyRacesOfSameDayCheckBox.getValue(); boolean isShowOnlyCurrentlyRunningRaces = showOnlyCurrentlyRunningRacesCheckBox.getValue(); - return new RegattaRaceStatesSettings(selectedCourseAreas, selectedRegattas, isShowOnlyRacesOfSameDay, isShowOnlyCurrentlyRunningRaces); + return new RegattaRaceStatesSettings(this.courseAreas, selectedCourseAreas, this.raceGroups, selectedRegattas, + isShowOnlyRacesOfSameDay, isShowOnlyCurrentlyRunningRaces); } @Override From 4e0b5686a87da9162c773a383a22752cdf4f836c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 14:21:51 +0100 Subject: [PATCH 039/259] bug 2775: Cleanup of unused code --- .../client/RegattaOverviewEntryPoint.java | 3 +-- .../RegattaRaceStatesSettingsDialogComponent.java | 10 +--------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index 25565fbd849..326544442c9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -133,8 +133,7 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { return new SettingsToUrlSerializer().deserializeFromCurrentLocation(new RegattaRaceStatesSettings()); } - public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings, boolean isSetVisibleCourseAreasInUrl, - boolean isSetVisibleRegattasInUrl) { + public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings) { return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(settings) .setParameter(PARAM_IGNORE_LOCAL_SETTINGS, "true").setParameter(PARAM_EVENT, eventId.toString()) .buildString(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java index 7f2e83da083..bdb01ef48e0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java @@ -264,15 +264,7 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC } private void updateLinkUrl(UUID eventId, RegattaRaceStatesSettings settings) { - boolean isSetVisibleCourseAreasInUrl = true; - boolean isSetVisibleRegattasInUrl = true; - if (Util.size(settings.getVisibleCourseAreas()) == courseAreas.size()) { - isSetVisibleCourseAreasInUrl = false; - } - if (Util.size(settings.getVisibleRegattas()) == raceGroups.size()) { - isSetVisibleRegattasInUrl = false; - } - resultingLink.setHref(RegattaOverviewEntryPoint.getUrl(eventId, settings, isSetVisibleCourseAreasInUrl, isSetVisibleRegattasInUrl)); + resultingLink.setHref(RegattaOverviewEntryPoint.getUrl(eventId, settings)); } } From fefd4895056ec2fd137010442d68decb10b5b7ee Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 15:32:52 +0100 Subject: [PATCH 040/259] bug 2775: Moved RegattaOverview settings to a new GWT module to make it usable in other entry point modules for the creation of entry point links in e.g. AdminConsole and Home --- .../sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml | 2 +- .../regattaoverview/client/RegattaOverviewEntryPoint.java | 1 + .../gwt/regattaoverview/client/RegattaOverviewPanel.java | 1 + .../regattaoverview/client/RegattaRaceStatesComponent.java | 1 + .../client/RegattaRaceStatesSettingsDialogComponent.java | 1 + .../main/java/com/sap/sailing/gwt/settings/Settings.gwt.xml | 6 ++++++ .../client/regattaoverview}/RegattaRaceStatesSettings.java | 2 +- 7 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/Settings.gwt.xml rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/{regattaoverview/client => settings/client/regattaoverview}/RegattaRaceStatesSettings.java (98%) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml index 005c459d00d..476d2031cbd 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/RegattaOverview.gwt.xml @@ -42,7 +42,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index 326544442c9..16da658cb38 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -15,6 +15,7 @@ import com.google.gwt.user.client.ui.ScrollPanel; import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication; import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.regattaoverview.client.RegattaRaceStatesComponent.EntryHandler; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings; import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint; import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO; import com.sap.sse.gwt.settings.SettingsToUrlSerializer; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java index 2ea5c73b7ab..c6ffd7eaa3b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewPanel.java @@ -21,6 +21,7 @@ import com.google.gwt.user.client.ui.TabPanel; import com.google.gwt.user.client.ui.VerticalPanel; import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.regattaoverview.client.RegattaRaceStatesComponent.EntryHandler; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings; import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java index 4c374365152..e0789fad590 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesComponent.java @@ -49,6 +49,7 @@ import com.sap.sailing.domain.common.LeaderboardNameConstants; import com.sap.sailing.domain.common.PassingInstruction; import com.sap.sailing.domain.common.dto.FleetDTO; import com.sap.sailing.domain.common.racelog.Flags; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings; import com.sap.sailing.gwt.ui.client.AnchorCell; import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java index bdb01ef48e0..98f085dc64a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettingsDialogComponent.java @@ -17,6 +17,7 @@ import com.google.gwt.user.client.ui.FocusWidget; import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/Settings.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/Settings.gwt.xml new file mode 100644 index 00000000000..ef964e2a286 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/Settings.gwt.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java similarity index 98% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java index ba02c995b7c..f502da8a04d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaRaceStatesSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.regattaoverview.client; +package com.sap.sailing.gwt.settings.client.regattaoverview; import java.util.Collections; import java.util.HashSet; From e5949babb367da2bf2bfe3d38fa460b7719a0fdb Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 15:33:50 +0100 Subject: [PATCH 041/259] bug 2775: Added AbstractEntryPointWithSettingsLinkFactory to make the construction of entry point links using the real settings objects possible --- ...ractEntryPointWithSettingsLinkFactory.java | 15 +++++++++++ .../gwt/settings/SettingsToUrlSerializer.java | 14 ++--------- .../sap/sse/gwt/settings/UrlBuilderUtil.java | 25 +++++++++++++++++++ 3 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/UrlBuilderUtil.java diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java new file mode 100644 index 00000000000..b38c60173b7 --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java @@ -0,0 +1,15 @@ +package com.sap.sse.gwt.settings; + +import com.google.gwt.http.client.UrlBuilder; +import com.sap.sse.common.settings.Settings; + +public abstract class AbstractEntryPointWithSettingsLinkFactory { + private static final SettingsToUrlSerializer serializer = new SettingsToUrlSerializer(); + protected static String createEntryPointLink(String baseLink, Settings... settings) { + UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters(baseLink); + for (Settings setting : settings) { + serializer.serializeToUrlBuilder(setting, urlBuilder); + } + return urlBuilder.buildString(); + } +} diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java index 75850b33588..ac3cdfe30eb 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java @@ -19,7 +19,7 @@ public class SettingsToUrlSerializer { } public String serializeBasedOnCurrentLocationWithCleanParameters(Settings settings) { - final UrlBuilder urlBuilder = createUrlBuilderFromCurrentLocationWithCleanParameters(); + final UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters(); serializeToUrlBuilder(settings, urlBuilder); return urlBuilder.buildString(); } @@ -31,21 +31,11 @@ public class SettingsToUrlSerializer { } public UrlBuilder serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(Settings settings) { - final UrlBuilder urlBuilder = createUrlBuilderFromCurrentLocationWithCleanParameters(); + final UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters(); serializeToUrlBuilder(settings, urlBuilder); return urlBuilder; } - private UrlBuilder createUrlBuilderFromCurrentLocationWithCleanParameters() { - final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); - for(String parameterName : Window.Location.getParameterMap().keySet()) { - if("gwt.codesvr".equals(parameterName)) { - urlBuilder.removeParameter(parameterName); - } - } - return urlBuilder; - } - public void serializeToUrlBuilder(Settings settings, UrlBuilder urlBuilder) { Map> serializedValues = settingsToStringMapSerializer.serialize(settings); for(Map.Entry> entry : serializedValues.entrySet()) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/UrlBuilderUtil.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/UrlBuilderUtil.java new file mode 100644 index 00000000000..a1522d76e1f --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/UrlBuilderUtil.java @@ -0,0 +1,25 @@ +package com.sap.sse.gwt.settings; + +import com.google.gwt.http.client.UrlBuilder; +import com.google.gwt.user.client.Window; + +public class UrlBuilderUtil { + + public static UrlBuilder createUrlBuilderFromCurrentLocationWithCleanParameters() { + final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); + for(String parameterName : Window.Location.getParameterMap().keySet()) { + if(!"gwt.codesvr".equals(parameterName) + && !"locale".equals(parameterName)) { + urlBuilder.removeParameter(parameterName); + } + } + urlBuilder.setHash(null); + return urlBuilder; + } + + public static UrlBuilder createUrlBuilderFromCurrentLocationWithCleanParameters(String path) { + final UrlBuilder urlBuilder = createUrlBuilderFromCurrentLocationWithCleanParameters(); + urlBuilder.setPath(path); + return urlBuilder; + } +} From 0d4277a06d8478b7911625e41a3c310e3cbe23a9 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 16:10:45 +0100 Subject: [PATCH 042/259] bug 2775: Encapsulated basic RegattaOverview parameters to a settings object for ease of parsing the URL parameters --- .../client/RegattaOverviewEntryPoint.java | 32 ++++++++----------- .../RegattaOverviewBaseSettings.java | 21 ++++++++++++ 2 files changed, 34 insertions(+), 19 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java index 16da658cb38..f5653f8e579 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/regattaoverview/client/RegattaOverviewEntryPoint.java @@ -5,6 +5,7 @@ import java.util.UUID; 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.http.client.UrlBuilder; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.DockLayoutPanel; import com.google.gwt.user.client.ui.FlowPanel; @@ -15,6 +16,7 @@ import com.google.gwt.user.client.ui.ScrollPanel; import com.sap.sailing.gwt.common.authentication.FixedSailingAuthentication; import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.regattaoverview.client.RegattaRaceStatesComponent.EntryHandler; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewBaseSettings; import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings; import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint; import com.sap.sailing.gwt.ui.shared.RegattaOverviewEntryDTO; @@ -23,12 +25,7 @@ import com.sap.sse.security.ui.authentication.generic.sapheader.SAPHeaderWithAut public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { - private final static String PARAM_EVENT = "event"; - private final static String PARAM_ONLY_RUNNING_RACES = "onlyrunningraces"; - private final static String PARAM_ONLY_RACES_OF_SAME_DAY = "onlyracesofsameday"; - private final static String PARAM_REGATTA = "regatta"; - private final static String PARAM_COURSE_AREA = "coursearea"; - private final static String PARAM_IGNORE_LOCAL_SETTINGS = "ignoreLocalSettings"; + private static final SettingsToUrlSerializer serializer = new SettingsToUrlSerializer(); private DockLayoutPanel containerPanel; private RaceDetailPanel detailPanel; @@ -60,14 +57,16 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { siteHeader.addWidgetToRightSide(clockLabel); containerPanel.addNorth(siteHeader, 75); - String eventIdAsString = Window.Location.getParameter(PARAM_EVENT); - if (eventIdAsString == null) { + RegattaOverviewBaseSettings regattaOverviewSettings = serializer + .deserializeFromCurrentLocation(new RegattaOverviewBaseSettings()); + + if (regattaOverviewSettings.getEvent() == null) { Window.alert("Missing parameter"); return; } createAndAddDetailPanel(); - createAndAddRegattaPanel(UUID.fromString(eventIdAsString)); + createAndAddRegattaPanel(regattaOverviewSettings.getEvent(), regattaOverviewSettings.isIgnoreLocalSettings()); toggleDetailPanel(false); regattaPanel.setEntryClickedHandler(new EntryHandler() { @@ -90,9 +89,8 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { // containerPanel.setWidgetHidden(detailPanel, !visibile); } - private void createAndAddRegattaPanel(UUID eventId) { + private void createAndAddRegattaPanel(UUID eventId, boolean ignoreLocalSettings) { RegattaRaceStatesSettings settings = createRegattaRaceStatesSettingsFromURL(); - boolean ignoreLocalSettings = getIgnoreLocalSettingsFromURL(); regattaPanel = new RegattaOverviewPanel(sailingService, this, getStringMessages(), eventId, settings, userAgent, ignoreLocalSettings); regattaPanel.addHandler(new EventDTOLoadedEvent.Handler() { @@ -116,10 +114,6 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { containerPanel.add(scrollPanel); } - private boolean getIgnoreLocalSettingsFromURL() { - return Boolean.parseBoolean(Window.Location.getParameter(PARAM_IGNORE_LOCAL_SETTINGS)); - } - private void createAndAddDetailPanel() { detailPanel = new RaceDetailPanel(getStringMessages(), new ClickHandler() { @Override @@ -131,12 +125,12 @@ public class RegattaOverviewEntryPoint extends AbstractSailingEntryPoint { } public static RegattaRaceStatesSettings createRegattaRaceStatesSettingsFromURL() { - return new SettingsToUrlSerializer().deserializeFromCurrentLocation(new RegattaRaceStatesSettings()); + return serializer.deserializeFromCurrentLocation(new RegattaRaceStatesSettings()); } public static String getUrl(UUID eventId, RegattaRaceStatesSettings settings) { - return new SettingsToUrlSerializer().serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(settings) - .setParameter(PARAM_IGNORE_LOCAL_SETTINGS, "true").setParameter(PARAM_EVENT, eventId.toString()) - .buildString(); + UrlBuilder urlBuilder = serializer.serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(settings); + serializer.serializeToUrlBuilder(new RegattaOverviewBaseSettings(eventId), urlBuilder); + return urlBuilder.buildString(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java new file mode 100644 index 00000000000..4fa76f9db37 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java @@ -0,0 +1,21 @@ +package com.sap.sailing.gwt.settings.client.regattaoverview; + +import java.util.UUID; + +import com.sap.sse.common.settings.AbstractSettings; +import com.sap.sse.common.settings.BooleanSetting; +import com.sap.sse.common.settings.UUIDSetting; + +public final class RegattaOverviewBaseSettings extends AbstractSettings { + private final UUIDSetting event = new UUIDSetting("event", this); + private final BooleanSetting ignoreLocalSettings = new BooleanSetting("ignoreLocalSettings", this, false); + + public RegattaOverviewBaseSettings(UUID event) { + this(event, true); + } + + public RegattaOverviewBaseSettings(UUID event, boolean ignoreLocalSettings) { + this.event.setValue(event); + this.ignoreLocalSettings.setValue(ignoreLocalSettings); + } +} From 5fb51efbb693f6291c15b161e8f101e7b5d9d297 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 16:30:19 +0100 Subject: [PATCH 043/259] bug 2775: Using actual settings objects to construct RegattaOverview link in Home and AdminConsole --- .../java/com/sap/sailing/gwt/home/Home.gwt.xml | 1 + .../places/event/AbstractEventActivity.java | 15 ++++++++++----- .../EntryPointWithSettingsLinkFactory.java | 18 ++++++++++++++++++ .../RegattaOverviewBaseSettings.java | 15 +++++++++++++++ .../sap/sailing/gwt/ui/AdminConsole.gwt.xml | 1 + .../ui/adminconsole/EventDetailsComposite.java | 10 ++++------ .../gwt/ui/client/EntryPointLinkFactory.java | 4 ---- ...tractEntryPointWithSettingsLinkFactory.java | 2 ++ 8 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/EntryPointWithSettingsLinkFactory.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml index 6861808a6fe..35805af843f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml @@ -44,6 +44,7 @@ + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java index dcaa97c38eb..fef3975eece 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/event/AbstractEventActivity.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.home.desktop.places.event; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import com.google.gwt.activity.shared.AbstractActivity; import com.google.gwt.core.shared.GWT; @@ -32,6 +33,9 @@ import com.sap.sailing.gwt.home.shared.places.event.EventDefaultPlace; import com.sap.sailing.gwt.home.shared.places.events.EventsPlace; import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesDefaultPlace; import com.sap.sailing.gwt.home.shared.places.start.StartPlace; +import com.sap.sailing.gwt.settings.client.EntryPointWithSettingsLinkFactory; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewBaseSettings; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings; import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory; @@ -206,19 +210,20 @@ public abstract class AbstractEventActivity ex @Override public String getRegattaOverviewLink() { - String url = "RegattaOverview.html?ignoreLocalSettings=true&onlyrunningraces=false&event=" + getCtx().getEventId(); - url += "&onlyracesofsameday=" + eventDTO.isRunning(); + RegattaRaceStatesSettings regattaRaceStatesSettings = new RegattaRaceStatesSettings(); + regattaRaceStatesSettings.setShowOnlyCurrentlyRunningRaces(false); + regattaRaceStatesSettings.setShowOnlyRaceOfSameDay(eventDTO.isRunning()); if(showRegattaMetadata()) { if(getRegattaMetadata().isFlexibleLeaderboard()) { String defaultCourseAreaId = getRegattaMetadata().getDefaultCourseAreaId(); if(defaultCourseAreaId != null && !defaultCourseAreaId.isEmpty()) { - url += "&coursearea=" + defaultCourseAreaId; + regattaRaceStatesSettings.getVisibleCourseAreaSettings().addValue(UUID.fromString(defaultCourseAreaId)); } } else { - url += "®atta=" + getRegattaId(); + regattaRaceStatesSettings.getVisibleRegattaSettings().addValue(getRegattaId()); } } - return url; + return EntryPointWithSettingsLinkFactory.createRegattaOverviewLink(new RegattaOverviewBaseSettings(getCtx().getEventId()), regattaRaceStatesSettings); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/EntryPointWithSettingsLinkFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/EntryPointWithSettingsLinkFactory.java new file mode 100644 index 00000000000..9b0ad24458d --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/EntryPointWithSettingsLinkFactory.java @@ -0,0 +1,18 @@ +package com.sap.sailing.gwt.settings.client; + +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewBaseSettings; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaRaceStatesSettings; +import com.sap.sse.gwt.settings.AbstractEntryPointWithSettingsLinkFactory; + +public class EntryPointWithSettingsLinkFactory extends AbstractEntryPointWithSettingsLinkFactory { + + public static String createRegattaOverviewLink(RegattaOverviewBaseSettings regattaOverviewSettings) { + return createRegattaOverviewLink(regattaOverviewSettings, new RegattaRaceStatesSettings()); + } + + public static String createRegattaOverviewLink(RegattaOverviewBaseSettings regattaOverviewSettings, + RegattaRaceStatesSettings regattaRaceStatesSettings) { + return createEntryPointLink("/gwt/RegattaOverview.html", regattaOverviewSettings, regattaRaceStatesSettings); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java index 4fa76f9db37..bd8ee02fcc5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java @@ -10,6 +10,13 @@ public final class RegattaOverviewBaseSettings extends AbstractSettings { private final UUIDSetting event = new UUIDSetting("event", this); private final BooleanSetting ignoreLocalSettings = new BooleanSetting("ignoreLocalSettings", this, false); + public RegattaOverviewBaseSettings() { + } + + public RegattaOverviewBaseSettings(String event) { + this(UUID.fromString(event)); + } + public RegattaOverviewBaseSettings(UUID event) { this(event, true); } @@ -18,4 +25,12 @@ public final class RegattaOverviewBaseSettings extends AbstractSettings { this.event.setValue(event); this.ignoreLocalSettings.setValue(ignoreLocalSettings); } + + public UUID getEvent() { + return event.getValue(); + } + + public boolean isIgnoreLocalSettings() { + return ignoreLocalSettings.getValue(); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml index 1da133d8ad6..0d6c5b8952c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/AdminConsole.gwt.xml @@ -67,6 +67,7 @@ + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java index 8762b4e5341..b110b287b99 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java @@ -1,9 +1,7 @@ package com.sap.sailing.gwt.ui.adminconsole; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.ui.Anchor; @@ -13,7 +11,8 @@ import com.google.gwt.user.client.ui.Grid; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.VerticalPanel; -import com.sap.sailing.gwt.ui.client.EntryPointLinkFactory; +import com.sap.sailing.gwt.settings.client.EntryPointWithSettingsLinkFactory; +import com.sap.sailing.gwt.settings.client.regattaoverview.RegattaOverviewBaseSettings; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; @@ -135,9 +134,8 @@ public class EventDetailsComposite extends Composite { officialWebsiteURL.setText(event.getOfficialWebsiteURL()); officialWebsiteURL.setHref(event.getOfficialWebsiteURL()); sailorsInfoWebsiteURLList.setValues(new ArrayList(event.getSailorsInfoWebsiteURLs().values())); - Map regattaOverviewURLParameters = new HashMap(); - regattaOverviewURLParameters.put("event", event.id.toString()); - String regattaOverviewLink = EntryPointLinkFactory.createRegattaOverviewLink(regattaOverviewURLParameters); + String regattaOverviewLink = EntryPointWithSettingsLinkFactory + .createRegattaOverviewLink(new RegattaOverviewBaseSettings(event.id, false)); eventOverviewURL.setText(regattaOverviewLink); eventOverviewURL.setHref(UriUtils.fromString(regattaOverviewLink)); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java index 0cbc204ee07..8bb1e9d3249 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/EntryPointLinkFactory.java @@ -41,10 +41,6 @@ public class EntryPointLinkFactory extends AbstractEntryPointLinkFactory { return createEntryPointLink("/gwt/Home.html#/event/:eventId="+eventId, parameters); } - public static String createRegattaOverviewLink(Map parameters) { - return createEntryPointLink("/gwt/RegattaOverview.html", parameters); - } - public static String createDashboardLink(Map parameters) { return createEntryPointLink("/dashboards/RibDashboard.html", parameters); } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java index b38c60173b7..a4db16a9061 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java @@ -4,7 +4,9 @@ import com.google.gwt.http.client.UrlBuilder; import com.sap.sse.common.settings.Settings; public abstract class AbstractEntryPointWithSettingsLinkFactory { + private static final SettingsToUrlSerializer serializer = new SettingsToUrlSerializer(); + protected static String createEntryPointLink(String baseLink, Settings... settings) { UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters(baseLink); for (Settings setting : settings) { From 5bc2a5ed9dab58aca2caca778a9f96a2b5a04249 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 17:51:58 +0100 Subject: [PATCH 044/259] bug 2775: Added some JavaDocs to the central classes of the Settings framework --- .../com/sap/sse/common/settings/Settings.java | 34 ++++++++++++++----- .../gwt/settings/SettingsToUrlSerializer.java | 10 ++++++ .../settings/SettingsToJsonSerializer.java | 13 ++----- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java index 6f7df127e71..34b87b1845a 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java @@ -3,8 +3,8 @@ package com.sap.sse.common.settings; import java.util.Map; /** - * A generic format to keep the non-default settings for a Component. Such settings may be initialized with - * defaults. Usually they can be edited by a user using a SettingsDialogComponent displayed by a + * A generic format to keep the settings for a Component. Such settings may be initialized with defaults. + * Usually they can be edited by a user using a SettingsDialogComponent displayed by a * SettingsDialog. The interface is homed in this server-side, shared bundle because settings may as well * be handled on the server side, e.g., in order to store them in the user store or to apply them to a server-side * component. @@ -15,21 +15,39 @@ import java.util.Map; * in the user-specific preferences store where JSON may be a useful format to keep them as a {@link String}. *

* - * In order to enable mapping the settings to URL parameters, each setting needs to have a name and a {@link Setting} - * value that in turn can be serialized accordingly. Furthermore, the component to which the settings apply needs to - * provide a String identifier. This way, generic serializers/de-serializers can take over the serialization from/to the - * various formats. + * The following serializers are available: + *

    + *
  • + * {@link com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer}: Serializes to a Map containing String + * keys and values
  • + *
  • + * {@link com.sap.sse.gwt.settings.SettingsToUrlSerializer}: Serializes to a GWT UrlBuilder
  • + *
  • + * {@link com.sap.sse.shared.settings.SettingsToJsonSerializer}: Serializes to org.json.simple objects usable in the + * backend and on Android
  • + *
  • + * {@link com.sap.sse.gwt.settings.SettingsToJsonSerializerGWT}: Serializes to GWT's JSON types. The resliting JSON + * String is compatible with the backend-side SettingsToJsonSerializer.
  • + *
+ * + * In order to enable mapping the settings to URL parameters or JSON structures, each setting needs an associated name + * and the {@link Settings} hierarchy must be ensured. For this every {@link Setting} has a constructor requiring it's + * name and parent Settings object. To make {@link Settings} able to be nested in other {@link Settings} you need to + * provide the very same constructor that can simply call super on {@link AbstractSettings}. This way, generic + * serializers/de-serializers can take over the serialization from/to the various formats. * * @author Axel Uhl (D043530) * */ public interface Settings extends Setting { + /** + * Path separator for serializers that construct flat keys for the hierachical settings structures (e.g. URL). + */ public static final String PATH_SEPARATOR = "."; /** - * Obtains all settings that have non-default values and therefore are required for the later re-construction - * of the settings object when passed the resulting map. + * Obtains all child settings. */ Map getChildSettings(); } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java index ac3cdfe30eb..839d3b8b67b 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java @@ -8,6 +8,16 @@ import com.sap.sse.common.Util; import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer; +/** + * Serializes {@link Settings} objects to the URL by constructing flat keys from the hierarchical object graph. + * + * This type of serialzation has some limitations: + *
    + *
  • Empty collections can not be serialized. This can only occur for collection settings that have their default value set to be non-empty and there is no actual value.
  • + *
  • Null values can not be distinguished from empty strings
  • + *
+ * + */ public class SettingsToUrlSerializer { private final SettingsToStringMapSerializer settingsToStringMapSerializer = new SettingsToStringMapSerializer(); diff --git a/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java index 52f78b17b2d..f57df9da4a7 100644 --- a/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java +++ b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java @@ -3,21 +3,12 @@ package com.sap.sse.shared.settings; import org.json.simple.JSONArray; import org.json.simple.JSONObject; -import com.sap.sse.common.settings.EnumSetting; import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; /** - * Serializes a {@link Settings} object to a {@link JSONObject}. All setting types are supported as top-level entities. - * Nesting of {@link Settings} is generally supported. For example, a {@link Settings} object can be contains as one - * setting within another {@link Settings} object. However, when nesting {@link EnumSetting} objects within a - * {@link ListSetting} then it is mandatory to put this {@link ListSetting} object into a {@link Settings} object's - * {@link Settings#getNonDefaultSettings()}, such as into a {@link MapSettings} object. The technical reason for this - * limitation is that the {@link Class} object for the enumeration type must be stored with the serialized format in - * order to re-construct the enumeration literals of the correct type. For readability of the produced JSON output, - * this implementation chooses to store the enumeration class's name in a special property that is sibling of the - * enumeration property. A {@link ListSetting} object does not contain named properties and therefore does not allow - * us to add such a property easily. + * Serializes a {@link Settings} object to a {@link JSONObject}. All {@link Settings} subclasses are supported as top-level entities. + * Nesting of {@link Settings} is generally supported. * * @author Axel Uhl (D043530) * From dc809a598b1a77221b6859a2a748433591903db3 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 16 Mar 2016 18:02:12 +0100 Subject: [PATCH 045/259] bug 2775: Added a paragraph regarding RegattaOverview settings/parameters to the release notes --- java/com.sap.sailing.www/release_notes_admin.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 16d2c75d051..5a104e378d3 100644 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -33,6 +33,11 @@ No sailors info link is shown for UI languages if there is neither a default link nor one for the specific locale, even if there is one for another locale configured. +
  • The mechanism to handle RegattaOverview settings has been changed to a more generic approach. + This leads to slightly changed URL parameter names so that old bookmarks could be broken in a way + so that the actual shown set of races is different using the new version because the old parameters aren't correctly recognized. + All automatically generated links to this page in Home and AdminConsole have been updated to use the new parameter names. +
  • February 2016

      From b2cef2caf815708c2ca5127eb0eac089c6297407 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 17 Mar 2016 08:25:43 +0100 Subject: [PATCH 046/259] bug 2775: Added some more JavaDocs --- .../sse/common/settings/AbstractSettings.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index 7fa7ba06675..7e3a687fb63 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -4,6 +4,51 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +/** + * Common superclass for custom Settings used by Components. The following example shows how to implement custom + * Settings: + * + *
      + * 
      + * public final class RegattaOverviewBaseSettings extends AbstractSettings {
      + *     private final StringSetting myString = new UUIDSetting("myString", this);
      + *     private final BooleanSetting myBoolean = new BooleanSetting("myBoolean", this);
      + *     
      + *     // Used to create instances for a component
      + *     public RegattaOverviewBaseSettings() {
      + *     }
      + *     
      + *     // Used to create nested settings
      + *     public RegattaOverviewBaseSettings(String name, AbstractSettings settings) {
      + *         this.event.setValue(event);
      + *         this.ignoreLocalSettings.setValue(ignoreLocalSettings);
      + *     }
      + *     
      + *     public String getMyString() {
      + *         return this.myString.getValue();
      + *     }
      + *     
      + *     public void setMyString(String myString) {
      + *         return this.myString.setValue(myString);
      + *     }
      + *     
      + *     public boolean isMyBoolean() {
      + *         return this.myBoolean.getValue();
      + *     }
      + *     
      + *     public void setMyBoolean(boolean myBoolean) {
      + *         return this.myBoolean.setValue(myBoolean);
      + *     }
      + * }
      + * 
      + * 
      + * + * If a custom Settings class only has {@link Setting} oder {@link Settings} children that are correctly attached by + * calling their constructor with a name and the parent {@link Settings} you do not need to implement + * {@link #hashCode()}, {@link #equals(Object)} and {@link #toString()}. There are generic implementations of those methods that are + * based on the child {@link Setting}s which should be sufficient for most cases. + * + */ public abstract class AbstractSettings extends AbstractSetting implements Settings { private Map childSettings = new HashMap<>(); From 51489147521cc10610422931f90b841db4fefebf Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 17 Mar 2016 08:28:19 +0100 Subject: [PATCH 047/259] bug 2775: Using more concrete generics declarations --- .../src/com/sap/sse/common/settings/HasSettingsFactory.java | 2 +- .../src/com/sap/sse/common/settings/SettingsFactory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java index 6d5b7c03639..9b16b3753d3 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java @@ -1,5 +1,5 @@ package com.sap.sse.common.settings; -public interface HasSettingsFactory { +public interface HasSettingsFactory { SettingsFactory getSettingsFactory(); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java index 15fcbd8c53e..43800d8f76f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java @@ -1,5 +1,5 @@ package com.sap.sse.common.settings; -public interface SettingsFactory { +public interface SettingsFactory { T newInstance(); } From 4621d96215b53c9a9a350112cbaf4034f71ef375 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 17 Mar 2016 08:38:46 +0100 Subject: [PATCH 048/259] bug 2775: Added some more JavaDocs --- .../com/sap/sse/common/settings/SettingsFactory.java | 7 +++++++ .../sap/sse/common/settings/StringToEnumConverter.java | 8 ++++++++ .../serializer/AbstractSettingsToJsonSerializer.java | 10 ++++++++++ .../serializer/SettingsToStringMapSerializer.java | 6 ++++++ 4 files changed, 31 insertions(+) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java index 43800d8f76f..15629b0c5f4 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java @@ -1,5 +1,12 @@ package com.sap.sse.common.settings; +/** + * + * Used by {@link SettingsList} for deserialization of complex {@link Settings} based collections. + * Because GWT can't use reflection the serialization mechanism must rely on factories to create nested instances on demand. + * + * @param The type of the created {@link Settings} objects + */ public interface SettingsFactory { T newInstance(); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java index c99dcdbcb15..0ab5afc4707 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java @@ -1,5 +1,13 @@ package com.sap.sse.common.settings; +/** + * GWT can't use reflection. When deserializing Settings that contain {@link Enum} values there must be come conversion + * of raw String values to the actual enum constants. So an instance of {@link StringToEnumConverter} must be provided + * for every {@link Enum} based {@link Setting} objects. + * + * @param + * Type of the created enum instances + */ public interface StringToEnumConverter> { T fromString(String stringValue); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java index e4d83fe4f02..ed839c9e69f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java @@ -12,6 +12,16 @@ import com.sap.sse.common.settings.ValueCollectionSetting; import com.sap.sse.common.settings.ValueConverter; import com.sap.sse.common.settings.ValueSetting; +/** + * Base class for {@link Settings} serializers that produce JSON objects using some generic object model. This base + * class ensures that the produced structure is equivalent for different JSON APIs so the setrialized JSON Strings + * should be compatible and sharable between all those implementations. + * + * @param + * JSON object type + * @param + * JSON Array type + */ public abstract class AbstractSettingsToJsonSerializer { protected abstract OBJECT newOBJECT(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java index d07251ba2da..86a1a2f8b3b 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java @@ -17,6 +17,12 @@ import com.sap.sse.common.settings.ValueConverter; import com.sap.sse.common.settings.ValueCollectionSetting; import com.sap.sse.common.settings.ValueSetting; +/** + * {@link Settings} serializer that constructs flattened String keys with associated String values from the hierarchical + * {@link Settings} structures. This is necessary for cases where hierarchical structures aren't mappable (e.g. URL + * serialization). + * + */ public class SettingsToStringMapSerializer { public Map> serialize(Settings settings) { From fc2fe2d04f27f9046920fa489a8547bc34dee9dc Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 17 Mar 2016 14:48:46 +0100 Subject: [PATCH 049/259] bug 2775: Removed unused enum --- .../src/com/sap/sse/common/settings/SettingType.java | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingType.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingType.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingType.java deleted file mode 100644 index 38f61391f86..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingType.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.sap.sse.common.settings; - -public enum SettingType { - STRING, NUMBER, LIST, ENUM, MAP; -} From dc6d8d3723ad2891da66489c7b7134228031324e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 17 Mar 2016 14:59:06 +0100 Subject: [PATCH 050/259] bug 2775: JavaDoc adjustments --- .../src/com/sap/sse/common/settings/AbstractSettings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index 7e3a687fb63..1cdcf56e3d4 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -10,7 +10,7 @@ import java.util.Map; * *
        * 
      - * public final class RegattaOverviewBaseSettings extends AbstractSettings {
      + * public final class ExampleSettings extends AbstractSettings {
        *     private final StringSetting myString = new UUIDSetting("myString", this);
        *     private final BooleanSetting myBoolean = new BooleanSetting("myBoolean", this);
        *     
      
      From 459651cb4a928f119fcb2fc63da52036bfadca73 Mon Sep 17 00:00:00 2001
      From: Steffen Schaefer 
      Date: Wed, 13 Apr 2016 16:02:17 +0200
      Subject: [PATCH 051/259] Moved the inner storing of settings to value objects
       and changed the Settings hierarchy to be restored after deserialization to
       support both, Java and GWT serialization
      
      ---
       .../sse/common/settings/AbstractSetting.java  | 13 ++-
       .../sse/common/settings/AbstractSettings.java | 46 +++++++++-
       .../sap/sse/common/settings/SettingsList.java | 90 +++++++++++++++++-
       .../sse/common/settings/ValueConverter.java   |  7 +-
       .../settings/base/AbstractListSetting.java    | 59 ------------
       .../base/AbstractValueCollectionSetting.java  | 54 +++++++----
       .../base/AbstractValueListSetting.java        | 19 ++--
       .../base/AbstractValueSetSetting.java         | 19 ++--
       .../settings/base/AbstractValueSetting.java   | 27 ++++--
       .../settings/converter/BooleanConverter.java  | 16 +++-
       .../settings/converter/DecimalConverter.java  | 16 +++-
       .../settings/converter/DoubleConverter.java   | 16 +++-
       .../settings/converter/EnumConverter.java     | 12 +++
       .../settings/converter/StringConverter.java   | 15 ++-
       .../settings/converter/UUIDConverter.java     | 16 +++-
       .../common/settings/value/AbstractValue.java  | 47 ++++++++++
       .../common/settings/value/BooleanValue.java   | 13 +++
       .../common/settings/value/DecimalValue.java   | 15 +++
       .../common/settings/value/DoubleValue.java    | 13 +++
       .../settings/value/SettingsListValue.java     | 23 +++++
       .../common/settings/value/SettingsValue.java  | 53 +++++++++++
       .../common/settings/value/StringValue.java    | 13 +++
       .../sse/common/settings/value/UUIDValue.java  | 15 +++
       .../sap/sse/common/settings/value/Value.java  |  6 ++
       .../settings/value/ValueCollection.java       | 13 +++
       .../settings/value/ValueCollectionValue.java  | 92 +++++++++++++++++++
       .../common/settings/value/ValueListValue.java | 18 ++++
       .../common/settings/value/ValueSetValue.java  | 18 ++++
       .../AbstractSettingsSerializationTest.java    | 24 ++++-
       29 files changed, 664 insertions(+), 124 deletions(-)
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/AbstractValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/BooleanValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DecimalValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DoubleValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsListValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/StringValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/UUIDValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/Value.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueListValue.java
       create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueSetValue.java
      
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java
      index 6331ae82298..360fc35f71e 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java
      @@ -4,11 +4,18 @@ package com.sap.sse.common.settings;
       
       public abstract class AbstractSetting implements Setting {
           
      -    public AbstractSetting(String name, AbstractSettings settings) {
      -        settings.addSetting(name, this);
      +    protected final AbstractSettings settings;
      +    protected final String settingName;
      +
      +    public AbstractSetting(String settingName, AbstractSettings settings) {
      +        this.settingName = settingName;
      +        this.settings = settings;
      +        if(settings != null) {
      +            settings.addSetting(settingName, this);
      +        }
           }
           
           public AbstractSetting() {
      +        this(null, null);
           }
      -
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java
      index 1cdcf56e3d4..be3124c602a 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java
      @@ -1,9 +1,15 @@
       package com.sap.sse.common.settings;
       
      +import java.io.IOException;
      +import java.io.ObjectInputStream;
       import java.util.Collections;
       import java.util.HashMap;
       import java.util.Map;
       
      +import com.google.gwt.core.shared.GwtIncompatible;
      +import com.sap.sse.common.settings.value.SettingsValue;
      +import com.sap.sse.common.settings.value.Value;
      +
       /**
        * Common superclass for custom Settings used by Components. The following example shows how to implement custom
        * Settings:
      @@ -51,13 +57,51 @@ import java.util.Map;
        */
       public abstract class AbstractSettings extends AbstractSetting implements Settings {
       
      -    private Map childSettings = new HashMap<>();
      +    private SettingsValue value;
      +    private transient Map childSettings = new HashMap<>();
       
           public AbstractSettings() {
      +        value = new SettingsValue();
      +        addChildSettings();
           }
       
           public AbstractSettings(String name, AbstractSettings settings) {
               super(name, settings);
      +        value = (SettingsValue) settings.getValue(name);
      +        if(value == null) {
      +            value = new SettingsValue();
      +            settings.setValue(name, value);
      +        }
      +        settings.setValue(name, value);
      +        addChildSettings();
      +    }
      +    
      +    protected void adoptValue(SettingsValue value) {
      +        this.value = value;
      +    }
      +    
      +    protected SettingsValue getInnerValueObject() {
      +        return value;
      +    }
      +    
      +    @GwtIncompatible
      +    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
      +        ois.defaultReadObject();
      +        addChildSettings();
      +    }
      +    
      +    // TODO make abstract when all Settings are ported to the new system
      +    protected void addChildSettings() {
      +    }
      +    
      +    // TODO make protected
      +    public Value getValue(String settingName) {
      +        return value.getValue(settingName);
      +    }
      +    
      +    // TODO make protected
      +    public void setValue(String settingName, Value value) {
      +        this.value.setValue(settingName, value);
           }
       
           protected void addSetting(String name, Setting setting) {
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java
      index d42cafcb6fa..3cb61ecd244 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java
      @@ -1,15 +1,31 @@
       package com.sap.sse.common.settings;
       
      -import com.sap.sse.common.settings.base.AbstractListSetting;
      +import java.util.ArrayList;
      +import java.util.Collections;
      +import java.util.List;
      +
      +import com.sap.sse.common.settings.value.SettingsValue;
      +import com.sap.sse.common.settings.value.Value;
      +import com.sap.sse.common.settings.value.ValueCollectionValue;
      +import com.sap.sse.common.settings.value.ValueListValue;
       
       
      -public class SettingsList extends AbstractListSetting implements SettingsListSetting {
      +public class SettingsList extends AbstractSetting implements SettingsListSetting {
           
           private SettingsFactory settingsFactory;
      +    private final List values = new ArrayList<>();
           
           public SettingsList(String name, AbstractSettings settings, SettingsFactory settingsFactory) {
               super(name, settings);
               this.settingsFactory = settingsFactory;
      +        ValueListValue value = getValue();
      +        if(value != null) {
      +            for(Value val : value.getValueObjects()) {
      +                T childSettingsInstance = settingsFactory.newInstance();
      +                childSettingsInstance.adoptValue((SettingsValue)val);
      +                values.add(childSettingsInstance);
      +            }
      +        }
           }
       
           @Override
      @@ -17,8 +33,78 @@ public class SettingsList extends AbstractListSetting imp
               return settingsFactory;
           }
           
      +    private ValueCollectionValue> ensureValue() {
      +        ValueListValue result = getValue();
      +        if(result == null) {
      +            result = new ValueListValue();
      +            settings.setValue(settingName, result);
      +        }
      +        return result;
      +    }
      +    
      +    private ValueListValue getValue() {
      +        return (ValueListValue) settings.getValue(settingName);
      +    }
      +
           @Override
           public String toString() {
               return getValues().toString();
           }
      +
      +    @Override
      +    public boolean isDefaultValue() {
      +        // explicit default values are possible to implement
      +        // currently, empty is always default
      +        return values.isEmpty();
      +    }
      +
      +    @Override
      +    public void resetToDefault() {
      +        this.values.clear();
      +        settings.setValue(settingName, null);
      +    }
      +
      +    @Override
      +    public Iterable getValues() {
      +        return Collections.unmodifiableCollection(values);
      +    }
      +
      +    @Override
      +    public void setValues(Iterable values) {
      +        this.values.clear();
      +        ValueCollectionValue> valueObject = ensureValue();
      +        valueObject.clear();
      +        if(values != null) {
      +            for(T value : values) {
      +                this.values.add(value);
      +                valueObject.addValue(value.getInnerValueObject());
      +            }
      +        }
      +    }
      +
      +    @Override
      +    public int hashCode() {
      +        final int prime = 31;
      +        int result = 1;
      +        result = prime * result + ((values == null) ? 0 : values.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;
      +        @SuppressWarnings("rawtypes")
      +        SettingsList other = (SettingsList) obj;
      +        if (values == null) {
      +            if (other.values != null)
      +                return false;
      +        } else if (!values.equals(other.values))
      +            return false;
      +        return true;
      +    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java
      index 06abd876db0..1594af9a66b 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java
      @@ -1,5 +1,7 @@
       package com.sap.sse.common.settings;
       
      +import com.sap.sse.common.settings.value.Value;
      +
       public interface ValueConverter {
       
           Object toJSONValue(T value);
      @@ -9,5 +11,8 @@ public interface ValueConverter {
           String toStringValue(T value);
       
           T fromStringValue(String stringValue);
      -
      +    
      +    Value toValue(T value);
      +    
      +    T fromValue(Value value);
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java
      index e25d667fb9a..061c499ca71 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java
      @@ -1,74 +1,15 @@
       package com.sap.sse.common.settings.base;
       
      -import java.util.ArrayList;
      -import java.util.Collections;
      -import java.util.List;
      -
       import com.sap.sse.common.settings.AbstractSetting;
       import com.sap.sse.common.settings.AbstractSettings;
       import com.sap.sse.common.settings.CollectionSetting;
       
       public abstract class AbstractListSetting extends AbstractSetting implements CollectionSetting {
           
      -    private final List values = new ArrayList<>();
      -    
           public AbstractListSetting(String name, AbstractSettings settings) {
               super(name, settings);
           }
           
           public AbstractListSetting() {
           }
      -    
      -    @Override
      -    public boolean isDefaultValue() {
      -        // explicit default values are possible to implement
      -        // currently, empty is always default
      -        return values.isEmpty();
      -    }
      -    
      -    @Override
      -    public void resetToDefault() {
      -        this.values.clear();
      -    }
      -    
      -    @Override
      -    public Iterable getValues() {
      -        return Collections.unmodifiableCollection(values);
      -    }
      -
      -    @Override
      -    public void setValues(Iterable values) {
      -        this.values.clear();
      -        if(values != null) {
      -            for(T value : values) {
      -                this.values.add(value);
      -            }
      -        }
      -    }
      -
      -    @Override
      -    public int hashCode() {
      -        final int prime = 31;
      -        int result = 1;
      -        result = prime * result + ((values == null) ? 0 : values.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;
      -        @SuppressWarnings("rawtypes")
      -        AbstractListSetting other = (AbstractListSetting) obj;
      -        if (values == null) {
      -            if (other.values != null)
      -                return false;
      -        } else if (!values.equals(other.values))
      -            return false;
      -        return true;
      -    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java
      index 33ff758fe1f..9c997fb5858 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java
      @@ -6,48 +6,68 @@ import java.util.Collections;
       import com.sap.sse.common.settings.AbstractSettings;
       import com.sap.sse.common.settings.ValueCollectionSetting;
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.Value;
      +import com.sap.sse.common.settings.value.ValueCollectionValue;
       
      -public abstract class AbstractValueCollectionSetting extends AbstractHasValueSetting implements ValueCollectionSetting {
      +public abstract class AbstractValueCollectionSetting> extends AbstractHasValueSetting implements ValueCollectionSetting {
           
           public AbstractValueCollectionSetting(String name, AbstractSettings settings, ValueConverter valueConverter) {
               super(name, settings, valueConverter);
           }
           
      -    protected abstract Collection getInnerCollection();
      +    @SuppressWarnings("unchecked")
      +    protected ValueCollectionValue getValue() {
      +        return (ValueCollectionValue) settings.getValue(settingName);
      +    }
      +    
      +    protected abstract ValueCollectionValue createValue();
      +    
      +    private ValueCollectionValue ensureValue() {
      +        ValueCollectionValue result = getValue();
      +        if(result == null) {
      +            result = createValue();
      +            settings.setValue(settingName, result);
      +        }
      +        return result;
      +    }
           
           @Override
           public Iterable getValues() {
      -        return Collections.unmodifiableCollection(getInnerCollection());
      +        ValueCollectionValue value = getValue();
      +        if(value == null) {
      +            return Collections.emptyList();
      +        }
      +        return value.getValues(getValueConverter());
           }
       
           @Override
           public final void setValues(Iterable values) {
      -        this.getInnerCollection().clear();
      -        if(values != null) {
      -            for(T value : values) {
      -                this.getInnerCollection().add(value);
      -            }
      -        }
      +        ensureValue().setValues(values, getValueConverter());
           }
           
           public void addValue(T value) {
      -        this.getInnerCollection().add(value);
      +        ensureValue().addValue(value, getValueConverter());
           }
       
           public void clear() {
      -        this.getInnerCollection().clear();
      +        ensureValue().clear();
           }
       
           @Override
           public String toString() {
      -        return getInnerCollection().toString();
      +        ValueCollectionValue value = getValue();
      +        if(value == null) {
      +            return "[]";
      +        }
      +        return value.toString();
           }
       
           @Override
           public int hashCode() {
               final int prime = 31;
               int result = 1;
      -        result = prime * result + ((getInnerCollection() == null) ? 0 : getInnerCollection().hashCode());
      +        ValueCollectionValue value = getValue();
      +        result = prime * result + ((value == null) ? 0 : getValue().hashCode());
               return result;
           }
       
      @@ -61,10 +81,12 @@ public abstract class AbstractValueCollectionSetting extends AbstractHasValue
                   return false;
               @SuppressWarnings("rawtypes")
               AbstractValueCollectionSetting other = (AbstractValueCollectionSetting) obj;
      -        if (getInnerCollection() == null) {
      -            if (other.getInnerCollection() != null)
      +        ValueCollectionValue value = getValue();
      +        ValueCollectionValue otherValue = other.getValue();
      +        if (value == null) {
      +            if (otherValue != null)
                       return false;
      -        } else if (!getInnerCollection().equals(other.getInnerCollection()))
      +        } else if (!value.equals(otherValue))
                   return false;
               return true;
           }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java
      index 7e7e64d6c70..ccb5831608a 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java
      @@ -1,34 +1,33 @@
       package com.sap.sse.common.settings.base;
       
      -import java.util.ArrayList;
      -import java.util.Collection;
       import java.util.List;
       
       import com.sap.sse.common.settings.AbstractSettings;
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.Value;
      +import com.sap.sse.common.settings.value.ValueCollectionValue;
      +import com.sap.sse.common.settings.value.ValueListValue;
       
      -public abstract class AbstractValueListSetting extends AbstractValueCollectionSetting {
      -    
      -    private final List values = new ArrayList<>();
      -    
      +public abstract class AbstractValueListSetting extends AbstractValueCollectionSetting> {
           public AbstractValueListSetting(String name, AbstractSettings settings, ValueConverter valueConverter) {
               super(name, settings, valueConverter);
           }
           
           @Override
      -    protected Collection getInnerCollection() {
      -        return values;
      +    protected ValueCollectionValue> createValue() {
      +        return new ValueListValue();
           }
           
           @Override
           public void resetToDefault() {
      -        values.clear();
      +        clear();
           }
           
           @Override
           public boolean isDefaultValue() {
      +        ValueCollectionValue> value = getValue();
               // explicit default values are possible to implement
               // currently, empty is always default
      -        return getInnerCollection().isEmpty();
      +        return value == null || value.isEmpty();
           }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java
      index c1d4c661d60..ddfab85a7be 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java
      @@ -1,6 +1,5 @@
       package com.sap.sse.common.settings.base;
       
      -import java.util.Collection;
       import java.util.Collections;
       import java.util.HashSet;
       import java.util.Set;
      @@ -9,10 +8,12 @@ import com.sap.sse.common.Util;
       import com.sap.sse.common.settings.AbstractSettings;
       import com.sap.sse.common.settings.ValueConverter;
       import com.sap.sse.common.settings.ValueSetSetting;
      +import com.sap.sse.common.settings.value.Value;
      +import com.sap.sse.common.settings.value.ValueCollectionValue;
      +import com.sap.sse.common.settings.value.ValueSetValue;
       
      -public abstract class AbstractValueSetSetting extends AbstractValueCollectionSetting implements ValueSetSetting {
      +public abstract class AbstractValueSetSetting extends AbstractValueCollectionSetting> implements ValueSetSetting {
           
      -    private final Set values = new HashSet<>();
           private final Set defaultValues = new HashSet<>();
           private final boolean emptyIsDefault;
           
      @@ -36,19 +37,21 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection
           }
           
           @Override
      -    protected Collection getInnerCollection() {
      -        return values;
      +    protected ValueCollectionValue> createValue() {
      +        return new ValueSetValue();
           }
           
           @Override
           public boolean isDefaultValue() {
      -        return (emptyIsDefault && values.isEmpty())
      -                || (values.size() == defaultValues.size() && values.containsAll(defaultValues));
      +        ValueCollectionValue> value = getValue();
      +        return (emptyIsDefault && value.isEmpty())
      +                || (value.size() == defaultValues.size() && defaultValues.containsAll(value.getValues(getValueConverter())));
           }
           
           @Override
           public Iterable getValues() {
      -        if(emptyIsDefault && values.isEmpty()) {
      +        ValueCollectionValue> value = getValue();
      +        if(emptyIsDefault && (value == null || value.isEmpty())) {
                   return Collections.unmodifiableCollection(defaultValues);
               }
               return super.getValues();
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java
      index 4312a9cf131..aad89328ab2 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java
      @@ -3,31 +3,35 @@ package com.sap.sse.common.settings.base;
       import com.sap.sse.common.settings.AbstractSettings;
       import com.sap.sse.common.settings.ValueConverter;
       import com.sap.sse.common.settings.ValueSetting;
      +import com.sap.sse.common.settings.value.Value;
       
       public abstract class AbstractValueSetting extends AbstractHasValueSetting implements ValueSetting {
           
           private T defaultValue;
      -    
      -    private T value;
       
           protected AbstractValueSetting(String name, AbstractSettings settings, T defaultValue, ValueConverter valueConverter) {
               super(name, settings, valueConverter);
               this.defaultValue = defaultValue;
      -        this.value = defaultValue;
      +        resetToDefault();
           }
      -
      +    
           @Override
           public T getValue() {
      -        return value;
      +        Value value = settings.getValue(settingName);
      +        if(value == null) {
      +            return null;
      +        }
      +        return getValueConverter().fromValue(value);
           }
       
           @Override
           public void setValue(T value) {
      -        this.value = value;
      +        settings.setValue(settingName, getValueConverter().toValue(value));
           }
       
           @Override
           public boolean isDefaultValue() {
      +        T value = getValue();
               if(value == defaultValue) {
                   return true;
               }
      @@ -40,18 +44,19 @@ public abstract class AbstractValueSetting extends AbstractHasValueSetting
           
           @Override
           public void resetToDefault() {
      -        this.value = defaultValue;
      +        setValue(defaultValue);
           }
           
           @Override
           public String toString() {
      -        return "" +  value;
      +        return "" +  getValue();
           }
       
           @Override
           public int hashCode() {
               final int prime = 31;
               int result = 1;
      +        T value = getValue();
               result = prime * result + ((value == null) ? 0 : value.hashCode());
               return result;
           }
      @@ -66,10 +71,12 @@ public abstract class AbstractValueSetting extends AbstractHasValueSetting
                   return false;
               @SuppressWarnings("rawtypes")
               AbstractValueSetting other = (AbstractValueSetting) obj;
      +        T value = getValue();
      +        Object otherValue = other.getValue();
               if (value == null) {
      -            if (other.value != null)
      +            if (otherValue != null)
                       return false;
      -        } else if (!value.equals(other.value))
      +        } else if (!value.equals(otherValue))
                   return false;
               return true;
           }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java
      index 9a81059a863..8fc805cb62c 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java
      @@ -1,11 +1,13 @@
       package com.sap.sse.common.settings.converter;
       
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.BooleanValue;
      +import com.sap.sse.common.settings.value.Value;
       
       public class BooleanConverter implements ValueConverter {
      -    
      +
           public static final BooleanConverter INSTANCE = new BooleanConverter();
      -    
      +
           private BooleanConverter() {
           }
       
      @@ -28,4 +30,14 @@ public class BooleanConverter implements ValueConverter {
           public Boolean fromStringValue(String stringValue) {
               return stringValue == null ? null : Boolean.valueOf(stringValue);
           }
      +
      +    @Override
      +    public Boolean fromValue(Value value) {
      +        return ((BooleanValue) value).getValue();
      +    }
      +
      +    @Override
      +    public Value toValue(Boolean value) {
      +        return new BooleanValue(value);
      +    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java
      index da905f2e8d4..81c702ea5c8 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java
      @@ -3,11 +3,13 @@ package com.sap.sse.common.settings.converter;
       import java.math.BigDecimal;
       
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.DecimalValue;
      +import com.sap.sse.common.settings.value.Value;
       
       public class DecimalConverter implements ValueConverter {
      -    
      +
           public static final DecimalConverter INSTANCE = new DecimalConverter();
      -    
      +
           private DecimalConverter() {
           }
       
      @@ -30,4 +32,14 @@ public class DecimalConverter implements ValueConverter {
           public BigDecimal fromStringValue(String stringValue) {
               return stringValue == null ? null : new BigDecimal(stringValue);
           }
      +
      +    @Override
      +    public BigDecimal fromValue(Value value) {
      +        return ((DecimalValue) value).getValue();
      +    }
      +
      +    @Override
      +    public Value toValue(BigDecimal value) {
      +        return new DecimalValue(value);
      +    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java
      index a8c0be66ac2..8f07748095a 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java
      @@ -1,11 +1,13 @@
       package com.sap.sse.common.settings.converter;
       
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.DoubleValue;
      +import com.sap.sse.common.settings.value.Value;
       
       public class DoubleConverter implements ValueConverter {
      -    
      +
           public static final DoubleConverter INSTANCE = new DoubleConverter();
      -    
      +
           private DoubleConverter() {
           }
       
      @@ -28,4 +30,14 @@ public class DoubleConverter implements ValueConverter {
           public Double fromStringValue(String stringValue) {
               return stringValue == null ? null : Double.valueOf(stringValue);
           }
      +
      +    @Override
      +    public Double fromValue(Value value) {
      +        return ((DoubleValue) value).getValue();
      +    }
      +
      +    @Override
      +    public Value toValue(Double value) {
      +        return new DoubleValue(value);
      +    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java
      index 672c56c3197..64c55bf8d53 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java
      @@ -2,6 +2,8 @@ package com.sap.sse.common.settings.converter;
       
       import com.sap.sse.common.settings.StringToEnumConverter;
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.StringValue;
      +import com.sap.sse.common.settings.value.Value;
       
       public class EnumConverter> implements ValueConverter {
       
      @@ -30,4 +32,14 @@ public class EnumConverter> implements ValueConverter {
           public T fromStringValue(String stringValue) {
               return stringValue == null ? null : stringToEnumConverter.fromString(stringValue);
           }
      +
      +    @Override
      +    public T fromValue(Value value) {
      +        return fromStringValue(((StringValue) value).getValue());
      +    }
      +
      +    @Override
      +    public Value toValue(T value) {
      +        return new StringValue(toStringValue(value));
      +    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java
      index 3e58eeb9e1d..d7397ad993e 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java
      @@ -1,11 +1,13 @@
       package com.sap.sse.common.settings.converter;
       
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.StringValue;
      +import com.sap.sse.common.settings.value.Value;
       
       public class StringConverter implements ValueConverter {
      -    
      +
           public static final StringConverter INSTANCE = new StringConverter();
      -    
      +
           private StringConverter() {
           }
       
      @@ -29,4 +31,13 @@ public class StringConverter implements ValueConverter {
               return stringValue;
           }
       
      +    @Override
      +    public String fromValue(Value value) {
      +        return ((StringValue) value).getValue();
      +    }
      +
      +    @Override
      +    public Value toValue(String value) {
      +        return new StringValue(value);
      +    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java
      index 9ef5c3e7044..e621c956d98 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java
      @@ -3,11 +3,13 @@ package com.sap.sse.common.settings.converter;
       import java.util.UUID;
       
       import com.sap.sse.common.settings.ValueConverter;
      +import com.sap.sse.common.settings.value.UUIDValue;
      +import com.sap.sse.common.settings.value.Value;
       
       public class UUIDConverter implements ValueConverter {
      -    
      +
           public static final UUIDConverter INSTANCE = new UUIDConverter();
      -    
      +
           private UUIDConverter() {
           }
       
      @@ -30,4 +32,14 @@ public class UUIDConverter implements ValueConverter {
           public UUID fromStringValue(String stringValue) {
               return stringValue == null ? null : UUID.fromString(stringValue);
           }
      +
      +    @Override
      +    public UUID fromValue(Value value) {
      +        return ((UUIDValue) value).getValue();
      +    }
      +
      +    @Override
      +    public Value toValue(UUID value) {
      +        return new UUIDValue(value);
      +    }
       }
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/AbstractValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/AbstractValue.java
      new file mode 100644
      index 00000000000..e2e55874ffd
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/AbstractValue.java
      @@ -0,0 +1,47 @@
      +package com.sap.sse.common.settings.value;
      +
      +public abstract class AbstractValue implements Value {
      +    private static final long serialVersionUID = -6645573771084361853L;
      +    private T value;
      +
      +    protected AbstractValue() {
      +    }
      +
      +    public AbstractValue(T value) {
      +        this.value = value;
      +    }
      +    
      +    public T getValue() {
      +        return value;
      +    }
      +
      +    @Override
      +    public int hashCode() {
      +        final int prime = 31;
      +        int result = 1;
      +        result = prime * result + ((value == null) ? 0 : value.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;
      +        AbstractValue other = (AbstractValue) obj;
      +        if (value == null) {
      +            if (other.value != null)
      +                return false;
      +        } else if (!value.equals(other.value))
      +            return false;
      +        return true;
      +    }
      +    
      +    @Override
      +    public String toString() {
      +        return "" + value;
      +    }
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/BooleanValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/BooleanValue.java
      new file mode 100644
      index 00000000000..244005e57c6
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/BooleanValue.java
      @@ -0,0 +1,13 @@
      +package com.sap.sse.common.settings.value;
      +
      +public class BooleanValue extends AbstractValue {
      +    private static final long serialVersionUID = -4737742445276300510L;
      +
      +    protected BooleanValue() {
      +    }
      +
      +    public BooleanValue(Boolean value) {
      +        super(value);
      +    }
      +
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DecimalValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DecimalValue.java
      new file mode 100644
      index 00000000000..5d2b8a63f86
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DecimalValue.java
      @@ -0,0 +1,15 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.math.BigDecimal;
      +
      +public class DecimalValue extends AbstractValue {
      +    private static final long serialVersionUID = -2607692358788082588L;
      +
      +    protected DecimalValue() {
      +    }
      +
      +    public DecimalValue(BigDecimal value) {
      +        super(value);
      +    }
      +
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DoubleValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DoubleValue.java
      new file mode 100644
      index 00000000000..431fd4a1932
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/DoubleValue.java
      @@ -0,0 +1,13 @@
      +package com.sap.sse.common.settings.value;
      +
      +public class DoubleValue extends AbstractValue {
      +    private static final long serialVersionUID = -615238608843879977L;
      +
      +    protected DoubleValue() {
      +    }
      +
      +    public DoubleValue(Double value) {
      +        super(value);
      +    }
      +
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsListValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsListValue.java
      new file mode 100644
      index 00000000000..decbc97a900
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsListValue.java
      @@ -0,0 +1,23 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.util.HashMap;
      +
      +public class SettingsListValue {
      +    
      +    private HashMap values = new HashMap<>();
      +    
      +    public SettingsListValue() {
      +    }
      +
      +    public Value getValue(String name) {
      +        return values.get(name);
      +    }
      +    
      +    public void setValue(String name, Value value) {
      +        if(value == null) {
      +            values.remove(name);
      +        } else {
      +            values.put(name, value);
      +        }
      +    }
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsValue.java
      new file mode 100644
      index 00000000000..3b5f984465b
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/SettingsValue.java
      @@ -0,0 +1,53 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.util.HashMap;
      +
      +public class SettingsValue implements Value {
      +    private static final long serialVersionUID = -3407605464729611500L;
      +    private HashMap values = new HashMap<>();
      +    
      +    public SettingsValue() {
      +    }
      +
      +    public Value getValue(String name) {
      +        return values.get(name);
      +    }
      +    
      +    public void setValue(String name, Value value) {
      +        if(value == null) {
      +            values.remove(name);
      +        } else {
      +            values.put(name, value);
      +        }
      +    }
      +
      +    @Override
      +    public int hashCode() {
      +        final int prime = 31;
      +        int result = 1;
      +        result = prime * result + ((values == null) ? 0 : values.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;
      +        SettingsValue other = (SettingsValue) obj;
      +        if (values == null) {
      +            if (other.values != null)
      +                return false;
      +        } else if (!values.equals(other.values))
      +            return false;
      +        return true;
      +    }
      +    
      +    @Override
      +    public String toString() {
      +        return values.toString();
      +    }
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/StringValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/StringValue.java
      new file mode 100644
      index 00000000000..8ffc58d806b
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/StringValue.java
      @@ -0,0 +1,13 @@
      +package com.sap.sse.common.settings.value;
      +
      +public class StringValue extends AbstractValue {
      +    private static final long serialVersionUID = 4405912516159515483L;
      +
      +    protected StringValue() {
      +    }
      +
      +    public StringValue(String value) {
      +        super(value);
      +    }
      +
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/UUIDValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/UUIDValue.java
      new file mode 100644
      index 00000000000..6431ca75c5f
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/UUIDValue.java
      @@ -0,0 +1,15 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.util.UUID;
      +
      +public class UUIDValue extends AbstractValue {
      +    private static final long serialVersionUID = 4218811543529632907L;
      +
      +    protected UUIDValue() {
      +    }
      +
      +    public UUIDValue(UUID value) {
      +        super(value);
      +    }
      +
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/Value.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/Value.java
      new file mode 100644
      index 00000000000..edeaaff1d0b
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/Value.java
      @@ -0,0 +1,6 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.io.Serializable;
      +
      +public interface Value extends Serializable {
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java
      new file mode 100644
      index 00000000000..e321ae5f926
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java
      @@ -0,0 +1,13 @@
      +package com.sap.sse.common.settings.value;
      +
      +import com.sap.sse.common.settings.ValueConverter;
      +
      +public interface ValueCollection extends Value {
      +     Iterable getValues(ValueConverter converter);
      +
      +     void setValues(Iterable values, ValueConverter converter);
      +
      +     void addValue(T value, ValueConverter converter);
      +
      +    void clear();
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java
      new file mode 100644
      index 00000000000..8c6452fe7a9
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java
      @@ -0,0 +1,92 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.util.Collection;
      +import java.util.Collections;
      +
      +import com.sap.sse.common.settings.ValueConverter;
      +
      +public abstract class ValueCollectionValue> implements ValueCollection {
      +    private static final long serialVersionUID = -5820765644801217519L;
      +    private C values;
      +    
      +    protected ValueCollectionValue(C values) {
      +        this.values = values;
      +    }
      +    
      +    protected abstract  Collection emptyCollection();
      +    
      +    @Override
      +    public  Collection getValues(ValueConverter converter) {
      +        Collection result = emptyCollection();
      +        for (Value value : values) {
      +            result.add(converter.fromValue(value));
      +        }
      +        return result;
      +    }
      +    
      +    public Iterable getValueObjects() {
      +        return Collections.unmodifiableCollection(values);
      +    }
      +    
      +    @Override
      +    public  void setValues(Iterable values, ValueConverter converter) {
      +        clear();
      +        if(values != null) {
      +            for (T value : values) {
      +                addValue(value, converter);
      +            }
      +        }
      +    }
      +    
      +    @Override
      +    public void clear() {
      +        this.values.clear();
      +    }
      +    
      +    @Override
      +    public  void addValue(T value, ValueConverter converter) {
      +        this.values.add(converter.toValue(value));
      +    }
      +    
      +    public  void addValue(Value value) {
      +        this.values.add(value);
      +    }
      +
      +    public boolean isEmpty() {
      +        return values.isEmpty();
      +    }
      +
      +    public int size() {
      +        return values.size();
      +    }
      +
      +    @Override
      +    public int hashCode() {
      +        final int prime = 31;
      +        int result = 1;
      +        result = prime * result + ((values == null) ? 0 : values.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;
      +        ValueCollectionValue other = (ValueCollectionValue) obj;
      +        if (values == null) {
      +            if (other.values != null)
      +                return false;
      +        } else if (!values.equals(other.values))
      +            return false;
      +        return true;
      +    }
      +    
      +    @Override
      +    public String toString() {
      +        return values.toString();
      +    }
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueListValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueListValue.java
      new file mode 100644
      index 00000000000..1172a1d75a6
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueListValue.java
      @@ -0,0 +1,18 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.util.ArrayList;
      +import java.util.Collection;
      +import java.util.List;
      +
      +public class ValueListValue extends ValueCollectionValue> {
      +    private static final long serialVersionUID = -5820765644801217519L;
      +    
      +    public ValueListValue() {
      +        super(new ArrayList());
      +    }
      +    
      +    @Override
      +    protected  Collection emptyCollection() {
      +        return new ArrayList<>();
      +    }
      +}
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueSetValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueSetValue.java
      new file mode 100644
      index 00000000000..bb1fd4fd7ed
      --- /dev/null
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueSetValue.java
      @@ -0,0 +1,18 @@
      +package com.sap.sse.common.settings.value;
      +
      +import java.util.Collection;
      +import java.util.HashSet;
      +import java.util.Set;
      +
      +public class ValueSetValue extends ValueCollectionValue> {
      +    private static final long serialVersionUID = -5820765644801217519L;
      +    
      +    public ValueSetValue() {
      +        super(new HashSet());
      +    }
      +    
      +    @Override
      +    protected  Collection emptyCollection() {
      +        return new HashSet<>();
      +    }
      +}
      diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      index 6dd52eedbbd..9c3b60bffbc 100644
      --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      @@ -23,22 +23,32 @@ import com.sap.sse.common.settings.StringToEnumConverter;
       public abstract class AbstractSettingsSerializationTest {
       
           private static class TestOuterSettings extends AbstractSettings {
      -        private SimpleTestSettings nested = new SimpleTestSettings("nested", this);
      +        private SimpleTestSettings nested;
       
               public TestOuterSettings() {
               }
      +        
      +        @Override
      +        protected void addChildSettings() {
      +            nested = new SimpleTestSettings("nested", this);
      +        }
           }
       
           private static class TestListSettings extends AbstractSettings {
      -        private SettingsList l = new SettingsList<>("l", this, SimpleTestSettings::new);
      +        private SettingsList l;
       
               public TestListSettings() {
               }
      +        
      +        @Override
      +        protected void addChildSettings() {
      +            l = new SettingsList<>("l", this, SimpleTestSettings::new);
      +        }
           }
       
           private static class SimpleTestSettings extends AbstractSettings {
      -        private final StringSetting string = new StringSetting("string", this);
      -        private final DecimalSetting num = new DecimalSetting("num", this);
      +        private StringSetting string;
      +        private DecimalSetting num;
       
               public SimpleTestSettings() {
               }
      @@ -51,6 +61,12 @@ public abstract class AbstractSettingsSerializationTest {
               public SimpleTestSettings(String name, AbstractSettings parent) {
                   super(name, parent);
               }
      +        
      +        @Override
      +        protected void addChildSettings() {
      +            string = new StringSetting("string", this);
      +            num = new DecimalSetting("num", this);
      +        }
           }
       
           private static class TestSettings extends AbstractSettings {
      
      From d9dad10d1f982f637c6913046725ff81af7ff9c0 Mon Sep 17 00:00:00 2001
      From: Steffen Schaefer 
      Date: Wed, 13 Apr 2016 16:21:42 +0200
      Subject: [PATCH 052/259] Moved some settings to the new scheme for defining
       child settings
      
      ---
       .../RegattaOverviewBaseSettings.java          | 10 ++++--
       .../RegattaRaceStatesSettings.java            | 17 ++++++---
       .../AbstractSettingsSerializationTest.java    | 35 +++++++++++++------
       3 files changed, 44 insertions(+), 18 deletions(-)
      
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java
      index bd8ee02fcc5..536d6190d24 100644
      --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java
      @@ -7,8 +7,8 @@ import com.sap.sse.common.settings.BooleanSetting;
       import com.sap.sse.common.settings.UUIDSetting;
       
       public final class RegattaOverviewBaseSettings extends AbstractSettings {
      -    private final UUIDSetting event = new UUIDSetting("event", this);
      -    private final BooleanSetting ignoreLocalSettings = new BooleanSetting("ignoreLocalSettings", this, false);
      +    private UUIDSetting event;
      +    private BooleanSetting ignoreLocalSettings;
       
           public RegattaOverviewBaseSettings() {
           }
      @@ -21,6 +21,12 @@ public final class RegattaOverviewBaseSettings extends AbstractSettings {
               this(event, true);
           }
           
      +    @Override
      +    protected void addChildSettings() {
      +        event = new UUIDSetting("event", this);
      +        ignoreLocalSettings = new BooleanSetting("ignoreLocalSettings", this, false);
      +    }
      +    
           public RegattaOverviewBaseSettings(UUID event, boolean ignoreLocalSettings) {
               this.event.setValue(event);
               this.ignoreLocalSettings.setValue(ignoreLocalSettings);
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java
      index f502da8a04d..58c6314f494 100644
      --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java
      @@ -13,11 +13,10 @@ import com.sap.sse.common.settings.StringSetSetting;
       import com.sap.sse.common.settings.UUIDSetSetting;
       
       public final class RegattaRaceStatesSettings extends AbstractSettings {
      -    private final UUIDSetSetting visibleCourseAreas = new UUIDSetSetting("visibleCourseAreas", this, true);
      -    private final StringSetSetting visibleRegattas = new StringSetSetting("visibleRegattas", this, true);
      -    private final BooleanSetting showOnlyRacesOfSameDay = new BooleanSetting("showOnlyRacesOfSameDay", this, false);
      -    private final BooleanSetting showOnlyCurrentlyRunningRaces = new BooleanSetting("showOnlyCurrentlyRunningRaces",
      -            this, true);
      +    private UUIDSetSetting visibleCourseAreas;
      +    private StringSetSetting visibleRegattas;
      +    private BooleanSetting showOnlyRacesOfSameDay;
      +    private BooleanSetting showOnlyCurrentlyRunningRaces;
       
           public RegattaRaceStatesSettings() {
           }
      @@ -36,6 +35,14 @@ public final class RegattaRaceStatesSettings extends AbstractSettings {
               this.showOnlyRacesOfSameDay.setValue(showOnlyRacesOfSameDay);
               this.showOnlyCurrentlyRunningRaces.setValue(showOnlyCurrentlyRunningRaces);
           }
      +    
      +    @Override
      +    protected void addChildSettings() {
      +        visibleCourseAreas = new UUIDSetSetting("visibleCourseAreas", this, true);
      +        visibleRegattas = new StringSetSetting("visibleRegattas", this, true);
      +        showOnlyRacesOfSameDay = new BooleanSetting("showOnlyRacesOfSameDay", this, false);
      +        showOnlyCurrentlyRunningRaces = new BooleanSetting("showOnlyCurrentlyRunningRaces", this, true);
      +    }
       
           public Iterable getVisibleCourseAreas() {
               return visibleCourseAreas.getValues();
      diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      index 9c3b60bffbc..1c8082c38e5 100644
      --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      @@ -82,28 +82,41 @@ public abstract class AbstractSettingsSerializationTest {
           }
       
           private static class TestEnumListSettings extends AbstractSettings {
      -        private final EnumListSetting l = new EnumListSetting<>("l", this,
      -                new StringToEnumConverter() {
      -                    @Override
      -                    public Operators fromString(String stringValue) {
      -                        return TextOperator.Operators.valueOf(stringValue);
      -                    }
      -                });
      +        private EnumListSetting l;
       
      -        public TestEnumListSettings() {
      +        @Override
      +        protected void addChildSettings() {
      +            l = new EnumListSetting<>("l", this,
      +                    new StringToEnumConverter() {
      +                @Override
      +                public Operators fromString(String stringValue) {
      +                    return TextOperator.Operators.valueOf(stringValue);
      +                }
      +            });
               }
           }
       
           private static class DuplicateFieldSettings extends AbstractSettings {
               @SuppressWarnings("unused")
      -        private final StringSetting humba = new StringSetting("humba", this);
      +        private StringSetting humba;
               @SuppressWarnings("unused")
      -        private final DecimalSetting bumba = new DecimalSetting("humba", this);
      +        private DecimalSetting bumba;
      +        
      +        @Override
      +        protected void addChildSettings() {
      +            humba = new StringSetting("humba", this);
      +            bumba = new DecimalSetting("humba", this);
      +        }
           }
           
           private static class DisallowedKeySettings extends AbstractSettings {
               @SuppressWarnings("unused")
      -        private final StringSetting disallowedKey= new StringSetting("disallowed.key", this);
      +        private StringSetting disallowedKey;
      +        
      +        @Override
      +        protected void addChildSettings() {
      +            disallowedKey= new StringSetting("disallowed.key", this);
      +        }
           }
       
           protected abstract  SOT serialize(T settings) throws Exception;
      
      From 90835ffce179106ae8812835baa9b566a880251c Mon Sep 17 00:00:00 2001
      From: Benjamin Barth 
      Date: Mon, 18 Apr 2016 15:05:00 +0200
      Subject: [PATCH 053/259] Added new tab for user preferences which dummy
       content
      
      ---
       .../TabletAndDesktopUserProfileView.ui.xml    |  3 ++
       .../UserProfilePreferencesPresenter.java      | 31 ++++++++++++
       .../UserProfilePreferencesTabView.java        | 50 +++++++++++++++++++
       .../UserProfilePreferencesView.java           | 18 +++++++
       .../UserProfilePreferencesViewImpl.java       | 39 +++++++++++++++
       .../UserProfilePreferencesViewImpl.ui.xml     | 13 +++++
       .../shared/app/ApplicationHistoryMapper.java  |  2 +
       .../shared/places/PlaceTokenPrefixes.java     |  1 +
       .../profile/UserProfilePreferencesPlace.java  | 17 +++++++
       9 files changed, 174 insertions(+)
       create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java
       create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java
       create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java
       create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java
       create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml
       create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/UserProfilePreferencesPlace.java
      
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml
      index 0798d2ce2cc..829bc95e3e5 100644
      --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml
      @@ -45,6 +45,9 @@
             
               
             
      +      
      +        
      +      
           
         
        
      \ No newline at end of file
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java
      new file mode 100644
      index 00000000000..5c6eda77a73
      --- /dev/null
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java
      @@ -0,0 +1,31 @@
      +package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab;
      +
      +import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
      +import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
      +
      +public class UserProfilePreferencesPresenter implements UserProfilePreferencesView.Presenter {
      +
      +    private final UserProfilePreferencesView view;
      +    private final UserProfileView.Presenter userProfilePresenter;
      +//    private final UserDetailsPresenter userDetailsPresenter;
      +
      +    public UserProfilePreferencesPresenter(UserProfilePreferencesView view, UserProfileView.Presenter userProfilePresenter) {
      +        this.view = view;
      +        this.userProfilePresenter = userProfilePresenter;
      +        view.setPresenter(this);
      +//        this.userDetailsPresenter = new UserDetailsPresenter(view.getUserDetailsView(),
      +//                userProfilePresenter.getAuthenticationManager(), userProfilePresenter.getUserManagementService(),
      +//                userProfilePresenter.getMailVerifiedUrl());
      +    }
      +
      +    @Override
      +    public void setAuthenticationContext(AuthenticationContext authenticationContext) {
      +        view.getDecorator().setAuthenticationContext(authenticationContext);
      +//        userDetailsPresenter.setAuthenticationContext(authenticationContext);
      +    }
      +    
      +    @Override
      +    public void doTriggerLoginForm() {
      +        userProfilePresenter.doTriggerLoginForm();
      +    }
      +}
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java
      new file mode 100644
      index 00000000000..5429da2ac33
      --- /dev/null
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java
      @@ -0,0 +1,50 @@
      +package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab;
      +
      +import com.google.gwt.user.client.ui.AcceptsOneWidget;
      +import com.google.gwt.user.client.ui.Composite;
      +import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
      +import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileTabView;
      +import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
      +import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace;
      +import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
      +
      +public class UserProfilePreferencesTabView extends Composite implements UserProfileTabView {
      +
      +    private UserProfilePreferencesView.Presenter currentPresenter;
      +    private UserProfilePreferencesView view;
      +
      +    @Override
      +    public Class getPlaceClassForActivation() {
      +        return UserProfilePreferencesPlace.class;
      +    }
      +
      +    @Override
      +    public TabView.State getState() {
      +        return TabView.State.VISIBLE;
      +    }
      +
      +    @Override
      +    public void start(UserProfilePreferencesPlace myPlace, AcceptsOneWidget contentArea) {
      +        contentArea.setWidget(view);
      +    }
      +    
      +    @Override
      +    public void setAuthenticationContext(AuthenticationContext authenticationContext) {
      +        currentPresenter.setAuthenticationContext(authenticationContext);
      +    }
      +
      +    @Override
      +    public void stop() {
      +    }
      +
      +    @Override
      +    public UserProfilePreferencesPlace placeToFire() {
      +        return new UserProfilePreferencesPlace();
      +    }
      +
      +    @Override
      +    public void setPresenter(UserProfileView.Presenter currentPresenter) {
      +        view = new UserProfilePreferencesViewImpl();
      +        this.currentPresenter = new UserProfilePreferencesPresenter(view, currentPresenter);
      +    }
      +}
      \ No newline at end of file
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java
      new file mode 100644
      index 00000000000..a7b9e97d81c
      --- /dev/null
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java
      @@ -0,0 +1,18 @@
      +package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab;
      +
      +import com.google.gwt.user.client.ui.IsWidget;
      +import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
      +import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
      +import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView;
      +
      +public interface UserProfilePreferencesView extends IsWidget {
      +
      +    void setPresenter(Presenter presenter);
      +    
      +    UserDetailsView getUserDetailsView();
      +    
      +    NeedsAuthenticationContext getDecorator();
      +
      +    public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext {
      +    }
      +}
      \ No newline at end of file
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java
      new file mode 100644
      index 00000000000..03bf83ea709
      --- /dev/null
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java
      @@ -0,0 +1,39 @@
      +package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab;
      +
      +import com.google.gwt.core.client.GWT;
      +import com.google.gwt.uibinder.client.UiBinder;
      +import com.google.gwt.uibinder.client.UiField;
      +import com.google.gwt.user.client.ui.Composite;
      +import com.google.gwt.user.client.ui.Widget;
      +import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop;
      +import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
      +import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView;
      +
      +/**
      + * Created by pgtaboada on 25.11.14.
      + */
      +public class UserProfilePreferencesViewImpl extends Composite implements UserProfilePreferencesView {
      +
      +    interface MyBinder extends UiBinder {
      +    }
      +
      +    private static MyBinder ourUiBinder = GWT.create(MyBinder.class);
      +
      +    @UiField(provided = true)
      +    AuthorizedContentDecoratorDesktop decoratorUi;
      +    
      +    public UserDetailsView getUserDetailsView() {
      +        return null;
      +    }
      +    
      +    @Override
      +    public void setPresenter(Presenter presenter) {
      +        decoratorUi = new AuthorizedContentDecoratorDesktop(presenter);
      +        initWidget(ourUiBinder.createAndBindUi(this));
      +    }
      +    
      +    @Override
      +    public NeedsAuthenticationContext getDecorator() {
      +        return decoratorUi;
      +    }
      +}
      \ No newline at end of file
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml
      new file mode 100644
      index 00000000000..d86460496cd
      --- /dev/null
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml
      @@ -0,0 +1,13 @@
      +
      +    
      +    
      +    
      +    
      +    
      +        
      +            TODO
      +       
      +    
      +
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java
      index cfb4f3f68a1..410dae97e84 100755
      --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java
      @@ -37,6 +37,7 @@ import com.sap.sailing.gwt.home.shared.places.user.confirmation.ConfirmationPlac
       import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetPlace;
       import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDefaultPlace;
       import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDetailsPlace;
      +import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace;
       
       @WithTokenizers({ AboutUsPlace.Tokenizer.class, ContactPlace.Tokenizer.class, EventPlace.Tokenizer.class,
               EventsPlace.Tokenizer.class, SolutionsPlace.Tokenizer.class, WhatsNewPlace.Tokenizer.class,
      @@ -70,6 +71,7 @@ import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDetailsPla
               // User management places:
               UserProfileDefaultPlace.Tokenizer.class,
               UserProfileDetailsPlace.Tokenizer.class,
      +        UserProfilePreferencesPlace.Tokenizer.class,
               AuthenticationPlace.Tokenizer.class,
               ConfirmationPlace.Tokenizer.class,
               PasswordResetPlace.Tokenizer.class,
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/PlaceTokenPrefixes.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/PlaceTokenPrefixes.java
      index 301f6a4fa67..fe69be3e459 100644
      --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/PlaceTokenPrefixes.java
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/PlaceTokenPrefixes.java
      @@ -25,6 +25,7 @@ public class PlaceTokenPrefixes {
           public static final String Imprint = "/imprint/";
           public static final String UserProfileDefault = "/user/profile/";
           public static final String UserProfileDetails = "/user/profile/details/";
      +    public static final String UserProfilePreferences = "/user/profile/preferences/";
           public static final String UserConfirmation = "/user/confirmation/";
           public static final String UserPasswordReset = "/user/passwordreset/";
           public static final String UserAuthentication = "/user/auth/";
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/UserProfilePreferencesPlace.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/UserProfilePreferencesPlace.java
      new file mode 100644
      index 00000000000..7d0007f3fe9
      --- /dev/null
      +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/UserProfilePreferencesPlace.java
      @@ -0,0 +1,17 @@
      +package com.sap.sailing.gwt.home.shared.places.user.profile;
      +
      +import com.google.gwt.place.shared.Prefix;
      +import com.sap.sailing.gwt.home.shared.app.HasMobileVersion;
      +import com.sap.sailing.gwt.home.shared.places.PlaceTokenPrefixes;
      +
      +
      +public class UserProfilePreferencesPlace extends AbstractUserProfilePlace implements HasMobileVersion {
      +
      +    @Prefix(PlaceTokenPrefixes.UserProfilePreferences)
      +    public static class Tokenizer extends AbstractUserProfilePlace.Tokenizer {
      +        @Override
      +        protected UserProfilePreferencesPlace getRealPlace() {
      +            return new UserProfilePreferencesPlace();
      +        }
      +    }
      +}
      
      From 963a7ed5638a413c3de47e5d5147376e88dae878 Mon Sep 17 00:00:00 2001
      From: Steffen Schaefer 
      Date: Tue, 19 Apr 2016 08:31:40 +0200
      Subject: [PATCH 054/259] Child settings are transient for efficient
       serialization
      
      ---
       .../AbstractSettingsSerializationTest.java    | 24 +++++++++----------
       1 file changed, 12 insertions(+), 12 deletions(-)
      
      diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      index 1c8082c38e5..3a0e3fd27d6 100644
      --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      @@ -23,7 +23,7 @@ import com.sap.sse.common.settings.StringToEnumConverter;
       public abstract class AbstractSettingsSerializationTest {
       
           private static class TestOuterSettings extends AbstractSettings {
      -        private SimpleTestSettings nested;
      +        private transient SimpleTestSettings nested;
       
               public TestOuterSettings() {
               }
      @@ -35,7 +35,7 @@ public abstract class AbstractSettingsSerializationTest {
           }
       
           private static class TestListSettings extends AbstractSettings {
      -        private SettingsList l;
      +        private transient SettingsList l;
       
               public TestListSettings() {
               }
      @@ -47,8 +47,8 @@ public abstract class AbstractSettingsSerializationTest {
           }
       
           private static class SimpleTestSettings extends AbstractSettings {
      -        private StringSetting string;
      -        private DecimalSetting num;
      +        private transient StringSetting string;
      +        private transient DecimalSetting num;
       
               public SimpleTestSettings() {
               }
      @@ -70,12 +70,12 @@ public abstract class AbstractSettingsSerializationTest {
           }
       
           private static class TestSettings extends AbstractSettings {
      -        private final StringSetting humba = new StringSetting("humba", this);
      -        private final BooleanSetting bumpa = new BooleanSetting("bumpa", this);
      -        private final EnumSetting trala = new EnumSetting<>("trala", this,
      +        private transient final StringSetting humba = new StringSetting("humba", this);
      +        private transient final BooleanSetting bumpa = new BooleanSetting("bumpa", this);
      +        private transient final EnumSetting trala = new EnumSetting<>("trala", this,
                       TextOperator.Operators::valueOf);
      -        private final DecimalSetting num = new DecimalSetting("num", this);
      -        private final DecimalListSetting l = new DecimalListSetting("l", this);
      +        private transient final DecimalSetting num = new DecimalSetting("num", this);
      +        private transient final DecimalListSetting l = new DecimalListSetting("l", this);
       
               public TestSettings() {
               }
      @@ -98,9 +98,9 @@ public abstract class AbstractSettingsSerializationTest {
       
           private static class DuplicateFieldSettings extends AbstractSettings {
               @SuppressWarnings("unused")
      -        private StringSetting humba;
      +        private transient StringSetting humba;
               @SuppressWarnings("unused")
      -        private DecimalSetting bumba;
      +        private transient DecimalSetting bumba;
               
               @Override
               protected void addChildSettings() {
      @@ -111,7 +111,7 @@ public abstract class AbstractSettingsSerializationTest {
           
           private static class DisallowedKeySettings extends AbstractSettings {
               @SuppressWarnings("unused")
      -        private StringSetting disallowedKey;
      +        private transient StringSetting disallowedKey;
               
               @Override
               protected void addChildSettings() {
      
      From 8253ae657fd2515d9fcceca02d747df4d576bad1 Mon Sep 17 00:00:00 2001
      From: Steffen Schaefer 
      Date: Tue, 19 Apr 2016 08:32:04 +0200
      Subject: [PATCH 055/259] Fixed broken test
      
      ---
       .../shared/android/test/AbstractSettingsSerializationTest.java | 3 +++
       1 file changed, 3 insertions(+)
      
      diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      index 3a0e3fd27d6..5c2ef4646e0 100644
      --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java
      @@ -83,6 +83,9 @@ public abstract class AbstractSettingsSerializationTest {
       
           private static class TestEnumListSettings extends AbstractSettings {
               private EnumListSetting l;
      +        
      +        public TestEnumListSettings() {
      +        }
       
               @Override
               protected void addChildSettings() {
      
      From 80021e1dd8cfef3e7ac6fb9b2028478a58e07bdc Mon Sep 17 00:00:00 2001
      From: Steffen Schaefer 
      Date: Tue, 19 Apr 2016 08:44:01 +0200
      Subject: [PATCH 056/259] Removed unused class
      
      ---
       .../common/settings/base/AbstractListSetting.java | 15 ---------------
       1 file changed, 15 deletions(-)
       delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java
      
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java
      deleted file mode 100644
      index 061c499ca71..00000000000
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractListSetting.java
      +++ /dev/null
      @@ -1,15 +0,0 @@
      -package com.sap.sse.common.settings.base;
      -
      -import com.sap.sse.common.settings.AbstractSetting;
      -import com.sap.sse.common.settings.AbstractSettings;
      -import com.sap.sse.common.settings.CollectionSetting;
      -
      -public abstract class AbstractListSetting extends AbstractSetting implements CollectionSetting {
      -    
      -    public AbstractListSetting(String name, AbstractSettings settings) {
      -        super(name, settings);
      -    }
      -    
      -    public AbstractListSetting() {
      -    }
      -}
      
      From f3dd6e177447ffb65f1fa6135eeb522d218ccaf8 Mon Sep 17 00:00:00 2001
      From: Steffen Schaefer 
      Date: Tue, 19 Apr 2016 08:44:40 +0200
      Subject: [PATCH 057/259] Updated JavaDocs to reflect the current development
       state
      
      ---
       .../sse/common/settings/AbstractSettings.java | 44 ++++++++++++++++---
       1 file changed, 37 insertions(+), 7 deletions(-)
      
      diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java
      index be3124c602a..d8c846647df 100644
      --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java
      +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java
      @@ -17,17 +17,22 @@ import com.sap.sse.common.settings.value.Value;
        * 
        * 
        * public final class ExampleSettings extends AbstractSettings {
      - *     private final StringSetting myString = new UUIDSetting("myString", this);
      - *     private final BooleanSetting myBoolean = new BooleanSetting("myBoolean", this);
      + *     private transient StringSetting myString;
      + *     private transient BooleanSetting myBoolean;
        *     
        *     // Used to create instances for a component
      - *     public RegattaOverviewBaseSettings() {
      + *     public ExampleSettings() {
        *     }
        *     
        *     // Used to create nested settings
      - *     public RegattaOverviewBaseSettings(String name, AbstractSettings settings) {
      - *         this.event.setValue(event);
      - *         this.ignoreLocalSettings.setValue(ignoreLocalSettings);
      + *     public ExampleSettings(String name, AbstractSettings parentSettings) {
      + *         super(name, parentSettings);
      + *     }
      + *     
      + *     @Override
      + *     protected void addChildSettings() {
      + *         myString = new UUIDSetting("myString", this)
      + *         myBoolean = new BooleanSetting("myBoolean", this);
        *     }
        *     
        *     public String getMyString() {
      @@ -49,6 +54,13 @@ import com.sap.sse.common.settings.value.Value;
        * 
        * 
      * + * To correctly support several kinds of Serialization (Java, GWT and Custom), you need to ensure the following: + *
        + *
      • the Settings class must have a default constructor
      • + *
      • child settings fields need to be transient
      • + *
      • child settings instances must be initialized in {@link #addChildSettings()} method
      • + *
      + * * If a custom Settings class only has {@link Setting} oder {@link Settings} children that are correctly attached by * calling their constructor with a name and the parent {@link Settings} you do not need to implement * {@link #hashCode()}, {@link #equals(Object)} and {@link #toString()}. There are generic implementations of those methods that are @@ -60,11 +72,20 @@ public abstract class AbstractSettings extends AbstractSetting implements Settin private SettingsValue value; private transient Map childSettings = new HashMap<>(); + /** + * Default constructor for direct instantiation of root settings objects. + */ public AbstractSettings() { value = new SettingsValue(); addChildSettings(); } + /** + * Constructor for automatic attachment of a child settings object to its parent settings object. + * + * @param name the name of the child setting + * @param settings the parent settings to attach this settings object to + */ public AbstractSettings(String name, AbstractSettings settings) { super(name, settings); value = (SettingsValue) settings.getValue(name); @@ -76,6 +97,9 @@ public abstract class AbstractSettings extends AbstractSetting implements Settin addChildSettings(); } + /** + * Internal use only for correct lifecycle of {@link SettingsList}. + */ protected void adoptValue(SettingsValue value) { this.value = value; } @@ -90,7 +114,13 @@ public abstract class AbstractSettings extends AbstractSetting implements Settin addChildSettings(); } - // TODO make abstract when all Settings are ported to the new system + /** + * Overwrite this method to initialize child settings. + * {@link AbstractSettings} for an example. + * + * TODO make abstract when all Settings are ported to the new system + * + */ protected void addChildSettings() { } From 5e79321ed506cc99665aeb841bf5b2216f501dda Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Apr 2016 09:00:14 +0200 Subject: [PATCH 058/259] Test settings objects are now all serializable --- .../AbstractSettingsSerializationTest.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java index 5c2ef4646e0..914d1990029 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java @@ -2,6 +2,7 @@ package com.sap.sse.shared.android.test; import static org.junit.Assert.assertEquals; +import java.io.Serializable; import java.math.BigDecimal; import java.util.Arrays; @@ -22,7 +23,8 @@ import com.sap.sse.common.settings.StringToEnumConverter; public abstract class AbstractSettingsSerializationTest { - private static class TestOuterSettings extends AbstractSettings { + private static class TestOuterSettings extends AbstractSettings implements Serializable { + private static final long serialVersionUID = -7379232503773525915L; private transient SimpleTestSettings nested; public TestOuterSettings() { @@ -34,7 +36,8 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestListSettings extends AbstractSettings { + private static class TestListSettings extends AbstractSettings implements Serializable { + private static final long serialVersionUID = 6919127895749914961L; private transient SettingsList l; public TestListSettings() { @@ -46,7 +49,8 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class SimpleTestSettings extends AbstractSettings { + private static class SimpleTestSettings extends AbstractSettings implements Serializable { + private static final long serialVersionUID = -4134836978411240572L; private transient StringSetting string; private transient DecimalSetting num; @@ -69,7 +73,8 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestSettings extends AbstractSettings { + private static class TestSettings extends AbstractSettings implements Serializable { + private static final long serialVersionUID = -611806711715538293L; private transient final StringSetting humba = new StringSetting("humba", this); private transient final BooleanSetting bumpa = new BooleanSetting("bumpa", this); private transient final EnumSetting trala = new EnumSetting<>("trala", this, @@ -81,8 +86,9 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestEnumListSettings extends AbstractSettings { - private EnumListSetting l; + private static class TestEnumListSettings extends AbstractSettings implements Serializable { + private static final long serialVersionUID = 93688955681544920L; + private transient EnumListSetting l; public TestEnumListSettings() { } @@ -99,7 +105,8 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class DuplicateFieldSettings extends AbstractSettings { + private static class DuplicateFieldSettings extends AbstractSettings implements Serializable { + private static final long serialVersionUID = 4058775568295038177L; @SuppressWarnings("unused") private transient StringSetting humba; @SuppressWarnings("unused") @@ -112,7 +119,8 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class DisallowedKeySettings extends AbstractSettings { + private static class DisallowedKeySettings extends AbstractSettings implements Serializable { + private static final long serialVersionUID = -2265305217290147424L; @SuppressWarnings("unused") private transient StringSetting disallowedKey; From 30a565bf3ce6770a0b3fbba0ae0442809a9028ac Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Apr 2016 09:32:10 +0200 Subject: [PATCH 059/259] Adjusted test settings to reflect the current state of development --- .../AbstractSettingsSerializationTest.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java index 914d1990029..563e2b8790f 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java @@ -75,15 +75,23 @@ public abstract class AbstractSettingsSerializationTest { private static class TestSettings extends AbstractSettings implements Serializable { private static final long serialVersionUID = -611806711715538293L; - private transient final StringSetting humba = new StringSetting("humba", this); - private transient final BooleanSetting bumpa = new BooleanSetting("bumpa", this); - private transient final EnumSetting trala = new EnumSetting<>("trala", this, - TextOperator.Operators::valueOf); - private transient final DecimalSetting num = new DecimalSetting("num", this); - private transient final DecimalListSetting l = new DecimalListSetting("l", this); + private transient StringSetting humba; + private transient BooleanSetting bumpa; + private transient EnumSetting trala; + private transient DecimalSetting num; + private transient DecimalListSetting l; public TestSettings() { } + + @Override + protected void addChildSettings() { + humba = new StringSetting("humba", this); + bumpa = new BooleanSetting("bumpa", this); + trala = new EnumSetting<>("trala", this, TextOperator.Operators::valueOf); + num = new DecimalSetting("num", this); + l = new DecimalListSetting("l", this); + } } private static class TestEnumListSettings extends AbstractSettings implements Serializable { From c0c955848ebc570450520ff76a053915e007a010 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Apr 2016 09:33:35 +0200 Subject: [PATCH 060/259] Added currently not working test for Java serialization of settings --- .../test/SettingsJavaSerializationTest.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java new file mode 100644 index 00000000000..1dd792b22ec --- /dev/null +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java @@ -0,0 +1,35 @@ +package com.sap.sse.shared.android.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import org.junit.Ignore; + +import com.sap.sse.common.settings.Settings; + +@Ignore +public class SettingsJavaSerializationTest extends AbstractSettingsSerializationTest { + + @Override + protected byte[] serialize(T settings) throws Exception { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos);) { + oos.writeObject(settings); + oos.close(); + return baos.toByteArray(); + } + + } + + @SuppressWarnings("unchecked") + @Override + protected T deserialize(byte[] serializedObject, T settings) throws Exception { + try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedObject); + ObjectInputStream ois = new ObjectInputStream(bais);) { + return (T) ois.readObject(); + } + + } +} From 63284770dcc836e932f1bed7fed7e19c7a870396 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Apr 2016 09:34:34 +0200 Subject: [PATCH 061/259] Only resetting to default if there is no value --- .../sap/sse/common/settings/base/AbstractValueSetting.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java index aad89328ab2..9675d9200c0 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java @@ -12,7 +12,9 @@ public abstract class AbstractValueSetting extends AbstractHasValueSetting protected AbstractValueSetting(String name, AbstractSettings settings, T defaultValue, ValueConverter valueConverter) { super(name, settings, valueConverter); this.defaultValue = defaultValue; - resetToDefault(); + if(settings.getValue(settingName) == null) { + resetToDefault(); + } } @Override From 6797dabe8942e8912bcf2761db893a4bb4c0829f Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 19 Apr 2016 12:47:50 +0200 Subject: [PATCH 062/259] Added stub implementation for suggested multi selection and included it to users preferences page --- .../UserProfilePreferencesViewImpl.java | 23 ++++-- .../UserProfilePreferencesViewImpl.ui.xml | 15 +++- .../selection/SuggestedMultiSelection.gss | 66 +++++++++++++++++ .../selection/SuggestedMultiSelection.java | 73 +++++++++++++++++++ .../selection/SuggestedMultiSelection.ui.xml | 28 +++++++ .../SuggestedMultiSelectionItem.java | 32 ++++++++ .../SuggestedMultiSelectionItem.ui.xml | 12 +++ .../SuggestedMultiSelectionResources.java | 27 +++++++ 8 files changed, 267 insertions(+), 9 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 03bf83ea709..2e6bbbd3536 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -5,22 +5,25 @@ import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.view.client.ListDataProvider; +import com.sap.sailing.domain.common.dto.BoatClassDTO; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView; -/** - * Created by pgtaboada on 25.11.14. - */ public class UserProfilePreferencesViewImpl extends Composite implements UserProfilePreferencesView { interface MyBinder extends UiBinder { } - private static MyBinder ourUiBinder = GWT.create(MyBinder.class); + private static MyBinder uiBinder = GWT.create(MyBinder.class); - @UiField(provided = true) - AuthorizedContentDecoratorDesktop decoratorUi; + @UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi; + @UiField(provided = true) SuggestedMultiSelection competitorsIBelongToSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favouriteCompetitorsSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favouriteBoatClassesSelctionUi; public UserDetailsView getUserDetailsView() { return null; @@ -29,7 +32,13 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @Override public void setPresenter(Presenter presenter) { decoratorUi = new AuthorizedContentDecoratorDesktop(presenter); - initWidget(ourUiBinder.createAndBindUi(this)); + competitorsIBelongToSelctionUi = new SuggestedMultiSelection<>(new ListDataProvider(), + "TODO Competitors I belong to"); + favouriteCompetitorsSelctionUi = new SuggestedMultiSelection<>(new ListDataProvider(), + "TODO Favourite competitors"); + favouriteBoatClassesSelctionUi = new SuggestedMultiSelection<>(new ListDataProvider(), + "TODO Favourite boat classes"); + initWidget(uiBinder.createAndBindUi(this)); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml index d86460496cd..1f45327c1fd 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml @@ -1,13 +1,24 @@ + xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator" + xmlns:s="urn:import:com.sap.sailing.gwt.home.desktop.places.user.profile.selection"> - TODO + +
      + +
      +
      + +
      +
      + +
      +
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss new file mode 100644 index 00000000000..ca4bebcac53 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss @@ -0,0 +1,66 @@ +.suggestions { + width: 100%; + font-size: 1rem; + border: 1px solid #dedede; + border-radius: 0.333333333333333em; + overflow: hidden; +} + +.suggestionsHeader { + display: block; + background-color: #f2f2f2; + color: #333; + border-bottom: 1px solid #dedede; + text-decoration: none; + position: relative; + overflow: hidden; +} + +.suggestionsHeaderTitle { + padding: 1.111111111111111em; + padding-right: 0.25em; + font-size: 1.2em; + font-weight: 700; + line-height: 1.333; + display: inline-block; +} + +.suggestionsContent { + font-size: inherit; + overflow: hidden; +} + +.suggestionsContentToolbar { + padding: 0.333333333333333em; + position: relative; + text-align: right; +} + +.suggestionsAddFilter { + position: absolute !important; + left: 0.333333333333333em; + right: 8.666666666666667em; +} + +.suggestionsRemoveButton { + padding: 0.433333333333333em 1em; + position: relative; +} + +.suggestionsContentTable { + width: 100%; + border-spacing: 0; + border-collapse: separate; +} + +.suggestionsSelectedItem { + +} + +.suggestionsSelectedItemDescription { + +} + +.suggestionsSelectedItemRemoveButton { + +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java new file mode 100644 index 00000000000..d5089bb5835 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -0,0 +1,73 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.view.client.ProvidesKey; +import com.sap.sailing.gwt.home.shared.partials.filter.AbstractFilterWidget; +import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sse.common.filter.Filter; + +public class SuggestedMultiSelection extends Composite { + + private static SuggestedMultiSelectionUiBinder uiBinder = GWT.create(SuggestedMultiSelectionUiBinder.class); + + interface SuggestedMultiSelectionUiBinder extends UiBinder> { + } + + @UiField SpanElement headerTitleUi; + @UiField(provided = true) AbstractFilterWidget suggestionWidgetUi; + @UiField Button removeAllButtonUi; + @UiField FlowPanel itemContainerUi; + private final Map selectedItems = new HashMap<>(); + private final ProvidesKey keyProvider; + + public SuggestedMultiSelection(ProvidesKey keyProvider, String title) { + SuggestedMultiSelectionResources.INSTANCE.css().ensureInjected(); + this.keyProvider = keyProvider; + suggestionWidgetUi = new AbstractSuggestBoxFilter(StringMessages.INSTANCE.add()) { + @Override + protected String createSuggestionKeyString(T value) { + return null; + } + + @Override + protected String createSuggestionAdditionalDisplayString(T value) { + return null; + } + + @Override + protected Iterable getMatchingStrings(T value) { + return null; + } + + @Override + protected Filter getFilter(String searchString) { + return null; + } + }; + initWidget(uiBinder.createAndBindUi(this)); + headerTitleUi.setInnerText(title); + } + + public void setSelectedItems(List selectedItemsToSet) { + itemContainerUi.clear(); + selectedItems.clear(); + for (T item : selectedItemsToSet) { + Object key = keyProvider.getKey(item); + selectedItems.put(key, item); + itemContainerUi.add(new SuggestedMultiSelectionItem(item)); + } + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml new file mode 100644 index 00000000000..9b1f12c5385 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml @@ -0,0 +1,28 @@ + + + + + + + .noResults { + font-weight: bold; + font-style: italic; + padding: 1.2em; + } + + +
      + +
      +
      +
      + + + + +
      + +
      +
      +
      \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java new file mode 100644 index 00000000000..af6f1e249a1 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java @@ -0,0 +1,32 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.IsWidget; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; + +public class SuggestedMultiSelectionItem extends Composite { + + private static SuggestedMultiSelectionItemUiBinder uiBinder = GWT.create(SuggestedMultiSelectionItemUiBinder.class); + + interface SuggestedMultiSelectionItemUiBinder extends UiBinder> { + } + + @UiField SimplePanel itemDescriptionContainerUi; + @UiField Button removeItemButtonUi; + + public SuggestedMultiSelectionItem(T item) { + initWidget(uiBinder.createAndBindUi(this)); + itemDescriptionContainerUi.setWidget(getItemDescriptionWidget(item)); + } + + protected IsWidget getItemDescriptionWidget(T item) { + return new Label(item.toString()); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml new file mode 100644 index 00000000000..c537d474caf --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java new file mode 100644 index 00000000000..aacede6c358 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java @@ -0,0 +1,27 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.google.gwt.core.shared.GWT; +import com.google.gwt.resources.client.ClientBundle; +import com.google.gwt.resources.client.CssResource; + +public interface SuggestedMultiSelectionResources extends ClientBundle { + + public static final SuggestedMultiSelectionResources INSTANCE = GWT.create(SuggestedMultiSelectionResources.class); + + @Source("SuggestedMultiSelection.gss") + LocalCss css(); + + public interface LocalCss extends CssResource { + String suggestions(); + String suggestionsHeader(); + String suggestionsHeaderTitle(); + String suggestionsContent(); + String suggestionsContentToolbar(); + String suggestionsAddFilter(); + String suggestionsRemoveButton(); + String suggestionsContentTable(); + String suggestionsSelectedItem(); + String suggestionsSelectedItemDescription(); + String suggestionsSelectedItemRemoveButton(); + } +} From 1be9963430842395a5d01bf09c7b22cc72931c6f Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Apr 2016 13:01:23 +0200 Subject: [PATCH 063/259] Handling of Java serialization in SerializableSettings for AbstractSettings contents --- .../sse/common/settings/AbstractSettings.java | 38 +++++++++++++------ .../common/settings/SerializableSettings.java | 26 +++++++++++++ .../sap/sse/common/settings/SettingsList.java | 5 +++ .../AbstractSettingsSerializationTest.java | 34 +++++++++-------- .../test/SettingsJavaSerializationTest.java | 5 +-- 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index d8c846647df..fdc15df0159 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -1,12 +1,9 @@ package com.sap.sse.common.settings; -import java.io.IOException; -import java.io.ObjectInputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sse.common.settings.value.SettingsValue; import com.sap.sse.common.settings.value.Value; @@ -68,16 +65,15 @@ import com.sap.sse.common.settings.value.Value; * */ public abstract class AbstractSettings extends AbstractSetting implements Settings { - - private SettingsValue value; - private transient Map childSettings = new HashMap<>(); + private transient SettingsValue value; + private transient Map childSettings; /** * Default constructor for direct instantiation of root settings objects. */ public AbstractSettings() { value = new SettingsValue(); - addChildSettings(); + addChildSettingsInternal(); } /** @@ -94,7 +90,7 @@ public abstract class AbstractSettings extends AbstractSetting implements Settin settings.setValue(name, value); } settings.setValue(name, value); - addChildSettings(); + addChildSettingsInternal(); } /** @@ -102,16 +98,34 @@ public abstract class AbstractSettings extends AbstractSetting implements Settin */ protected void adoptValue(SettingsValue value) { this.value = value; + if(childSettings != null) { + for(Map.Entry entry : childSettings.entrySet()) { + Setting childSetting = entry.getValue(); + if(childSetting instanceof AbstractSettings) { + Value childValue = value.getValue(entry.getKey()); + if(childValue != null) { + ((AbstractSettings) childSetting).adoptValue((SettingsValue) childValue); + } + } + if(childSetting instanceof SettingsList) { + Value childValue = value.getValue(entry.getKey()); + if(childValue != null) { + ((SettingsList) childSetting).adoptValue(); + } + } + } + } } protected SettingsValue getInnerValueObject() { return value; } - @GwtIncompatible - private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { - ois.defaultReadObject(); - addChildSettings(); + protected final void addChildSettingsInternal() { + if(childSettings == null) { + childSettings = new HashMap<>(); + addChildSettings(); + } } /** diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java index ae32a9aab7b..cab89231d7d 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java @@ -1,9 +1,35 @@ package com.sap.sse.common.settings; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sse.common.settings.value.SettingsValue; + public abstract class SerializableSettings extends AbstractSettings implements Serializable { private static final long serialVersionUID = -2710627501473421333L; + public SerializableSettings() { + super(); + } + + public SerializableSettings(String name, AbstractSettings settings) { + super(name, settings); + } + + @GwtIncompatible + private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { + ois.defaultReadObject(); + adoptValue((SettingsValue) ois.readObject()); + addChildSettingsInternal(); + } + + @GwtIncompatible + private void writeObject(ObjectOutputStream out) throws IOException { + SettingsValue innerValueObject = getInnerValueObject(); + out.writeObject(innerValueObject); + } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java index 3cb61ecd244..4285ef91a82 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java @@ -18,6 +18,11 @@ public class SettingsList extends AbstractSetting im public SettingsList(String name, AbstractSettings settings, SettingsFactory settingsFactory) { super(name, settings); this.settingsFactory = settingsFactory; + adoptValue(); + } + + protected void adoptValue() { + values.clear(); ValueListValue value = getValue(); if(value != null) { for(Value val : value.getValueObjects()) { diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java index 563e2b8790f..48b73fc1d21 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java @@ -2,7 +2,6 @@ package com.sap.sse.shared.android.test; import static org.junit.Assert.assertEquals; -import java.io.Serializable; import java.math.BigDecimal; import java.util.Arrays; @@ -16,6 +15,7 @@ import com.sap.sse.common.settings.DecimalListSetting; import com.sap.sse.common.settings.DecimalSetting; import com.sap.sse.common.settings.EnumListSetting; import com.sap.sse.common.settings.EnumSetting; +import com.sap.sse.common.settings.SerializableSettings; import com.sap.sse.common.settings.Settings; import com.sap.sse.common.settings.SettingsList; import com.sap.sse.common.settings.StringSetting; @@ -23,7 +23,7 @@ import com.sap.sse.common.settings.StringToEnumConverter; public abstract class AbstractSettingsSerializationTest { - private static class TestOuterSettings extends AbstractSettings implements Serializable { + private static class TestOuterSettings extends SerializableSettings { private static final long serialVersionUID = -7379232503773525915L; private transient SimpleTestSettings nested; @@ -36,7 +36,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestListSettings extends AbstractSettings implements Serializable { + private static class TestListSettings extends SerializableSettings { private static final long serialVersionUID = 6919127895749914961L; private transient SettingsList l; @@ -49,7 +49,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class SimpleTestSettings extends AbstractSettings implements Serializable { + private static class SimpleTestSettings extends SerializableSettings { private static final long serialVersionUID = -4134836978411240572L; private transient StringSetting string; private transient DecimalSetting num; @@ -73,7 +73,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestSettings extends AbstractSettings implements Serializable { + private static class TestSettings extends SerializableSettings { private static final long serialVersionUID = -611806711715538293L; private transient StringSetting humba; private transient BooleanSetting bumpa; @@ -94,7 +94,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestEnumListSettings extends AbstractSettings implements Serializable { + private static class TestEnumListSettings extends SerializableSettings { private static final long serialVersionUID = 93688955681544920L; private transient EnumListSetting l; @@ -113,7 +113,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class DuplicateFieldSettings extends AbstractSettings implements Serializable { + private static class DuplicateFieldSettings extends SerializableSettings { private static final long serialVersionUID = 4058775568295038177L; @SuppressWarnings("unused") private transient StringSetting humba; @@ -127,7 +127,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class DisallowedKeySettings extends AbstractSettings implements Serializable { + private static class DisallowedKeySettings extends SerializableSettings { private static final long serialVersionUID = -2265305217290147424L; @SuppressWarnings("unused") private transient StringSetting disallowedKey; @@ -140,17 +140,21 @@ public abstract class AbstractSettingsSerializationTest { protected abstract SOT serialize(T settings) throws Exception; - protected abstract T deserialize(SOT serializedObject, T settings) throws Exception; + protected T deserialize(SOT serializedObject, Class settingsClass) throws Exception { + T deserializedInstance = settingsClass.newInstance(); + return deserialize(serializedObject, deserializedInstance); + } + + protected T deserialize(SOT serializedObject, T settings) throws Exception { + return null; + }; + + @SuppressWarnings("unchecked") private T serializeAndDeserialize(T objectToSerialize) { try { SOT serialized = serialize(objectToSerialize); - - @SuppressWarnings("unchecked") - Class settingsType = (Class) objectToSerialize.getClass(); - T deserializedInstance = settingsType.newInstance(); - - return deserialize(serialized, deserializedInstance); + return deserialize(serialized, (Class) objectToSerialize.getClass()); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java index 1dd792b22ec..3dc5d73347b 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java @@ -5,11 +5,8 @@ import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import org.junit.Ignore; - import com.sap.sse.common.settings.Settings; -@Ignore public class SettingsJavaSerializationTest extends AbstractSettingsSerializationTest { @Override @@ -25,7 +22,7 @@ public class SettingsJavaSerializationTest extends AbstractSettingsSerialization @SuppressWarnings("unchecked") @Override - protected T deserialize(byte[] serializedObject, T settings) throws Exception { + protected T deserialize(byte[] serializedObject, Class settingsClass) throws Exception { try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedObject); ObjectInputStream ois = new ObjectInputStream(bais);) { return (T) ois.readObject(); From 6cb01435aea0fc248624fd1966deea2cc358f1e6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Apr 2016 13:24:04 +0200 Subject: [PATCH 064/259] Introduced a private GwtIncompatible annotation --- .../sse/common/settings/GwtIncompatible.java | 27 +++++++++++++++++++ .../common/settings/SerializableSettings.java | 1 - 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/GwtIncompatible.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/GwtIncompatible.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/GwtIncompatible.java new file mode 100644 index 00000000000..5d2d0268bca --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/GwtIncompatible.java @@ -0,0 +1,27 @@ +package com.sap.sse.common.settings; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Private version of com.google.gwt.core.shared.GwtIncompatible. + * GWT doesn't check for the concrete annotation class but only checks if there is an annotation named GwtIncompatible. + * With this private annotation we can flag something as GWT incompatible without introducing a dependency to GWT core. + * + */ +@Retention(RetentionPolicy.CLASS) +@Target({ + ElementType.TYPE, ElementType.METHOD, + ElementType.CONSTRUCTOR, ElementType.FIELD }) +@Documented +public @interface GwtIncompatible { + /** + * An attribute that can be used to explain why the code is incompatible. + * A GwtIncompatible annotation can have any number of attributes; attributes + * are for documentation purposes and are ignored by the GWT compiler. + */ + String value() default ""; +} \ No newline at end of file diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java index cab89231d7d..de99770a70a 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java @@ -5,7 +5,6 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; -import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sse.common.settings.value.SettingsValue; public abstract class SerializableSettings extends AbstractSettings implements Serializable { From 8b18b2138c233d5ac71cbcf71c19459487545243 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 19 Apr 2016 16:52:42 +0200 Subject: [PATCH 065/259] Adjusted stub implementation of suggested multi selection for flexible item rendering and added some dummy data --- .../UserProfilePreferencesViewImpl.java | 26 ++++++++---- .../selection/SuggestedMultiSelection.gss | 39 ++++++++++++++---- .../selection/SuggestedMultiSelection.java | 41 +++++++++++++++++-- ...ultiSelectionBoatClassItemDescription.java | 30 ++++++++++++++ ...tiSelectionBoatClassItemDescription.ui.xml | 16 ++++++++ ...ltiSelectionCompetitorItemDescription.java | 32 +++++++++++++++ ...iSelectionCompetitorItemDescription.ui.xml | 17 ++++++++ .../SuggestedMultiSelectionItem.java | 15 +++---- .../SuggestedMultiSelectionItem.ui.xml | 4 +- .../SuggestedMultiSelectionResources.java | 5 ++- 10 files changed, 192 insertions(+), 33 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 2e6bbbd3536..9dd9407e690 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -1,12 +1,14 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; +import java.util.Arrays; + import com.google.gwt.core.client.GWT; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.ListDataProvider; -import com.sap.sailing.domain.common.dto.BoatClassDTO; +import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop; @@ -23,7 +25,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi; @UiField(provided = true) SuggestedMultiSelection competitorsIBelongToSelctionUi; @UiField(provided = true) SuggestedMultiSelection favouriteCompetitorsSelctionUi; - @UiField(provided = true) SuggestedMultiSelection favouriteBoatClassesSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favouriteBoatClassesSelctionUi; public UserDetailsView getUserDetailsView() { return null; @@ -32,13 +34,21 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @Override public void setPresenter(Presenter presenter) { decoratorUi = new AuthorizedContentDecoratorDesktop(presenter); - competitorsIBelongToSelctionUi = new SuggestedMultiSelection<>(new ListDataProvider(), - "TODO Competitors I belong to"); - favouriteCompetitorsSelctionUi = new SuggestedMultiSelection<>(new ListDataProvider(), - "TODO Favourite competitors"); - favouriteBoatClassesSelctionUi = new SuggestedMultiSelection<>(new ListDataProvider(), - "TODO Favourite boat classes"); + competitorsIBelongToSelctionUi = SuggestedMultiSelection.forCompetitors( + new ListDataProvider(), "TODO Competitors I belong to"); + favouriteCompetitorsSelctionUi = SuggestedMultiSelection.forCompetitors( + new ListDataProvider(), "TODO Favourite competitors"); + favouriteBoatClassesSelctionUi = SuggestedMultiSelection.forBoatClasses( + new ListDataProvider(), "TODO Favourite boat classes"); initWidget(uiBinder.createAndBindUi(this)); + + favouriteCompetitorsSelctionUi.setSelectedItems(Arrays.asList( + new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), + new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), + new SimpleCompetitorDTO("Competitor with a very long name to test wrapping in favourite list", "USA 1337", "us", null))); + favouriteBoatClassesSelctionUi.setSelectedItems(Arrays.asList( + BoatClassMasterdata.KIELZUGVOGEL, + BoatClassMasterdata.J22)); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss index ca4bebcac53..7e74e3f2513 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss @@ -30,13 +30,13 @@ overflow: hidden; } -.suggestionsContentToolbar { +.suggestionsContentToolbar, .suggestionsSelectedItem { padding: 0.333333333333333em; position: relative; text-align: right; } -.suggestionsAddFilter { +.suggestionsAddFilter, .suggestionsItemDescription { position: absolute !important; left: 0.333333333333333em; right: 8.666666666666667em; @@ -54,13 +54,34 @@ } .suggestionsSelectedItem { - + border-top: 1px solid #ddd; } -.suggestionsSelectedItemDescription { - +.suggestionsItemDescription { + text-align: left; + line-height: 2em; +} + +.suggestionsItemDescription > * { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.suggestionsItemDescriptionImage, .suggestionsItemDescriptionId { + margin: 0 0.25em; +} + +.suggestionsItemDescriptionImage { + background-repeat: no-repeat; + background-size: contain; + background-position: center; + display: inline-block; + vertical-align: bottom; +} + +.suggestionsItemDescriptionId { + font-weight: 600; + display: inline-block; + min-width: 5.5em; } - -.suggestionsSelectedItemRemoveButton { - -} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index d5089bb5835..137a28ea057 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -11,8 +11,11 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; +import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.view.client.ProvidesKey; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractFilterWidget; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -31,10 +34,12 @@ public class SuggestedMultiSelection extends Composite { @UiField FlowPanel itemContainerUi; private final Map selectedItems = new HashMap<>(); private final ProvidesKey keyProvider; + private final WidgetProvider widgetProvider; - public SuggestedMultiSelection(ProvidesKey keyProvider, String title) { + private SuggestedMultiSelection(ProvidesKey keyProvider, WidgetProvider widgetProvider, String title) { SuggestedMultiSelectionResources.INSTANCE.css().ensureInjected(); this.keyProvider = keyProvider; + this.widgetProvider = widgetProvider; suggestionWidgetUi = new AbstractSuggestBoxFilter(StringMessages.INSTANCE.add()) { @Override protected String createSuggestionKeyString(T value) { @@ -63,11 +68,41 @@ public class SuggestedMultiSelection extends Composite { public void setSelectedItems(List selectedItemsToSet) { itemContainerUi.clear(); selectedItems.clear(); - for (T item : selectedItemsToSet) { + for (final T item : selectedItemsToSet) { Object key = keyProvider.getKey(item); selectedItems.put(key, item); - itemContainerUi.add(new SuggestedMultiSelectionItem(item)); + itemContainerUi.add(new SuggestedMultiSelectionItem() { + @Override + protected IsWidget getItemDescriptionWidget() { + return widgetProvider.getItemDescriptionWidget(item); + } + }); } } + + private interface WidgetProvider { + IsWidget getItemDescriptionWidget(T item); + } + + public static SuggestedMultiSelection forCompetitors( + ProvidesKey keyProvider, String headerTitle) { + return new SuggestedMultiSelection<>(keyProvider, new WidgetProvider() { + @Override + public IsWidget getItemDescriptionWidget(SimpleCompetitorDTO item) { + return new SuggestedMultiSelectionCompetitorItemDescription(item); + } + }, headerTitle); + } + + public static SuggestedMultiSelection forBoatClasses( + ProvidesKey keyProvider, String headerTitle) { + return new SuggestedMultiSelection<>(keyProvider, new WidgetProvider() { + @Override + public IsWidget getItemDescriptionWidget(BoatClassMasterdata item) { + return new SuggestedMultiSelectionBoatClassItemDescription(item); + } + }, headerTitle); + } + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java new file mode 100644 index 00000000000..91429f69ea6 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java @@ -0,0 +1,30 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.gwt.common.client.BoatClassImageResolver; + +class SuggestedMultiSelectionBoatClassItemDescription extends Widget { + + private static LocalUiBinder uiBinder = GWT.create(LocalUiBinder.class); + + interface LocalUiBinder extends UiBinder { + } + + @UiField DivElement imageUi; + @UiField SpanElement nameUi; + + SuggestedMultiSelectionBoatClassItemDescription(BoatClassMasterdata boatClass) { + setElement(uiBinder.createAndBindUi(this)); + imageUi.getStyle().setBackgroundImage("url('" + BoatClassImageResolver.getBoatClassIconResource( + boatClass.getDisplayName()).getSafeUri().asString() + "')"); + nameUi.setInnerText(boatClass.getDisplayName()); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml new file mode 100644 index 00000000000..fdc0974942d --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml @@ -0,0 +1,16 @@ + + + + + + + .imageSize { + width: 2.133333333333333em !important; + height: 2.133333333333333em !important; + } + +
      +
      + +
      +
      \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.java new file mode 100644 index 00000000000..d10ff518508 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.java @@ -0,0 +1,32 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.ui.client.FlagImageResolver; + +class SuggestedMultiSelectionCompetitorItemDescription extends Widget { + + private static LocalUiBinder uiBinder = GWT.create(LocalUiBinder.class); + + interface LocalUiBinder extends UiBinder { + } + + @UiField DivElement flagImageUi; + @UiField SpanElement sailIdUi; + @UiField SpanElement nameUi; + + SuggestedMultiSelectionCompetitorItemDescription(SimpleCompetitorDTO competitor) { + setElement(uiBinder.createAndBindUi(this)); + flagImageUi.getStyle().setBackgroundImage("url('" + FlagImageResolver.getFlagImageUri( + competitor.getFlagImageURL(), competitor.getTwoLetterIsoCountryCode()).asString() + "')"); + sailIdUi.setInnerText(competitor.getSailID()); + nameUi.setInnerText(competitor.getName()); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml new file mode 100644 index 00000000000..b6a0b6541ff --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml @@ -0,0 +1,17 @@ + + + + + + + .imageSize { + width: 1.666666666666667em !important; + height: 2em !important; + } + +
      +
      + + +
      +
      \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java index af6f1e249a1..715f4e1e264 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java @@ -6,27 +6,24 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.IsWidget; -import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; -public class SuggestedMultiSelectionItem extends Composite { +abstract class SuggestedMultiSelectionItem extends Composite { - private static SuggestedMultiSelectionItemUiBinder uiBinder = GWT.create(SuggestedMultiSelectionItemUiBinder.class); + private static LocalUiBinder uiBinder = GWT.create(LocalUiBinder.class); - interface SuggestedMultiSelectionItemUiBinder extends UiBinder> { + interface LocalUiBinder extends UiBinder { } @UiField SimplePanel itemDescriptionContainerUi; @UiField Button removeItemButtonUi; - public SuggestedMultiSelectionItem(T item) { + SuggestedMultiSelectionItem() { initWidget(uiBinder.createAndBindUi(this)); - itemDescriptionContainerUi.setWidget(getItemDescriptionWidget(item)); + itemDescriptionContainerUi.setWidget(getItemDescriptionWidget()); } - protected IsWidget getItemDescriptionWidget(T item) { - return new Label(item.toString()); - } + protected abstract IsWidget getItemDescriptionWidget(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml index c537d474caf..4e3040acc3e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml @@ -4,8 +4,8 @@ - - + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java index aacede6c358..5b543aad2b3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java @@ -21,7 +21,8 @@ public interface SuggestedMultiSelectionResources extends ClientBundle { String suggestionsRemoveButton(); String suggestionsContentTable(); String suggestionsSelectedItem(); - String suggestionsSelectedItemDescription(); - String suggestionsSelectedItemRemoveButton(); + String suggestionsItemDescription(); + String suggestionsItemDescriptionImage(); + String suggestionsItemDescriptionId(); } } From 9fd7eddfaf744fdce26b1696ec8566492add7ed6 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Apr 2016 15:51:51 +0200 Subject: [PATCH 066/259] Added callback method to AbstractSuggestBoxFilter to be able to react on selections --- .../filter/AbstractSuggestBoxFilter.java | 19 ++++++++++++++----- .../RacesByCompetitorTextBoxFilter.java | 4 ++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java index 3cc965244b7..bb9467b2907 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java @@ -36,6 +36,9 @@ public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFi suggestBox.addSelectionHandler(new SelectionHandler() { @Override public void onSelection(SelectionEvent event) { + @SuppressWarnings("unchecked") + C suggestObject = ((SimpleSuggestion) event.getSelectedItem()).suggestObject; + AbstractSuggestBoxFilter.this.onSuggestionSelected(suggestObject); AbstractSuggestBoxFilter.super.update(); } }); @@ -47,6 +50,8 @@ public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFi suggestionObjectList.addAll(selectableValues); } + protected abstract void onSuggestionSelected(C selectedItem); + protected abstract String createSuggestionKeyString(C value); protected abstract String createSuggestionAdditionalDisplayString(C value); @@ -81,7 +86,8 @@ public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFi } } - private void setSuggestions(Request request, Callback callback, Iterable suggestionObjects, Iterable queryTokens) { + private void setSuggestions(Request request, Callback callback, Iterable suggestionObjects, + Iterable queryTokens) { List suggestions = new ArrayList<>(); List normalizedQueryTokens = new ArrayList<>(); for (String token : queryTokens) { @@ -121,10 +127,13 @@ public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFi public String getDisplayString() { SafeHtmlBuilder builder = new SafeHtmlBuilder(); appendHighlighted(builder, createSuggestionKeyString(suggestObject)); - builder.append(SafeHtmlUtils.fromTrustedString(ITALIC_TAG_OPEN)); - builder.append(SafeHtmlUtils.fromSafeConstant(" - ")); - appendHighlighted(builder, createSuggestionAdditionalDisplayString(suggestObject)); - builder.append(SafeHtmlUtils.fromTrustedString(ITALIC_TAG_CLOSE)); + String additionalString = createSuggestionAdditionalDisplayString(suggestObject); + if(additionalString != null && !additionalString.isEmpty()) { + builder.append(SafeHtmlUtils.fromTrustedString(ITALIC_TAG_OPEN)); + builder.append(SafeHtmlUtils.fromSafeConstant(" - ")); + appendHighlighted(builder, additionalString); + builder.append(SafeHtmlUtils.fromTrustedString(ITALIC_TAG_CLOSE)); + } return builder.toSafeHtml().asString(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java index dfdbdcc98e5..4280e233e66 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java @@ -27,6 +27,10 @@ public class RacesByCompetitorTextBoxFilter extends AbstractSuggestBoxFilter Date: Wed, 20 Apr 2016 15:52:48 +0200 Subject: [PATCH 067/259] Made AbstractTextInputFilter clear method accessable for implementing subclasses --- .../partials/filter/AbstractTextInputFilter.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractTextInputFilter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractTextInputFilter.java index 0eb71be8c0e..7f1216c5e74 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractTextInputFilter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractTextInputFilter.java @@ -58,17 +58,21 @@ public abstract class AbstractTextInputFilter extends AbstractFilterWidget notifyValueChangeHandlers(); } + protected void clear() { + textInputUi.setValue(null); + update(); + } + protected abstract Filter getFilter(String searchString); private class TextInputFilterHandler implements ClickHandler, KeyUpHandler { @Override public void onKeyUp(KeyUpEvent event) { - update(); + AbstractTextInputFilter.this.update(); } @Override public void onClick(ClickEvent event) { - textInputUi.setValue(null); - update(); + AbstractTextInputFilter.this.clear(); } } From 0f154df63bf499af27bb7c320e5841e840868a1e Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Apr 2016 16:37:47 +0200 Subject: [PATCH 068/259] Refactored stub implementation of suggested multi selection for dynamic data access --- .../UserProfilePreferencesPresenter.java | 43 +++++ .../UserProfilePreferencesView.java | 13 ++ .../UserProfilePreferencesViewImpl.java | 38 ++-- .../selection/SuggestedMultiSelection.java | 164 +++++++++++++----- .../SuggestedMultiSelectionDataProvider.java | 21 +++ .../SuggestedMultiSelectionItem.java | 9 + ...ggestedMultiSelectionListDataProvider.java | 60 +++++++ 7 files changed, 292 insertions(+), 56 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 5c6eda77a73..8110ca3c561 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -1,6 +1,14 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; +import java.util.Arrays; +import java.util.List; + +import com.google.gwt.view.client.ProvidesKey; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionListDataProvider; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; public class UserProfilePreferencesPresenter implements UserProfilePreferencesView.Presenter { @@ -16,6 +24,10 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi // this.userDetailsPresenter = new UserDetailsPresenter(view.getUserDetailsView(), // userProfilePresenter.getAuthenticationManager(), userProfilePresenter.getUserManagementService(), // userProfilePresenter.getMailVerifiedUrl()); + view.setFavouriteCompetitors(competitorsDummyData); + view.setFavouriteBoatClasses(Arrays.asList( + BoatClassMasterdata.KIELZUGVOGEL, + BoatClassMasterdata.J22)); } @Override @@ -28,4 +40,35 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi public void doTriggerLoginForm() { userProfilePresenter.doTriggerLoginForm(); } + + @Override + public SuggestedMultiSelectionDataProvider getBoatClassDataProvider() { + SuggestedMultiSelectionListDataProvider dataProvider = + new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { + @Override + public Object getKey(BoatClassMasterdata item) { + return item.getDisplayName(); + } + }); + dataProvider.setSuggestionItems(Arrays.asList(BoatClassMasterdata.values())); + return dataProvider; + } + + @Override + public SuggestedMultiSelectionDataProvider getCompetitorDataProvider() { + SuggestedMultiSelectionListDataProvider dataProvider = + new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { + @Override + public Object getKey(SimpleCompetitorDTO item) { + return item.getSailID(); + } + }); + dataProvider.setSuggestionItems(competitorsDummyData); + return dataProvider; + } + + private final List competitorsDummyData = Arrays.asList( + new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), + new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), + new SimpleCompetitorDTO("Competitor with a long name to test wrapping in favourite list", "USA 1337", "us", null)); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index a7b9e97d81c..9482122ed79 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -1,6 +1,11 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; +import java.util.Collection; + import com.google.gwt.user.client.ui.IsWidget; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView; @@ -12,7 +17,15 @@ public interface UserProfilePreferencesView extends IsWidget { UserDetailsView getUserDetailsView(); NeedsAuthenticationContext getDecorator(); + + void setCompetitorsIBelongTo(Collection selectedItems); + + void setFavouriteCompetitors(Collection selectedItems); + + void setFavouriteBoatClasses(Collection selectedItems); public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext { + SuggestedMultiSelectionDataProvider getBoatClassDataProvider(); + SuggestedMultiSelectionDataProvider getCompetitorDataProvider(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 9dd9407e690..12659850174 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -1,13 +1,12 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; -import java.util.Arrays; +import java.util.Collection; import com.google.gwt.core.client.GWT; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; -import com.google.gwt.view.client.ListDataProvider; import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; @@ -34,21 +33,28 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @Override public void setPresenter(Presenter presenter) { decoratorUi = new AuthorizedContentDecoratorDesktop(presenter); - competitorsIBelongToSelctionUi = SuggestedMultiSelection.forCompetitors( - new ListDataProvider(), "TODO Competitors I belong to"); - favouriteCompetitorsSelctionUi = SuggestedMultiSelection.forCompetitors( - new ListDataProvider(), "TODO Favourite competitors"); - favouriteBoatClassesSelctionUi = SuggestedMultiSelection.forBoatClasses( - new ListDataProvider(), "TODO Favourite boat classes"); + competitorsIBelongToSelctionUi = SuggestedMultiSelection.forCompetitors(presenter.getCompetitorDataProvider(), + "TODO Competitors I belong to"); + favouriteCompetitorsSelctionUi = SuggestedMultiSelection.forCompetitors(presenter.getCompetitorDataProvider(), + "TODO Favourite competitors"); + favouriteBoatClassesSelctionUi = SuggestedMultiSelection.forBoatClasses(presenter.getBoatClassDataProvider(), + "TODO Favourite boat classes"); initWidget(uiBinder.createAndBindUi(this)); - - favouriteCompetitorsSelctionUi.setSelectedItems(Arrays.asList( - new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), - new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), - new SimpleCompetitorDTO("Competitor with a very long name to test wrapping in favourite list", "USA 1337", "us", null))); - favouriteBoatClassesSelctionUi.setSelectedItems(Arrays.asList( - BoatClassMasterdata.KIELZUGVOGEL, - BoatClassMasterdata.J22)); + } + + @Override + public void setCompetitorsIBelongTo(Collection selectedItems) { + competitorsIBelongToSelctionUi.setSelectedItems(selectedItems); + } + + @Override + public void setFavouriteCompetitors(Collection selectedItems) { + favouriteCompetitorsSelctionUi.setSelectedItems(selectedItems); + } + + @Override + public void setFavouriteBoatClasses(Collection selectedItems) { + favouriteBoatClassesSelctionUi.setSelectedItems(selectedItems); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index 137a28ea057..ea58186a04a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -1,27 +1,28 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.Arrays; +import java.util.Collection; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.SpanElement; +import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; -import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.SuggestionItemsCallback; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractFilterWidget; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.common.filter.Filter; -public class SuggestedMultiSelection extends Composite { +public final class SuggestedMultiSelection extends Composite { private static SuggestedMultiSelectionUiBinder uiBinder = GWT.create(SuggestedMultiSelectionUiBinder.class); @@ -32,77 +33,160 @@ public class SuggestedMultiSelection extends Composite { @UiField(provided = true) AbstractFilterWidget suggestionWidgetUi; @UiField Button removeAllButtonUi; @UiField FlowPanel itemContainerUi; - private final Map selectedItems = new HashMap<>(); - private final ProvidesKey keyProvider; + private final SuggestedMultiSelectionDataProvider dataProvider; private final WidgetProvider widgetProvider; - private SuggestedMultiSelection(ProvidesKey keyProvider, WidgetProvider widgetProvider, String title) { + private SuggestedMultiSelection(SuggestedMultiSelectionDataProvider dataProvider, + WidgetProvider widgetProvider, String title) { SuggestedMultiSelectionResources.INSTANCE.css().ensureInjected(); - this.keyProvider = keyProvider; + this.dataProvider = dataProvider; this.widgetProvider = widgetProvider; - suggestionWidgetUi = new AbstractSuggestBoxFilter(StringMessages.INSTANCE.add()) { + this.suggestionWidgetUi = widgetProvider.getSuggestBoxFilter(new SelectionCallback() { @Override - protected String createSuggestionKeyString(T value) { - return null; + public void onSuggestionSelected(T selectedItem) { + SuggestedMultiSelection.this.addSelectedItem(selectedItem); } - - @Override - protected String createSuggestionAdditionalDisplayString(T value) { - return null; - } - - @Override - protected Iterable getMatchingStrings(T value) { - return null; - } - - @Override - protected Filter getFilter(String searchString) { - return null; - } - }; + }); initWidget(uiBinder.createAndBindUi(this)); headerTitleUi.setInnerText(title); + this.updateUiState(); } - public void setSelectedItems(List selectedItemsToSet) { + @UiHandler("removeAllButtonUi") + void onRemoveAllButtonClicked(ClickEvent event) { + dataProvider.clearSelection(); + itemContainerUi.clear(); + this.updateUiState(); + } + + public void setSelectedItems(Collection selectedItemsToSet) { + dataProvider.clearSelection(); itemContainerUi.clear(); - selectedItems.clear(); for (final T item : selectedItemsToSet) { - Object key = keyProvider.getKey(item); - selectedItems.put(key, item); - itemContainerUi.add(new SuggestedMultiSelectionItem() { + this.addSelectedItem(item); + } + } + + private void addSelectedItem(final T selectedItem) { + dataProvider.addSelection(selectedItem); + itemContainerUi.add(new SuggestedMultiSelectionItem() { + @Override + protected IsWidget getItemDescriptionWidget() { + return widgetProvider.getItemDescriptionWidget(selectedItem); + } + + @Override + protected void onRemoveItemRequsted() { + dataProvider.removeSelection(selectedItem); + this.removeFromParent(); + updateUiState(); + } + }); + this.updateUiState(); + } + + private void updateUiState() { + removeAllButtonUi.setEnabled(itemContainerUi.getWidgetCount() > 0); + } + + private static abstract class AbstractSuggestedMultiSelectionFilter extends AbstractSuggestBoxFilter { + protected final SuggestedMultiSelectionDataProvider dataProvider; + private final SelectionCallback selectionCallback; + + protected AbstractSuggestedMultiSelectionFilter(SuggestedMultiSelectionDataProvider dataProvider, + SelectionCallback selectionCallback, String placeholderText) { + super(placeholderText); + this.dataProvider = dataProvider; + this.selectionCallback = selectionCallback; + } + + @Override + protected final String createSuggestionKeyString(T value) { + return String.valueOf(dataProvider.getKey(value)); + } + + @Override + protected final void onSuggestionSelected(T selectedItem) { + AbstractSuggestedMultiSelectionFilter.this.clear(); + selectionCallback.onSuggestionSelected(selectedItem); + } + + @Override + protected final Filter getFilter(String searchString) { + dataProvider.getSuggestionItems(searchString, new SuggestionItemsCallback() { @Override - protected IsWidget getItemDescriptionWidget() { - return widgetProvider.getItemDescriptionWidget(item); + public void setSuggestionItems(Collection suggestionItems) { + AbstractSuggestedMultiSelectionFilter.this.setSelectableValues(suggestionItems); } }); + return new Filter() { + @Override public boolean matches(T object) { return true; } + @Override public String getName() { return "alwaysMatchingFilter"; } + }; } } + private interface SelectionCallback { + void onSuggestionSelected(T selectedItem); + } + private interface WidgetProvider { IsWidget getItemDescriptionWidget(T item); + AbstractSuggestBoxFilter getSuggestBoxFilter(SelectionCallback selectionCallback); } public static SuggestedMultiSelection forCompetitors( - ProvidesKey keyProvider, String headerTitle) { - return new SuggestedMultiSelection<>(keyProvider, new WidgetProvider() { + final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { + return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { @Override public IsWidget getItemDescriptionWidget(SimpleCompetitorDTO item) { return new SuggestedMultiSelectionCompetitorItemDescription(item); } + + @Override + public AbstractSuggestBoxFilter getSuggestBoxFilter( + SelectionCallback selectionCallback) { + return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, + StringMessages.INSTANCE.add(StringMessages.INSTANCE.competitor())) { + @Override + protected String createSuggestionAdditionalDisplayString(SimpleCompetitorDTO value) { + return value.getName(); + } + + @Override + protected Iterable getMatchingStrings(SimpleCompetitorDTO value) { + return Arrays.asList(value.getSailID(), value.getName()); + } + }; + } }, headerTitle); } public static SuggestedMultiSelection forBoatClasses( - ProvidesKey keyProvider, String headerTitle) { - return new SuggestedMultiSelection<>(keyProvider, new WidgetProvider() { + final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { + return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { @Override public IsWidget getItemDescriptionWidget(BoatClassMasterdata item) { return new SuggestedMultiSelectionBoatClassItemDescription(item); } + + @Override + public AbstractSuggestBoxFilter getSuggestBoxFilter( + SelectionCallback selectionCallback) { + return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, + StringMessages.INSTANCE.add(StringMessages.INSTANCE.boatClass())) { + @Override + protected String createSuggestionAdditionalDisplayString(BoatClassMasterdata value) { + return null; + } + + @Override + protected Iterable getMatchingStrings(BoatClassMasterdata value) { + return Arrays.asList(value.getAlternativeNames()); + } + }; + } }, headerTitle); } - } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java new file mode 100644 index 00000000000..8b426fe2f37 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java @@ -0,0 +1,21 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import java.util.Collection; + +import com.google.gwt.view.client.ProvidesKey; + +public interface SuggestedMultiSelectionDataProvider extends ProvidesKey { + + void addSelection(T item); + + void removeSelection(T item); + + void clearSelection(); + + void getSuggestionItems(String query, final SuggestionItemsCallback callback); + + interface SuggestionItemsCallback { + void setSuggestionItems(Collection suggestionItems); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java index 715f4e1e264..7b36e0f1c0a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java @@ -1,8 +1,10 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.IsWidget; @@ -24,6 +26,13 @@ abstract class SuggestedMultiSelectionItem extends Composite { itemDescriptionContainerUi.setWidget(getItemDescriptionWidget()); } + @UiHandler("removeItemButtonUi") + void onRemoveItemButtonClicked(ClickEvent event) { + this.onRemoveItemRequsted(); + } + protected abstract IsWidget getItemDescriptionWidget(); + + protected abstract void onRemoveItemRequsted(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java new file mode 100644 index 00000000000..414352c4f3f --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java @@ -0,0 +1,60 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.gwt.view.client.ProvidesKey; + +public class SuggestedMultiSelectionListDataProvider implements SuggestedMultiSelectionDataProvider { + + private final Map selectedItemsMap = new HashMap<>(); + private final ProvidesKey keyProvider; + private final List suggestionItemsList = new ArrayList(); + + public SuggestedMultiSelectionListDataProvider(ProvidesKey keyProvider) { + this.keyProvider = keyProvider; + } + + @Override + public Object getKey(T item) { + return keyProvider == null ? item : keyProvider.getKey(item); + } + + @Override + public void addSelection(T item) { + Object key = getKey(item); + selectedItemsMap.put(key, item); + } + + @Override + public void removeSelection(T item) { + Object key = getKey(item); + selectedItemsMap.remove(key); + } + + @Override + public void clearSelection() { + selectedItemsMap.clear(); + } + + public void setSuggestionItems(Collection suggestionItems) { + suggestionItemsList.clear(); + suggestionItemsList.addAll(suggestionItems); + } + + @Override + public void getSuggestionItems(String query, final SuggestionItemsCallback callback) { + List filteredSuggestionItems = new ArrayList<>(); + for (T item : suggestionItemsList) { + Object key = getKey(item); + if (!selectedItemsMap.containsKey(key)) { + filteredSuggestionItems.add(item); + } + } + callback.setSuggestionItems(filteredSuggestionItems); + } + +} From b250b89684966f3db6163e76a4ab4c3b8ef08dec Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 21 Apr 2016 09:27:50 +0200 Subject: [PATCH 069/259] Added stub implementation for notification toggle to suggested multi selection --- .../selection/SuggestedMultiSelection.gss | 22 ++++++-- .../selection/SuggestedMultiSelection.java | 1 + .../selection/SuggestedMultiSelection.ui.xml | 4 +- ...estedMultiSelectionNotificationToggle.java | 51 +++++++++++++++++++ ...tedMultiSelectionNotificationToggle.ui.xml | 10 ++++ .../SuggestedMultiSelectionResources.java | 2 + 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss index 7e74e3f2513..e9f3544820b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss @@ -30,18 +30,26 @@ overflow: hidden; } -.suggestionsContentToolbar, .suggestionsSelectedItem { +.suggestionsSettingsMenuItem, .suggestionsContentToolbar, .suggestionsSelectedItem { padding: 0.333333333333333em; position: relative; text-align: right; } -.suggestionsAddFilter, .suggestionsItemDescription { +.suggestionsSettingsMenuItemLabel, .suggestionsAddFilter, .suggestionsItemDescription { position: absolute !important; left: 0.333333333333333em; right: 8.666666666666667em; } +.suggestionsSettingsMenuItemLabel, .suggestionsItemDescription { + right: 8.666666666666667em; +} + +.suggestionsAddFilter { + right: 9.666666666666667em; +} + .suggestionsRemoveButton { padding: 0.433333333333333em 1em; position: relative; @@ -53,11 +61,19 @@ border-collapse: separate; } +.suggestionsSettingsMenuItem { + border-bottom: 1px solid #ddd; +} + .suggestionsSelectedItem { border-top: 1px solid #ddd; } -.suggestionsItemDescription { +.suggestionsSettingsMenuItemLabel { + font-weight: 600; +} + +.suggestionsSettingsMenuItemLabel, .suggestionsItemDescription { text-align: left; line-height: 2em; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index ea58186a04a..c326bd8c869 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -30,6 +30,7 @@ public final class SuggestedMultiSelection extends Composite { } @UiField SpanElement headerTitleUi; + @UiField SuggestedMultiSelectionNotificationToggle noticationToggleUi; @UiField(provided = true) AbstractFilterWidget suggestionWidgetUi; @UiField Button removeAllButtonUi; @UiField FlowPanel itemContainerUi; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml index 9b1f12c5385..07003f640ba 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml @@ -1,6 +1,7 @@ + xmlns:sp="urn:import:com.sap.sailing.gwt.home.shared.partials" + xmlns:s="urn:import:com.sap.sailing.gwt.home.desktop.places.user.profile.selection"> @@ -16,6 +17,7 @@
      +
      diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java new file mode 100644 index 00000000000..9a849eb71cf --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java @@ -0,0 +1,51 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.uibinder.client.UiHandler; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HasEnabled; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.common.client.SharedResources; + +class SuggestedMultiSelectionNotificationToggle extends Composite implements HasEnabled { + + private static LocalUiBinder uiBinder = GWT.create(LocalUiBinder.class); + + interface LocalUiBinder extends UiBinder { + } + + @UiField SharedResources res; + @UiField Button toggleButtonUi; + private boolean enabled = false; + + SuggestedMultiSelectionNotificationToggle() { + initWidget(uiBinder.createAndBindUi(this)); + this.updateUiState(); // TODO remove + } + + @UiHandler("toggleButtonUi") + void onToggleButtonClicked(ClickEvent event) { + setEnabled(!isEnabled()); + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + this.updateUiState(); + } + + private void updateUiState() { + toggleButtonUi.setStyleName(res.mainCss().buttonred(), !enabled); + toggleButtonUi.setText(enabled ? "!Enabled!" : "!Disabled!"); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml new file mode 100644 index 00000000000..f20d4a0a885 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml @@ -0,0 +1,10 @@ + + + + + + + TODO Email notification for this category + + + \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java index 5b543aad2b3..3332b49ed8b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java @@ -16,6 +16,8 @@ public interface SuggestedMultiSelectionResources extends ClientBundle { String suggestionsHeader(); String suggestionsHeaderTitle(); String suggestionsContent(); + String suggestionsSettingsMenuItem(); + String suggestionsSettingsMenuItemLabel(); String suggestionsContentToolbar(); String suggestionsAddFilter(); String suggestionsRemoveButton(); From b065a7146f933f14151d5b802d05345383eb062a Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 13 Jun 2016 11:16:07 +0200 Subject: [PATCH 070/259] Fixed potential NPE in AbstractValueSetSetting isDefault method --- .../sap/sse/common/settings/base/AbstractValueSetSetting.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java index ddfab85a7be..f0ab3961a11 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java @@ -44,7 +44,7 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection @Override public boolean isDefaultValue() { ValueCollectionValue> value = getValue(); - return (emptyIsDefault && value.isEmpty()) + return (emptyIsDefault && (value == null || value.isEmpty())) || (value.size() == defaultValues.size() && defaultValues.containsAll(value.getValues(getValueConverter()))); } From 5b2657b380178e0d84238b068bf516695741b571 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 13 Jun 2016 11:20:30 +0200 Subject: [PATCH 071/259] Adjust initialization of AbstractSettings class --- .../src/com/sap/sse/common/settings/AbstractSettings.java | 1 - 1 file changed, 1 deletion(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index fdc15df0159..de9018c2093 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -89,7 +89,6 @@ public abstract class AbstractSettings extends AbstractSetting implements Settin value = new SettingsValue(); settings.setValue(name, value); } - settings.setValue(name, value); addChildSettingsInternal(); } From 1709dbf1a02dba112315e652f4f6355a4c866f94 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 14 Jun 2016 08:51:33 +0200 Subject: [PATCH 072/259] Added default write to SerializableSettings writeObject method --- .../src/com/sap/sse/common/settings/SerializableSettings.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java index de99770a70a..7b65bc18c69 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java @@ -28,6 +28,7 @@ public abstract class SerializableSettings extends AbstractSettings implements S @GwtIncompatible private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); SettingsValue innerValueObject = getInnerValueObject(); out.writeObject(innerValueObject); } From 3050a307454c886730f1564c67a3bb5ce378d077 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 29 Jun 2016 16:18:34 +0200 Subject: [PATCH 073/259] Adjusted layout style to ensure space for wrapped text in SuggestedMultiSelectionNotificationToggle --- .../selection/SuggestedMultiSelection.gss | 17 +++++++++++++---- ...estedMultiSelectionNotificationToggle.ui.xml | 2 +- .../SuggestedMultiSelectionResources.java | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss index e9f3544820b..397a5d5c1ea 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss @@ -36,14 +36,24 @@ text-align: right; } -.suggestionsSettingsMenuItemLabel, .suggestionsAddFilter, .suggestionsItemDescription { +.suggestionsAddFilter, .suggestionsItemDescription { position: absolute !important; left: 0.333333333333333em; right: 8.666666666666667em; } -.suggestionsSettingsMenuItemLabel, .suggestionsItemDescription { - right: 8.666666666666667em; +.suggestionsSettingsMenuItemLabel { + padding-right: 8.666666666666667em +} + +.suggestionsRemoveButton ,.suggestionsToggleButton { + padding: 0.433333333333333em 1em; +} + +.suggestionsToggleButton { + position: absolute; + right: 0.333333333333333em; + top: 0.333333333333333em; } .suggestionsAddFilter { @@ -51,7 +61,6 @@ } .suggestionsRemoveButton { - padding: 0.433333333333333em 1em; position: relative; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml index f20d4a0a885..3edbcaa3b04 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml @@ -5,6 +5,6 @@ TODO Email notification for this category - + \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java index 3332b49ed8b..e7905df2270 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java @@ -18,6 +18,7 @@ public interface SuggestedMultiSelectionResources extends ClientBundle { String suggestionsContent(); String suggestionsSettingsMenuItem(); String suggestionsSettingsMenuItemLabel(); + String suggestionsToggleButton(); String suggestionsContentToolbar(); String suggestionsAddFilter(); String suggestionsRemoveButton(); From c99d373579e74753ef6aba954830f41afed20888 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 29 Jun 2016 17:06:41 +0200 Subject: [PATCH 074/259] Adjusted SuggestedMultiSelectionDataProvider class hierarchy --- ...ctSuggestedMultiSelectionDataProvider.java | 65 +++++++++++++++++++ .../SuggestedMultiSelectionDataProvider.java | 2 + ...ggestedMultiSelectionListDataProvider.java | 33 +--------- 3 files changed, 70 insertions(+), 30 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java new file mode 100644 index 00000000000..931a7b6f140 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java @@ -0,0 +1,65 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class AbstractSuggestedMultiSelectionDataProvider + implements SuggestedMultiSelectionDataProvider { + + private final Map selectedItemsMap = new HashMap<>(); + private boolean notificationsEnabled; + + @Override + public final void addSelection(T item) { + Object key = getKey(item); + selectedItemsMap.put(key, item); + } + + @Override + public final void removeSelection(T item) { + Object key = getKey(item); + selectedItemsMap.remove(key); + } + + @Override + public final void clearSelection() { + selectedItemsMap.clear(); + } + + @Override + public final void setNotifications(boolean enabled) { + notificationsEnabled = enabled; + } + + @Override + public final void getSuggestionItems(String query, final SuggestionItemsCallback callback) { + final SuggestionItemsCallback internalCallback = new SuggestionItemsCallback() { + @Override + public void setSuggestionItems(Collection suggestionItems) { + List filteredSuggestionItems = new ArrayList<>(); + for (T item : suggestionItems) { + Object key = getKey(item); + if (!selectedItemsMap.containsKey(key)) { + filteredSuggestionItems.add(item); + } + } + callback.setSuggestionItems(filteredSuggestionItems); + } + }; + this.getSuggestions(query, internalCallback); + } + + protected abstract void getSuggestions(String query, SuggestionItemsCallback callback); + + public boolean isNotificationsEnabled() { + return notificationsEnabled; + } + + public Collection getSelectedItems() { + return new ArrayList<>(selectedItemsMap.values()); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java index 8b426fe2f37..ff7373da51a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java @@ -12,6 +12,8 @@ public interface SuggestedMultiSelectionDataProvider extends ProvidesKey { void clearSelection(); + void setNotifications(boolean enabled); + void getSuggestionItems(String query, final SuggestionItemsCallback callback); interface SuggestionItemsCallback { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java index 414352c4f3f..c65a48e5837 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java @@ -2,15 +2,12 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; -import java.util.Map; import com.google.gwt.view.client.ProvidesKey; -public class SuggestedMultiSelectionListDataProvider implements SuggestedMultiSelectionDataProvider { +public class SuggestedMultiSelectionListDataProvider extends AbstractSuggestedMultiSelectionDataProvider { - private final Map selectedItemsMap = new HashMap<>(); private final ProvidesKey keyProvider; private final List suggestionItemsList = new ArrayList(); @@ -23,38 +20,14 @@ public class SuggestedMultiSelectionListDataProvider implements SuggestedMult return keyProvider == null ? item : keyProvider.getKey(item); } - @Override - public void addSelection(T item) { - Object key = getKey(item); - selectedItemsMap.put(key, item); - } - - @Override - public void removeSelection(T item) { - Object key = getKey(item); - selectedItemsMap.remove(key); - } - - @Override - public void clearSelection() { - selectedItemsMap.clear(); - } - public void setSuggestionItems(Collection suggestionItems) { suggestionItemsList.clear(); suggestionItemsList.addAll(suggestionItems); } @Override - public void getSuggestionItems(String query, final SuggestionItemsCallback callback) { - List filteredSuggestionItems = new ArrayList<>(); - for (T item : suggestionItemsList) { - Object key = getKey(item); - if (!selectedItemsMap.containsKey(key)) { - filteredSuggestionItems.add(item); - } - } - callback.setSuggestionItems(filteredSuggestionItems); + protected void getSuggestions(String query, SuggestionItemsCallback callback) { + callback.setSuggestionItems(suggestionItemsList); } } From 4f870fccb9deb7c8ac024f787be37523b9f393ae Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 29 Jun 2016 17:51:12 +0200 Subject: [PATCH 075/259] Removed samples for competitor selections --- .../UserProfilePreferencesPresenter.java | 43 ++++++++----------- .../UserProfilePreferencesView.java | 6 +-- .../UserProfilePreferencesViewImpl.java | 20 +++------ .../UserProfilePreferencesViewImpl.ui.xml | 12 +++--- 4 files changed, 32 insertions(+), 49 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 8110ca3c561..9fed79381a0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -1,11 +1,9 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; import java.util.Arrays; -import java.util.List; import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionListDataProvider; @@ -15,16 +13,11 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi private final UserProfilePreferencesView view; private final UserProfileView.Presenter userProfilePresenter; -// private final UserDetailsPresenter userDetailsPresenter; public UserProfilePreferencesPresenter(UserProfilePreferencesView view, UserProfileView.Presenter userProfilePresenter) { this.view = view; this.userProfilePresenter = userProfilePresenter; view.setPresenter(this); -// this.userDetailsPresenter = new UserDetailsPresenter(view.getUserDetailsView(), -// userProfilePresenter.getAuthenticationManager(), userProfilePresenter.getUserManagementService(), -// userProfilePresenter.getMailVerifiedUrl()); - view.setFavouriteCompetitors(competitorsDummyData); view.setFavouriteBoatClasses(Arrays.asList( BoatClassMasterdata.KIELZUGVOGEL, BoatClassMasterdata.J22)); @@ -42,7 +35,7 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public SuggestedMultiSelectionDataProvider getBoatClassDataProvider() { + public SuggestedMultiSelectionDataProvider getFavouriteBoatClassesDataProvider() { SuggestedMultiSelectionListDataProvider dataProvider = new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { @Override @@ -54,21 +47,21 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi return dataProvider; } - @Override - public SuggestedMultiSelectionDataProvider getCompetitorDataProvider() { - SuggestedMultiSelectionListDataProvider dataProvider = - new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { - @Override - public Object getKey(SimpleCompetitorDTO item) { - return item.getSailID(); - } - }); - dataProvider.setSuggestionItems(competitorsDummyData); - return dataProvider; - } - - private final List competitorsDummyData = Arrays.asList( - new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), - new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), - new SimpleCompetitorDTO("Competitor with a long name to test wrapping in favourite list", "USA 1337", "us", null)); +// @Override +// public SuggestedMultiSelectionDataProvider getFavouriteCompetitorsDataProvider() { +// SuggestedMultiSelectionListDataProvider dataProvider = +// new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { +// @Override +// public Object getKey(SimpleCompetitorDTO item) { +// return item.getSailID(); +// } +// }); +// dataProvider.setSuggestionItems(competitorsDummyData); +// return dataProvider; +// } +// +// private final List competitorsDummyData = Arrays.asList( +// new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), +// new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), +// new SimpleCompetitorDTO("Competitor with a long name to test wrapping in favourite list", "USA 1337", "us", null)); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index 9482122ed79..aa1bcff3656 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -18,14 +18,12 @@ public interface UserProfilePreferencesView extends IsWidget { NeedsAuthenticationContext getDecorator(); - void setCompetitorsIBelongTo(Collection selectedItems); - void setFavouriteCompetitors(Collection selectedItems); void setFavouriteBoatClasses(Collection selectedItems); public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext { - SuggestedMultiSelectionDataProvider getBoatClassDataProvider(); - SuggestedMultiSelectionDataProvider getCompetitorDataProvider(); + SuggestedMultiSelectionDataProvider getFavouriteBoatClassesDataProvider(); +// SuggestedMultiSelectionDataProvider getFavouriteCompetitorsDataProvider(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 12659850174..853b7a73721 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -22,8 +22,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro private static MyBinder uiBinder = GWT.create(MyBinder.class); @UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi; - @UiField(provided = true) SuggestedMultiSelection competitorsIBelongToSelctionUi; - @UiField(provided = true) SuggestedMultiSelection favouriteCompetitorsSelctionUi; +// @UiField(provided = true) SuggestedMultiSelection favouriteCompetitorsSelctionUi; @UiField(provided = true) SuggestedMultiSelection favouriteBoatClassesSelctionUi; public UserDetailsView getUserDetailsView() { @@ -33,23 +32,16 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @Override public void setPresenter(Presenter presenter) { decoratorUi = new AuthorizedContentDecoratorDesktop(presenter); - competitorsIBelongToSelctionUi = SuggestedMultiSelection.forCompetitors(presenter.getCompetitorDataProvider(), - "TODO Competitors I belong to"); - favouriteCompetitorsSelctionUi = SuggestedMultiSelection.forCompetitors(presenter.getCompetitorDataProvider(), - "TODO Favourite competitors"); - favouriteBoatClassesSelctionUi = SuggestedMultiSelection.forBoatClasses(presenter.getBoatClassDataProvider(), - "TODO Favourite boat classes"); +// favouriteCompetitorsSelctionUi = SuggestedMultiSelection +// .forCompetitors(presenter.getFavouriteCompetitorDataProvider(), "TODO Favourite competitors"); + favouriteBoatClassesSelctionUi = SuggestedMultiSelection + .forBoatClasses(presenter.getFavouriteBoatClassesDataProvider(), "TODO Favourite boat classes"); initWidget(uiBinder.createAndBindUi(this)); } - @Override - public void setCompetitorsIBelongTo(Collection selectedItems) { - competitorsIBelongToSelctionUi.setSelectedItems(selectedItems); - } - @Override public void setFavouriteCompetitors(Collection selectedItems) { - favouriteCompetitorsSelctionUi.setSelectedItems(selectedItems); +// favouriteCompetitorsSelctionUi.setSelectedItems(selectedItems); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml index 1f45327c1fd..b226980e0e1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml @@ -9,13 +9,13 @@ + + + + + +
      - -
      -
      - -
      -
      From 14a88dd44be1837378301f3a3de2bd38b4812f88 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 29 Jun 2016 17:51:41 +0200 Subject: [PATCH 076/259] Added ClickHandler to notifiaction toggle button --- .../user/profile/selection/SuggestedMultiSelection.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index c326bd8c869..37dd9fc801d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -6,6 +6,7 @@ import java.util.Collection; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.SpanElement; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; @@ -50,6 +51,13 @@ public final class SuggestedMultiSelection extends Composite { }); initWidget(uiBinder.createAndBindUi(this)); headerTitleUi.setInnerText(title); + noticationToggleUi.toggleButtonUi.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + final boolean enabled = noticationToggleUi.isEnabled(); + SuggestedMultiSelection.this.dataProvider.setNotifications(enabled); + } + }); this.updateUiState(); } From 541ec499c6d02fc4477c6f928590b5c1de2712f7 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 30 Jun 2016 09:58:55 +0200 Subject: [PATCH 077/259] Adjusted matching strings for boat class suggestion filter --- .../domain/common/BoatClassMasterdata.java | 15 +++++++++++++++ .../selection/SuggestedMultiSelection.java | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java index 102ba7d4ccf..076bb255d99 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/BoatClassMasterdata.java @@ -210,6 +210,21 @@ public enum BoatClassMasterdata { public boolean hasAdditionalDownwindSail() { return hasAdditionalDownwindSail; } + + /** + * Gets the list of names for this {@link BoatClassMasterdata} instance, containing its + * {@link #displayName display name} and the {@link #alternativeNames alternative names} (if any). + * + * @return the list of names for the boat class + */ + public Iterable getBoatClassNames() { + List result = new ArrayList<>(getAlternativeNames().length + 1); + result.add(this.getDisplayName()); + for (String alternativeName : this.getAlternativeNames()) { + result.add(alternativeName); + } + return result; + } public static Iterable getAllBoatClassNames(boolean includeAlternativeNames) { final List result = new ArrayList<>(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index 37dd9fc801d..f6b4e0b0296 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -191,7 +191,7 @@ public final class SuggestedMultiSelection extends Composite { @Override protected Iterable getMatchingStrings(BoatClassMasterdata value) { - return Arrays.asList(value.getAlternativeNames()); + return value.getBoatClassNames(); } }; } From 634a7fc6fbc263093d96539102bedd2e58b4a9a4 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 30 Jun 2016 13:28:34 +0200 Subject: [PATCH 078/259] Readded sample for favorite competitor selection --- .../UserProfilePreferencesPresenter.java | 40 ++++++++++--------- .../UserProfilePreferencesView.java | 4 +- .../UserProfilePreferencesViewImpl.java | 16 ++++---- .../UserProfilePreferencesViewImpl.ui.xml | 13 +++--- 4 files changed, 36 insertions(+), 37 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 9fed79381a0..86f65bc0504 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -1,9 +1,11 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; import java.util.Arrays; +import java.util.List; import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionListDataProvider; @@ -21,12 +23,12 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi view.setFavouriteBoatClasses(Arrays.asList( BoatClassMasterdata.KIELZUGVOGEL, BoatClassMasterdata.J22)); + view.setFavouriteCompetitors(competitorsDummyData); } @Override public void setAuthenticationContext(AuthenticationContext authenticationContext) { view.getDecorator().setAuthenticationContext(authenticationContext); -// userDetailsPresenter.setAuthenticationContext(authenticationContext); } @Override @@ -35,7 +37,7 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public SuggestedMultiSelectionDataProvider getFavouriteBoatClassesDataProvider() { + public SuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider() { SuggestedMultiSelectionListDataProvider dataProvider = new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { @Override @@ -47,21 +49,21 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi return dataProvider; } -// @Override -// public SuggestedMultiSelectionDataProvider getFavouriteCompetitorsDataProvider() { -// SuggestedMultiSelectionListDataProvider dataProvider = -// new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { -// @Override -// public Object getKey(SimpleCompetitorDTO item) { -// return item.getSailID(); -// } -// }); -// dataProvider.setSuggestionItems(competitorsDummyData); -// return dataProvider; -// } -// -// private final List competitorsDummyData = Arrays.asList( -// new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), -// new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), -// new SimpleCompetitorDTO("Competitor with a long name to test wrapping in favourite list", "USA 1337", "us", null)); + @Override + public SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider() { + SuggestedMultiSelectionListDataProvider dataProvider = + new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { + @Override + public Object getKey(SimpleCompetitorDTO item) { + return item.getSailID(); + } + }); + dataProvider.setSuggestionItems(competitorsDummyData); + return dataProvider; + } + + private final List competitorsDummyData = Arrays.asList( + new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), + new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), + new SimpleCompetitorDTO("Competitor with a long name to test wrapping in favourite list", "USA 1337", "us", null)); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index aa1bcff3656..ee3169a1ff0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -23,7 +23,7 @@ public interface UserProfilePreferencesView extends IsWidget { void setFavouriteBoatClasses(Collection selectedItems); public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext { - SuggestedMultiSelectionDataProvider getFavouriteBoatClassesDataProvider(); -// SuggestedMultiSelectionDataProvider getFavouriteCompetitorsDataProvider(); + SuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider(); + SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 853b7a73721..2734d477ba8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -22,8 +22,8 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro private static MyBinder uiBinder = GWT.create(MyBinder.class); @UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi; -// @UiField(provided = true) SuggestedMultiSelection favouriteCompetitorsSelctionUi; - @UiField(provided = true) SuggestedMultiSelection favouriteBoatClassesSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; public UserDetailsView getUserDetailsView() { return null; @@ -32,21 +32,21 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @Override public void setPresenter(Presenter presenter) { decoratorUi = new AuthorizedContentDecoratorDesktop(presenter); -// favouriteCompetitorsSelctionUi = SuggestedMultiSelection -// .forCompetitors(presenter.getFavouriteCompetitorDataProvider(), "TODO Favourite competitors"); - favouriteBoatClassesSelctionUi = SuggestedMultiSelection - .forBoatClasses(presenter.getFavouriteBoatClassesDataProvider(), "TODO Favourite boat classes"); + favoriteCompetitorsSelctionUi = SuggestedMultiSelection + .forCompetitors(presenter.getFavoriteCompetitorsDataProvider(), "TODO Favourite competitors"); + favoriteBoatClassesSelctionUi = SuggestedMultiSelection + .forBoatClasses(presenter.getFavoriteBoatClassesDataProvider(), "TODO Favourite boat classes"); initWidget(uiBinder.createAndBindUi(this)); } @Override public void setFavouriteCompetitors(Collection selectedItems) { -// favouriteCompetitorsSelctionUi.setSelectedItems(selectedItems); + favoriteCompetitorsSelctionUi.setSelectedItems(selectedItems); } @Override public void setFavouriteBoatClasses(Collection selectedItems) { - favouriteBoatClassesSelctionUi.setSelectedItems(selectedItems); + favoriteBoatClassesSelctionUi.setSelectedItems(selectedItems); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml index b226980e0e1..367de349c4d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml @@ -9,14 +9,11 @@ - - - - - - -
      - +
      + +
      +
      +
      From 52edd9d5989ec0e7759f664c97398ca67dca609b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 30 Jun 2016 13:48:16 +0200 Subject: [PATCH 079/259] Adjustments to serialization behavior of AbstractSetting(s) --- .../src/com/sap/sse/common/settings/AbstractSetting.java | 4 ++-- .../src/com/sap/sse/common/settings/AbstractSettings.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java index 360fc35f71e..abc472ee88c 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java @@ -4,8 +4,8 @@ package com.sap.sse.common.settings; public abstract class AbstractSetting implements Setting { - protected final AbstractSettings settings; - protected final String settingName; + protected transient final AbstractSettings settings; + protected transient final String settingName; public AbstractSetting(String settingName, AbstractSettings settings) { this.settingName = settingName; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index de9018c2093..c4bdb5ea2a7 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -65,7 +65,7 @@ import com.sap.sse.common.settings.value.Value; * */ public abstract class AbstractSettings extends AbstractSetting implements Settings { - private transient SettingsValue value; + private SettingsValue value; private transient Map childSettings; /** From 38affe46a7f826e9bf3417e7a4a3bb4ac1c5f0fa Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 30 Jun 2016 14:23:18 +0200 Subject: [PATCH 080/259] Introduced a specific superclass for generic serializable settings and moved all related classes to a specific subpackage --- .../RegattaOverviewBaseSettings.java | 9 +- .../RegattaRaceStatesSettings.java | 11 +- java/com.sap.sse.common/META-INF/MANIFEST.MF | 5 +- .../sse/common/settings/AbstractSettings.java | 164 +----------- .../sse/common/settings/BooleanSetting.java | 15 -- .../common/settings/DecimalListSetting.java | 12 - .../sse/common/settings/DecimalSetting.java | 17 -- .../common/settings/DoubleListSetting.java | 10 - .../sse/common/settings/DoubleSetting.java | 15 -- .../sse/common/settings/EnumListSetting.java | 10 - .../sap/sse/common/settings/EnumSetting.java | 15 -- .../common/settings/SerializableSettings.java | 28 -- .../com/sap/sse/common/settings/Settings.java | 14 +- .../common/settings/SettingsListSetting.java | 4 - .../common/settings/StringListSetting.java | 10 - .../sse/common/settings/StringSetSetting.java | 22 -- .../sse/common/settings/StringSetting.java | 15 -- .../sse/common/settings/UUIDListSetting.java | 12 - .../sse/common/settings/UUIDSetSetting.java | 24 -- .../sap/sse/common/settings/UUIDSetting.java | 17 -- .../base/AbstractHasValueSetting.java | 21 -- .../AbstractGenericSerializableSettings.java | 240 ++++++++++++++++++ .../{ => generic}/AbstractSetting.java | 6 +- .../settings/generic/BooleanSetting.java | 15 ++ .../{ => generic}/CollectionSetting.java | 2 +- .../settings/generic/DecimalListSetting.java | 12 + .../settings/generic/DecimalSetting.java | 17 ++ .../settings/generic/DoubleListSetting.java | 10 + .../settings/generic/DoubleSetting.java | 15 ++ .../settings/generic/EnumListSetting.java | 10 + .../common/settings/generic/EnumSetting.java | 15 ++ .../generic/GenericSerializableSettings.java | 19 ++ .../{ => generic}/HasSettingsFactory.java | 4 +- .../{ => generic}/HasValueSetting.java | 2 +- .../settings/{ => generic}/Setting.java | 4 +- .../{ => generic}/SettingsFactory.java | 4 +- .../settings/{ => generic}/SettingsList.java | 6 +- .../settings/generic/SettingsListSetting.java | 4 + .../settings/generic/StringListSetting.java | 10 + .../settings/generic/StringSetSetting.java | 22 ++ .../settings/generic/StringSetting.java | 15 ++ .../{ => generic}/StringToEnumConverter.java | 2 +- .../settings/generic/UUIDListSetting.java | 12 + .../settings/generic/UUIDSetSetting.java | 24 ++ .../common/settings/generic/UUIDSetting.java | 17 ++ .../{ => generic}/ValueCollectionSetting.java | 2 +- .../{ => generic}/ValueConverter.java | 2 +- .../{ => generic}/ValueSetSetting.java | 2 +- .../settings/{ => generic}/ValueSetting.java | 2 +- .../generic/base/AbstractHasValueSetting.java | 21 ++ .../base/AbstractValueCollectionSetting.java | 10 +- .../base/AbstractValueListSetting.java | 8 +- .../base/AbstractValueSetSetting.java | 16 +- .../base/AbstractValueSetting.java | 10 +- .../converter/BooleanConverter.java | 4 +- .../converter/DecimalConverter.java | 4 +- .../converter/DoubleConverter.java | 4 +- .../converter/EnumConverter.java | 6 +- .../converter/StringConverter.java | 4 +- .../converter/UUIDConverter.java | 4 +- .../AbstractSettingsToJsonSerializer.java | 31 +-- .../SettingsToStringMapSerializer.java | 42 +-- .../settings/value/ValueCollection.java | 2 +- .../settings/value/ValueCollectionValue.java | 2 +- ...ractEntryPointWithSettingsLinkFactory.java | 6 +- .../settings/SettingsToJsonSerializerGWT.java | 6 +- .../gwt/settings/SettingsToUrlSerializer.java | 18 +- .../AbstractSettingsSerializationTest.java | 45 ++-- .../test/SettingsJavaSerializationTest.java | 6 +- .../test/SettingsToJsonSerializationTest.java | 6 +- .../SettingsToStringMapSerializationTest.java | 6 +- .../META-INF/MANIFEST.MF | 5 +- 72 files changed, 640 insertions(+), 571 deletions(-) delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java delete mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/AbstractSetting.java (62%) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/BooleanSetting.java rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/CollectionSetting.java (75%) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/HasSettingsFactory.java (53%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/HasValueSetting.java (68%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/Setting.java (80%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/SettingsFactory.java (80%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/SettingsList.java (91%) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetting.java rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/StringToEnumConverter.java (91%) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDListSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetSetting.java create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetting.java rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/ValueCollectionSetting.java (68%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/ValueConverter.java (87%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/ValueSetSetting.java (74%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/ValueSetting.java (71%) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractHasValueSetting.java rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/base/AbstractValueCollectionSetting.java (86%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/base/AbstractValueListSetting.java (72%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/base/AbstractValueSetSetting.java (70%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/base/AbstractValueSetting.java (84%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/converter/BooleanConverter.java (89%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/converter/DecimalConverter.java (90%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/converter/DoubleConverter.java (89%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/converter/EnumConverter.java (86%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/converter/StringConverter.java (88%) rename java/com.sap.sse.common/src/com/sap/sse/common/settings/{ => generic}/converter/UUIDConverter.java (89%) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java index 536d6190d24..412d4d57bc3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java @@ -2,11 +2,12 @@ package com.sap.sailing.gwt.settings.client.regattaoverview; import java.util.UUID; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.BooleanSetting; -import com.sap.sse.common.settings.UUIDSetting; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.BooleanSetting; +import com.sap.sse.common.settings.generic.UUIDSetting; -public final class RegattaOverviewBaseSettings extends AbstractSettings { +public final class RegattaOverviewBaseSettings extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -8541790130000694098L; private UUIDSetting event; private BooleanSetting ignoreLocalSettings; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java index 58c6314f494..e32720c857d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java @@ -7,12 +7,13 @@ import java.util.UUID; import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.RaceGroupDTO; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.BooleanSetting; -import com.sap.sse.common.settings.StringSetSetting; -import com.sap.sse.common.settings.UUIDSetSetting; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.BooleanSetting; +import com.sap.sse.common.settings.generic.StringSetSetting; +import com.sap.sse.common.settings.generic.UUIDSetSetting; -public final class RegattaRaceStatesSettings extends AbstractSettings { +public final class RegattaRaceStatesSettings extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = 7059340304556830062L; private UUIDSetSetting visibleCourseAreas; private StringSetSetting visibleRegattas; private BooleanSetting showOnlyRacesOfSameDay; diff --git a/java/com.sap.sse.common/META-INF/MANIFEST.MF b/java/com.sap.sse.common/META-INF/MANIFEST.MF index 5265a8e68f2..397e8dde2ee 100644 --- a/java/com.sap.sse.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.common/META-INF/MANIFEST.MF @@ -13,8 +13,9 @@ Export-Package: com.sap.sse.common, com.sap.sse.common.scalablevalue, com.sap.sse.common.search, com.sap.sse.common.settings, - com.sap.sse.common.settings.base, - com.sap.sse.common.settings.converter, + com.sap.sse.common.settings.generic, + com.sap.sse.common.settings.generic.base, + com.sap.sse.common.settings.generic.converter, com.sap.sse.common.settings.serializer, com.sap.sse.common.util Require-Bundle: com.sap.sse.datamining.annotations diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index c4bdb5ea2a7..8b732d0b7f3 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -1,11 +1,6 @@ package com.sap.sse.common.settings; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.sap.sse.common.settings.value.SettingsValue; -import com.sap.sse.common.settings.value.Value; +import com.sap.sse.common.settings.generic.Setting; /** * Common superclass for custom Settings used by Components. The following example shows how to implement custom @@ -64,160 +59,5 @@ import com.sap.sse.common.settings.value.Value; * based on the child {@link Setting}s which should be sufficient for most cases. * */ -public abstract class AbstractSettings extends AbstractSetting implements Settings { - private SettingsValue value; - private transient Map childSettings; - - /** - * Default constructor for direct instantiation of root settings objects. - */ - public AbstractSettings() { - value = new SettingsValue(); - addChildSettingsInternal(); - } - - /** - * Constructor for automatic attachment of a child settings object to its parent settings object. - * - * @param name the name of the child setting - * @param settings the parent settings to attach this settings object to - */ - public AbstractSettings(String name, AbstractSettings settings) { - super(name, settings); - value = (SettingsValue) settings.getValue(name); - if(value == null) { - value = new SettingsValue(); - settings.setValue(name, value); - } - addChildSettingsInternal(); - } - - /** - * Internal use only for correct lifecycle of {@link SettingsList}. - */ - protected void adoptValue(SettingsValue value) { - this.value = value; - if(childSettings != null) { - for(Map.Entry entry : childSettings.entrySet()) { - Setting childSetting = entry.getValue(); - if(childSetting instanceof AbstractSettings) { - Value childValue = value.getValue(entry.getKey()); - if(childValue != null) { - ((AbstractSettings) childSetting).adoptValue((SettingsValue) childValue); - } - } - if(childSetting instanceof SettingsList) { - Value childValue = value.getValue(entry.getKey()); - if(childValue != null) { - ((SettingsList) childSetting).adoptValue(); - } - } - } - } - } - - protected SettingsValue getInnerValueObject() { - return value; - } - - protected final void addChildSettingsInternal() { - if(childSettings == null) { - childSettings = new HashMap<>(); - addChildSettings(); - } - } - - /** - * Overwrite this method to initialize child settings. - * {@link AbstractSettings} for an example. - * - * TODO make abstract when all Settings are ported to the new system - * - */ - protected void addChildSettings() { - } - - // TODO make protected - public Value getValue(String settingName) { - return value.getValue(settingName); - } - - // TODO make protected - public void setValue(String settingName, Value value) { - this.value.setValue(settingName, value); - } - - protected void addSetting(String name, Setting setting) { - if (name.contains(Settings.PATH_SEPARATOR)) { - throw new IllegalArgumentException("\"" + Settings.PATH_SEPARATOR - + "\" is currently not allowed for setting names"); - } - if (childSettings.containsKey(name)) { - throw new IllegalArgumentException("setting with name " + name + " already added to setting type " - + getClass().getSimpleName()); - } - childSettings.put(name, setting); - } - - @Override - public boolean isDefaultValue() { - for (Setting setting : childSettings.values()) { - if (!setting.isDefaultValue()) { - return false; - } - } - return true; - } - - @Override - public void resetToDefault() { - for (Setting setting : childSettings.values()) { - setting.resetToDefault(); - } - } - - @Override - public Map getChildSettings() { - return Collections.unmodifiableMap(childSettings); - } - - public String toString() { - StringBuilder sb = new StringBuilder("{(").append(this.getClass().getSimpleName()).append(")"); - boolean first = true; - for (Map.Entry childSetting : childSettings.entrySet()) { - if (!first) { - sb.append("; "); - } - sb.append(childSetting.getKey() + "=" + childSetting.getValue()); - - first = false; - } - sb.append("}"); - return sb.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((childSettings == null) ? 0 : childSettings.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; - AbstractSettings other = (AbstractSettings) obj; - if (childSettings == null) { - if (other.childSettings != null) - return false; - } else if (!childSettings.equals(other.childSettings)) - return false; - return true; - } +public abstract class AbstractSettings implements Settings { } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java deleted file mode 100644 index 4914d179301..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/BooleanSetting.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueSetting; -import com.sap.sse.common.settings.converter.BooleanConverter; - -public class BooleanSetting extends AbstractValueSetting { - - public BooleanSetting(String name, AbstractSettings settings) { - this(name, settings, null); - } - - public BooleanSetting(String name, AbstractSettings settings, Boolean defaultValue) { - super(name, settings, defaultValue, BooleanConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java deleted file mode 100644 index c7454c7453b..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalListSetting.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.sap.sse.common.settings; - -import java.math.BigDecimal; - -import com.sap.sse.common.settings.base.AbstractValueListSetting; -import com.sap.sse.common.settings.converter.DecimalConverter; - -public class DecimalListSetting extends AbstractValueListSetting { - public DecimalListSetting(String name, AbstractSettings settings) { - super(name, settings, DecimalConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java deleted file mode 100644 index 0ba4220690e..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DecimalSetting.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.sap.sse.common.settings; - -import java.math.BigDecimal; - -import com.sap.sse.common.settings.base.AbstractValueSetting; -import com.sap.sse.common.settings.converter.DecimalConverter; - -public class DecimalSetting extends AbstractValueSetting { - - public DecimalSetting(String name, AbstractSettings settings) { - this(name, settings, null); - } - - public DecimalSetting(String name, AbstractSettings settings, BigDecimal defaultValue) { - super(name, settings, defaultValue, DecimalConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java deleted file mode 100644 index 03569717e46..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleListSetting.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueListSetting; -import com.sap.sse.common.settings.converter.DoubleConverter; - -public class DoubleListSetting extends AbstractValueListSetting { - public DoubleListSetting(String name, AbstractSettings settings) { - super(name, settings, DoubleConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java deleted file mode 100644 index b214e5e8808..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/DoubleSetting.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueSetting; -import com.sap.sse.common.settings.converter.DoubleConverter; - -public class DoubleSetting extends AbstractValueSetting { - - public DoubleSetting(String name, AbstractSettings settings) { - this(name, settings, null); - } - - public DoubleSetting(String name, AbstractSettings settings, Double defaultValue) { - super(name, settings, defaultValue, DoubleConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java deleted file mode 100644 index 428a87dc425..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumListSetting.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueListSetting; -import com.sap.sse.common.settings.converter.EnumConverter; - -public class EnumListSetting> extends AbstractValueListSetting { - public EnumListSetting(String name, AbstractSettings settings, StringToEnumConverter stringToEnumConverter) { - super(name, settings, new EnumConverter<>(stringToEnumConverter)); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java deleted file mode 100644 index 7968c295642..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/EnumSetting.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueSetting; -import com.sap.sse.common.settings.converter.EnumConverter; - -public class EnumSetting> extends AbstractValueSetting { - - public EnumSetting(String name, AbstractSettings settings, StringToEnumConverter stringToEnumConverter) { - this(name, settings, null, stringToEnumConverter); - } - - public EnumSetting(String name, AbstractSettings settings, T defaultValue, StringToEnumConverter stringToEnumConverter) { - super(name, settings, defaultValue, new EnumConverter<>(stringToEnumConverter)); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java index 7b65bc18c69..a2de8e9aeb1 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java @@ -1,35 +1,7 @@ package com.sap.sse.common.settings; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.Serializable; -import com.sap.sse.common.settings.value.SettingsValue; - public abstract class SerializableSettings extends AbstractSettings implements Serializable { - private static final long serialVersionUID = -2710627501473421333L; - - public SerializableSettings() { - super(); - } - - public SerializableSettings(String name, AbstractSettings settings) { - super(name, settings); - } - - @GwtIncompatible - private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { - ois.defaultReadObject(); - adoptValue((SettingsValue) ois.readObject()); - addChildSettingsInternal(); - } - - @GwtIncompatible - private void writeObject(ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - SettingsValue innerValueObject = getInnerValueObject(); - out.writeObject(innerValueObject); - } } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java index 34b87b1845a..053de9ab236 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java @@ -1,6 +1,6 @@ package com.sap.sse.common.settings; -import java.util.Map; +import com.sap.sse.common.settings.generic.Setting; /** * A generic format to keep the settings for a Component. Such settings may be initialized with defaults. @@ -39,15 +39,5 @@ import java.util.Map; * @author Axel Uhl (D043530) * */ -public interface Settings extends Setting { - - /** - * Path separator for serializers that construct flat keys for the hierachical settings structures (e.g. URL). - */ - public static final String PATH_SEPARATOR = "."; - - /** - * Obtains all child settings. - */ - Map getChildSettings(); +public interface Settings { } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java deleted file mode 100644 index d1b9ffadf3e..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsListSetting.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.sap.sse.common.settings; - -public interface SettingsListSetting extends CollectionSetting, HasSettingsFactory { -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java deleted file mode 100644 index eed33b568e6..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringListSetting.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueListSetting; -import com.sap.sse.common.settings.converter.StringConverter; - -public class StringListSetting extends AbstractValueListSetting { - public StringListSetting(String name, AbstractSettings settings) { - super(name, settings, StringConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java deleted file mode 100644 index 0f229fa66c9..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetSetting.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueSetSetting; -import com.sap.sse.common.settings.converter.StringConverter; - -public class StringSetSetting extends AbstractValueSetSetting { - public StringSetSetting(String name, AbstractSettings settings) { - super(name, settings, StringConverter.INSTANCE); - } - - public StringSetSetting(String name, AbstractSettings settings, boolean emptyIsDefault) { - super(name, settings, emptyIsDefault, StringConverter.INSTANCE); - } - - public StringSetSetting(String name, AbstractSettings settings, Iterable defaultValues) { - super(name, settings, defaultValues, StringConverter.INSTANCE); - } - - public StringSetSetting(String name, AbstractSettings settings, Iterable defaultValues, boolean emptyIsDefault) { - super(name, settings, defaultValues, emptyIsDefault, StringConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java deleted file mode 100644 index c020d5e88f5..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringSetting.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.sap.sse.common.settings; - -import com.sap.sse.common.settings.base.AbstractValueSetting; -import com.sap.sse.common.settings.converter.StringConverter; - -public class StringSetting extends AbstractValueSetting { - - public StringSetting(String name, AbstractSettings settings) { - this(name, settings, null); - } - - public StringSetting(String name, AbstractSettings settings, String defaultValue) { - super(name, settings, defaultValue, StringConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java deleted file mode 100644 index 083a92368ec..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDListSetting.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.sap.sse.common.settings; - -import java.util.UUID; - -import com.sap.sse.common.settings.base.AbstractValueListSetting; -import com.sap.sse.common.settings.converter.UUIDConverter; - -public class UUIDListSetting extends AbstractValueListSetting { - public UUIDListSetting(String name, AbstractSettings settings) { - super(name, settings, UUIDConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java deleted file mode 100644 index c2d759bf21c..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetSetting.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.sap.sse.common.settings; - -import java.util.UUID; - -import com.sap.sse.common.settings.base.AbstractValueSetSetting; -import com.sap.sse.common.settings.converter.UUIDConverter; - -public class UUIDSetSetting extends AbstractValueSetSetting { - public UUIDSetSetting(String name, AbstractSettings settings) { - super(name, settings, UUIDConverter.INSTANCE); - } - - public UUIDSetSetting(String name, AbstractSettings settings, boolean emptyIsDefault) { - super(name, settings, emptyIsDefault, UUIDConverter.INSTANCE); - } - - public UUIDSetSetting(String name, AbstractSettings settings, Iterable defaultValues) { - super(name, settings, defaultValues, UUIDConverter.INSTANCE); - } - - public UUIDSetSetting(String name, AbstractSettings settings, Iterable defaultValues, boolean emptyIsDefault) { - super(name, settings, defaultValues, emptyIsDefault, UUIDConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java deleted file mode 100644 index 784393c627d..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/UUIDSetting.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.sap.sse.common.settings; - -import java.util.UUID; - -import com.sap.sse.common.settings.base.AbstractValueSetting; -import com.sap.sse.common.settings.converter.UUIDConverter; - -public class UUIDSetting extends AbstractValueSetting { - - public UUIDSetting(String name, AbstractSettings settings) { - this(name, settings, null); - } - - public UUIDSetting(String name, AbstractSettings settings, UUID defaultValue) { - super(name, settings, defaultValue, UUIDConverter.INSTANCE); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java deleted file mode 100644 index 3947245fb69..00000000000 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractHasValueSetting.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.sap.sse.common.settings.base; - -import com.sap.sse.common.settings.AbstractSetting; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.HasValueSetting; -import com.sap.sse.common.settings.ValueConverter; - -public abstract class AbstractHasValueSetting extends AbstractSetting implements HasValueSetting { - - private ValueConverter valueConverter; - - public AbstractHasValueSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { - super(name, settings); - this.valueConverter = valueConverter; - } - - @Override - public ValueConverter getValueConverter() { - return valueConverter; - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java new file mode 100644 index 00000000000..519b19c264c --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java @@ -0,0 +1,240 @@ +package com.sap.sse.common.settings.generic; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.sap.sse.common.settings.GwtIncompatible; +import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.value.SettingsValue; +import com.sap.sse.common.settings.value.Value; + +/** + * Common superclass for custom Settings used by Components. The following example shows how to implement custom + * Settings: + * + *
      + * 
      + * public final class ExampleSettings extends AbstractSettings {
      + *     private transient StringSetting myString;
      + *     private transient BooleanSetting myBoolean;
      + *     
      + *     // Used to create instances for a component
      + *     public ExampleSettings() {
      + *     }
      + *     
      + *     // Used to create nested settings
      + *     public ExampleSettings(String name, AbstractSettings parentSettings) {
      + *         super(name, parentSettings);
      + *     }
      + *     
      + *     @Override
      + *     protected void addChildSettings() {
      + *         myString = new UUIDSetting("myString", this)
      + *         myBoolean = new BooleanSetting("myBoolean", this);
      + *     }
      + *     
      + *     public String getMyString() {
      + *         return this.myString.getValue();
      + *     }
      + *     
      + *     public void setMyString(String myString) {
      + *         return this.myString.setValue(myString);
      + *     }
      + *     
      + *     public boolean isMyBoolean() {
      + *         return this.myBoolean.getValue();
      + *     }
      + *     
      + *     public void setMyBoolean(boolean myBoolean) {
      + *         return this.myBoolean.setValue(myBoolean);
      + *     }
      + * }
      + * 
      + * 
      + * + * To correctly support several kinds of Serialization (Java, GWT and Custom), you need to ensure the following: + *
        + *
      • the Settings class must have a default constructor
      • + *
      • child settings fields need to be transient
      • + *
      • child settings instances must be initialized in {@link #addChildSettings()} method
      • + *
      + * + * If a custom Settings class only has {@link Setting} oder {@link Settings} children that are correctly attached by + * calling their constructor with a name and the parent {@link Settings} you do not need to implement + * {@link #hashCode()}, {@link #equals(Object)} and {@link #toString()}. There are generic implementations of those methods that are + * based on the child {@link Setting}s which should be sufficient for most cases. + * + */ +public abstract class AbstractGenericSerializableSettings extends AbstractSetting implements GenericSerializableSettings { + private static final long serialVersionUID = -415371632804540785L; + private SettingsValue value; + private transient Map childSettings; + + /** + * Default constructor for direct instantiation of root settings objects. + */ + public AbstractGenericSerializableSettings() { + value = new SettingsValue(); + addChildSettingsInternal(); + } + + /** + * Constructor for automatic attachment of a child settings object to its parent settings object. + * + * @param name the name of the child setting + * @param settings the parent settings to attach this settings object to + */ + public AbstractGenericSerializableSettings(String name, AbstractGenericSerializableSettings settings) { + super(name, settings); + value = (SettingsValue) settings.getValue(name); + if(value == null) { + value = new SettingsValue(); + settings.setValue(name, value); + } + addChildSettingsInternal(); + } + + /** + * Internal use only for correct lifecycle of {@link SettingsList}. + */ + protected void adoptValue(SettingsValue value) { + this.value = value; + if(childSettings != null) { + for(Map.Entry entry : childSettings.entrySet()) { + Setting childSetting = entry.getValue(); + if(childSetting instanceof AbstractGenericSerializableSettings) { + Value childValue = value.getValue(entry.getKey()); + if(childValue != null) { + ((AbstractGenericSerializableSettings) childSetting).adoptValue((SettingsValue) childValue); + } + } + if(childSetting instanceof SettingsList) { + Value childValue = value.getValue(entry.getKey()); + if(childValue != null) { + ((SettingsList) childSetting).adoptValue(); + } + } + } + } + } + + protected SettingsValue getInnerValueObject() { + return value; + } + + protected final void addChildSettingsInternal() { + if(childSettings == null) { + childSettings = new HashMap<>(); + addChildSettings(); + } + } + + /** + * Overwrite this method to initialize child settings. + * {@link AbstractGenericSerializableSettings} for an example. + * + * TODO make abstract when all Settings are ported to the new system + * + */ + protected void addChildSettings() { + } + + // TODO make protected + public Value getValue(String settingName) { + return value.getValue(settingName); + } + + // TODO make protected + public void setValue(String settingName, Value value) { + this.value.setValue(settingName, value); + } + + protected void addSetting(String name, Setting setting) { + if (name.contains(GenericSerializableSettings.PATH_SEPARATOR)) { + throw new IllegalArgumentException("\"" + GenericSerializableSettings.PATH_SEPARATOR + + "\" is currently not allowed for setting names"); + } + if (childSettings.containsKey(name)) { + throw new IllegalArgumentException("setting with name " + name + " already added to setting type " + + getClass().getSimpleName()); + } + childSettings.put(name, setting); + } + + @Override + public boolean isDefaultValue() { + for (Setting setting : childSettings.values()) { + if (!setting.isDefaultValue()) { + return false; + } + } + return true; + } + + @Override + public void resetToDefault() { + for (Setting setting : childSettings.values()) { + setting.resetToDefault(); + } + } + + @Override + public Map getChildSettings() { + return Collections.unmodifiableMap(childSettings); + } + + @GwtIncompatible + private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { + ois.defaultReadObject(); + addChildSettingsInternal(); + } + + @GwtIncompatible + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + + public String toString() { + StringBuilder sb = new StringBuilder("{(").append(this.getClass().getSimpleName()).append(")"); + boolean first = true; + for (Map.Entry childSetting : childSettings.entrySet()) { + if (!first) { + sb.append("; "); + } + sb.append(childSetting.getKey() + "=" + childSetting.getValue()); + + first = false; + } + sb.append("}"); + return sb.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((childSettings == null) ? 0 : childSettings.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; + AbstractGenericSerializableSettings other = (AbstractGenericSerializableSettings) obj; + if (childSettings == null) { + if (other.childSettings != null) + return false; + } else if (!childSettings.equals(other.childSettings)) + return false; + return true; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractSetting.java similarity index 62% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractSetting.java index abc472ee88c..b83b7849b36 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractSetting.java @@ -1,13 +1,13 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; public abstract class AbstractSetting implements Setting { - protected transient final AbstractSettings settings; + protected transient final AbstractGenericSerializableSettings settings; protected transient final String settingName; - public AbstractSetting(String settingName, AbstractSettings settings) { + public AbstractSetting(String settingName, AbstractGenericSerializableSettings settings) { this.settingName = settingName; this.settings = settings; if(settings != null) { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/BooleanSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/BooleanSetting.java new file mode 100644 index 00000000000..7e77c253dc8 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/BooleanSetting.java @@ -0,0 +1,15 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.generic.converter.BooleanConverter; + +public class BooleanSetting extends AbstractValueSetting { + + public BooleanSetting(String name, AbstractGenericSerializableSettings settings) { + this(name, settings, null); + } + + public BooleanSetting(String name, AbstractGenericSerializableSettings settings, Boolean defaultValue) { + super(name, settings, defaultValue, BooleanConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/CollectionSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/CollectionSetting.java similarity index 75% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/CollectionSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/CollectionSetting.java index 8a3ab82c555..ba3e40c4348 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/CollectionSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/CollectionSetting.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; public interface CollectionSetting extends Setting { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalListSetting.java new file mode 100644 index 00000000000..cceaf14770c --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalListSetting.java @@ -0,0 +1,12 @@ +package com.sap.sse.common.settings.generic; + +import java.math.BigDecimal; + +import com.sap.sse.common.settings.generic.base.AbstractValueListSetting; +import com.sap.sse.common.settings.generic.converter.DecimalConverter; + +public class DecimalListSetting extends AbstractValueListSetting { + public DecimalListSetting(String name, AbstractGenericSerializableSettings settings) { + super(name, settings, DecimalConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalSetting.java new file mode 100644 index 00000000000..b436699a243 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DecimalSetting.java @@ -0,0 +1,17 @@ +package com.sap.sse.common.settings.generic; + +import java.math.BigDecimal; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.generic.converter.DecimalConverter; + +public class DecimalSetting extends AbstractValueSetting { + + public DecimalSetting(String name, AbstractGenericSerializableSettings settings) { + this(name, settings, null); + } + + public DecimalSetting(String name, AbstractGenericSerializableSettings settings, BigDecimal defaultValue) { + super(name, settings, defaultValue, DecimalConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleListSetting.java new file mode 100644 index 00000000000..5ae268f8e0d --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleListSetting.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueListSetting; +import com.sap.sse.common.settings.generic.converter.DoubleConverter; + +public class DoubleListSetting extends AbstractValueListSetting { + public DoubleListSetting(String name, AbstractGenericSerializableSettings settings) { + super(name, settings, DoubleConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleSetting.java new file mode 100644 index 00000000000..da9b39cbfc5 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/DoubleSetting.java @@ -0,0 +1,15 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.generic.converter.DoubleConverter; + +public class DoubleSetting extends AbstractValueSetting { + + public DoubleSetting(String name, AbstractGenericSerializableSettings settings) { + this(name, settings, null); + } + + public DoubleSetting(String name, AbstractGenericSerializableSettings settings, Double defaultValue) { + super(name, settings, defaultValue, DoubleConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumListSetting.java new file mode 100644 index 00000000000..d014be853b9 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumListSetting.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueListSetting; +import com.sap.sse.common.settings.generic.converter.EnumConverter; + +public class EnumListSetting> extends AbstractValueListSetting { + public EnumListSetting(String name, AbstractGenericSerializableSettings settings, StringToEnumConverter stringToEnumConverter) { + super(name, settings, new EnumConverter<>(stringToEnumConverter)); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumSetting.java new file mode 100644 index 00000000000..d54cf953a89 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/EnumSetting.java @@ -0,0 +1,15 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.generic.converter.EnumConverter; + +public class EnumSetting> extends AbstractValueSetting { + + public EnumSetting(String name, AbstractGenericSerializableSettings settings, StringToEnumConverter stringToEnumConverter) { + this(name, settings, null, stringToEnumConverter); + } + + public EnumSetting(String name, AbstractGenericSerializableSettings settings, T defaultValue, StringToEnumConverter stringToEnumConverter) { + super(name, settings, defaultValue, new EnumConverter<>(stringToEnumConverter)); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java new file mode 100644 index 00000000000..15b23ee516c --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java @@ -0,0 +1,19 @@ +package com.sap.sse.common.settings.generic; + +import java.io.Serializable; +import java.util.Map; + +import com.sap.sse.common.settings.Settings; + +public interface GenericSerializableSettings extends Settings, Setting, Serializable { + + /** + * Path separator for serializers that construct flat keys for the hierachical settings structures (e.g. URL). + */ + public static final String PATH_SEPARATOR = "."; + + /** + * Obtains all child settings. + */ + Map getChildSettings(); +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/HasSettingsFactory.java similarity index 53% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/HasSettingsFactory.java index 9b16b3753d3..d1c37c38d2a 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasSettingsFactory.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/HasSettingsFactory.java @@ -1,4 +1,6 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.Settings; public interface HasSettingsFactory { SettingsFactory getSettingsFactory(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/HasValueSetting.java similarity index 68% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/HasValueSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/HasValueSetting.java index 9400363627b..e375bb47b76 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/HasValueSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/HasValueSetting.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; public interface HasValueSetting extends Setting { ValueConverter getValueConverter(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/Setting.java similarity index 80% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/Setting.java index a95f280d0d1..8de8ca7fc0d 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Setting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/Setting.java @@ -1,6 +1,6 @@ -package com.sap.sse.common.settings; - +package com.sap.sse.common.settings.generic; +import com.sap.sse.common.settings.AbstractSettings; /** * A setting as contained as values in the map returned by {@link AbstractSettings#getSettings()}. This generic diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsFactory.java similarity index 80% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsFactory.java index 15629b0c5f4..86f151238db 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsFactory.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsFactory.java @@ -1,4 +1,6 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.Settings; /** * diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsList.java similarity index 91% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsList.java index 4285ef91a82..68d367db16f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SettingsList.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsList.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; import java.util.ArrayList; import java.util.Collections; @@ -10,12 +10,12 @@ import com.sap.sse.common.settings.value.ValueCollectionValue; import com.sap.sse.common.settings.value.ValueListValue; -public class SettingsList extends AbstractSetting implements SettingsListSetting { +public class SettingsList extends AbstractSetting implements SettingsListSetting { private SettingsFactory settingsFactory; private final List values = new ArrayList<>(); - public SettingsList(String name, AbstractSettings settings, SettingsFactory settingsFactory) { + public SettingsList(String name, AbstractGenericSerializableSettings settings, SettingsFactory settingsFactory) { super(name, settings); this.settingsFactory = settingsFactory; adoptValue(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsListSetting.java new file mode 100644 index 00000000000..72eece7f9b9 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsListSetting.java @@ -0,0 +1,4 @@ +package com.sap.sse.common.settings.generic; + +public interface SettingsListSetting extends CollectionSetting, HasSettingsFactory { +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringListSetting.java new file mode 100644 index 00000000000..74f7ed6615a --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringListSetting.java @@ -0,0 +1,10 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueListSetting; +import com.sap.sse.common.settings.generic.converter.StringConverter; + +public class StringListSetting extends AbstractValueListSetting { + public StringListSetting(String name, AbstractGenericSerializableSettings settings) { + super(name, settings, StringConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetSetting.java new file mode 100644 index 00000000000..9b4cb237a3e --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetSetting.java @@ -0,0 +1,22 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetSetting; +import com.sap.sse.common.settings.generic.converter.StringConverter; + +public class StringSetSetting extends AbstractValueSetSetting { + public StringSetSetting(String name, AbstractGenericSerializableSettings settings) { + super(name, settings, StringConverter.INSTANCE); + } + + public StringSetSetting(String name, AbstractGenericSerializableSettings settings, boolean emptyIsDefault) { + super(name, settings, emptyIsDefault, StringConverter.INSTANCE); + } + + public StringSetSetting(String name, AbstractGenericSerializableSettings settings, Iterable defaultValues) { + super(name, settings, defaultValues, StringConverter.INSTANCE); + } + + public StringSetSetting(String name, AbstractGenericSerializableSettings settings, Iterable defaultValues, boolean emptyIsDefault) { + super(name, settings, defaultValues, emptyIsDefault, StringConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetting.java new file mode 100644 index 00000000000..b1536b19b32 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringSetting.java @@ -0,0 +1,15 @@ +package com.sap.sse.common.settings.generic; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.generic.converter.StringConverter; + +public class StringSetting extends AbstractValueSetting { + + public StringSetting(String name, AbstractGenericSerializableSettings settings) { + this(name, settings, null); + } + + public StringSetting(String name, AbstractGenericSerializableSettings settings, String defaultValue) { + super(name, settings, defaultValue, StringConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringToEnumConverter.java similarity index 91% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringToEnumConverter.java index 0ab5afc4707..83447be94ae 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/StringToEnumConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/StringToEnumConverter.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; /** * GWT can't use reflection. When deserializing Settings that contain {@link Enum} values there must be come conversion diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDListSetting.java new file mode 100644 index 00000000000..3b24a916cb7 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDListSetting.java @@ -0,0 +1,12 @@ +package com.sap.sse.common.settings.generic; + +import java.util.UUID; + +import com.sap.sse.common.settings.generic.base.AbstractValueListSetting; +import com.sap.sse.common.settings.generic.converter.UUIDConverter; + +public class UUIDListSetting extends AbstractValueListSetting { + public UUIDListSetting(String name, AbstractGenericSerializableSettings settings) { + super(name, settings, UUIDConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetSetting.java new file mode 100644 index 00000000000..704a60268d7 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetSetting.java @@ -0,0 +1,24 @@ +package com.sap.sse.common.settings.generic; + +import java.util.UUID; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetSetting; +import com.sap.sse.common.settings.generic.converter.UUIDConverter; + +public class UUIDSetSetting extends AbstractValueSetSetting { + public UUIDSetSetting(String name, AbstractGenericSerializableSettings settings) { + super(name, settings, UUIDConverter.INSTANCE); + } + + public UUIDSetSetting(String name, AbstractGenericSerializableSettings settings, boolean emptyIsDefault) { + super(name, settings, emptyIsDefault, UUIDConverter.INSTANCE); + } + + public UUIDSetSetting(String name, AbstractGenericSerializableSettings settings, Iterable defaultValues) { + super(name, settings, defaultValues, UUIDConverter.INSTANCE); + } + + public UUIDSetSetting(String name, AbstractGenericSerializableSettings settings, Iterable defaultValues, boolean emptyIsDefault) { + super(name, settings, defaultValues, emptyIsDefault, UUIDConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetting.java new file mode 100644 index 00000000000..1871d841d5d --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/UUIDSetting.java @@ -0,0 +1,17 @@ +package com.sap.sse.common.settings.generic; + +import java.util.UUID; + +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.generic.converter.UUIDConverter; + +public class UUIDSetting extends AbstractValueSetting { + + public UUIDSetting(String name, AbstractGenericSerializableSettings settings) { + this(name, settings, null); + } + + public UUIDSetting(String name, AbstractGenericSerializableSettings settings, UUID defaultValue) { + super(name, settings, defaultValue, UUIDConverter.INSTANCE); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueCollectionSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueCollectionSetting.java similarity index 68% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueCollectionSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueCollectionSetting.java index ab192d42e2e..b71750cdbb4 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueCollectionSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueCollectionSetting.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; public interface ValueCollectionSetting extends HasValueSetting, CollectionSetting { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueConverter.java similarity index 87% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueConverter.java index 1594af9a66b..d9a3de5f24a 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueConverter.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; import com.sap.sse.common.settings.value.Value; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueSetSetting.java similarity index 74% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueSetSetting.java index fe81decbcd7..a7d715e1ca7 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueSetSetting.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; public interface ValueSetSetting extends ValueCollectionSetting { void setDefaultValues(Iterable defaultValues); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueSetting.java similarity index 71% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueSetting.java index 75385c4472b..16644bf880f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/ValueSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/ValueSetting.java @@ -1,4 +1,4 @@ -package com.sap.sse.common.settings; +package com.sap.sse.common.settings.generic; public interface ValueSetting extends HasValueSetting { T getValue(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractHasValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractHasValueSetting.java new file mode 100644 index 00000000000..1c8f26e8e20 --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractHasValueSetting.java @@ -0,0 +1,21 @@ +package com.sap.sse.common.settings.generic.base; + +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.AbstractSetting; +import com.sap.sse.common.settings.generic.HasValueSetting; +import com.sap.sse.common.settings.generic.ValueConverter; + +public abstract class AbstractHasValueSetting extends AbstractSetting implements HasValueSetting { + + private ValueConverter valueConverter; + + public AbstractHasValueSetting(String name, AbstractGenericSerializableSettings settings, ValueConverter valueConverter) { + super(name, settings); + this.valueConverter = valueConverter; + } + + @Override + public ValueConverter getValueConverter() { + return valueConverter; + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueCollectionSetting.java similarity index 86% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueCollectionSetting.java index 9c997fb5858..146364a5b6f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueCollectionSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueCollectionSetting.java @@ -1,17 +1,17 @@ -package com.sap.sse.common.settings.base; +package com.sap.sse.common.settings.generic.base; import java.util.Collection; import java.util.Collections; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.ValueCollectionSetting; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.ValueCollectionSetting; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.Value; import com.sap.sse.common.settings.value.ValueCollectionValue; public abstract class AbstractValueCollectionSetting> extends AbstractHasValueSetting implements ValueCollectionSetting { - public AbstractValueCollectionSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + public AbstractValueCollectionSetting(String name, AbstractGenericSerializableSettings settings, ValueConverter valueConverter) { super(name, settings, valueConverter); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueListSetting.java similarity index 72% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueListSetting.java index ccb5831608a..966337840d9 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueListSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueListSetting.java @@ -1,15 +1,15 @@ -package com.sap.sse.common.settings.base; +package com.sap.sse.common.settings.generic.base; import java.util.List; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.Value; import com.sap.sse.common.settings.value.ValueCollectionValue; import com.sap.sse.common.settings.value.ValueListValue; public abstract class AbstractValueListSetting extends AbstractValueCollectionSetting> { - public AbstractValueListSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + public AbstractValueListSetting(String name, AbstractGenericSerializableSettings settings, ValueConverter valueConverter) { super(name, settings, valueConverter); } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueSetSetting.java similarity index 70% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueSetSetting.java index f0ab3961a11..455ceaf3829 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueSetSetting.java @@ -1,13 +1,13 @@ -package com.sap.sse.common.settings.base; +package com.sap.sse.common.settings.generic.base; import java.util.Collections; import java.util.HashSet; import java.util.Set; import com.sap.sse.common.Util; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.ValueConverter; -import com.sap.sse.common.settings.ValueSetSetting; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.ValueConverter; +import com.sap.sse.common.settings.generic.ValueSetSetting; import com.sap.sse.common.settings.value.Value; import com.sap.sse.common.settings.value.ValueCollectionValue; import com.sap.sse.common.settings.value.ValueSetValue; @@ -17,20 +17,20 @@ public abstract class AbstractValueSetSetting extends AbstractValueCollection private final Set defaultValues = new HashSet<>(); private final boolean emptyIsDefault; - public AbstractValueSetSetting(String name, AbstractSettings settings, ValueConverter valueConverter) { + public AbstractValueSetSetting(String name, AbstractGenericSerializableSettings settings, ValueConverter valueConverter) { this(name, settings, false, valueConverter); } - public AbstractValueSetSetting(String name, AbstractSettings settings, boolean emptyIsDefault, ValueConverter valueConverter) { + public AbstractValueSetSetting(String name, AbstractGenericSerializableSettings settings, boolean emptyIsDefault, ValueConverter valueConverter) { super(name, settings, valueConverter); this.emptyIsDefault = emptyIsDefault; } - public AbstractValueSetSetting(String name, AbstractSettings settings, Iterable defaultValues, ValueConverter valueConverter) { + public AbstractValueSetSetting(String name, AbstractGenericSerializableSettings settings, Iterable defaultValues, ValueConverter valueConverter) { this(name, settings, defaultValues, false, valueConverter); } - public AbstractValueSetSetting(String name, AbstractSettings settings, Iterable defaultValues, boolean emptyIsDefault, ValueConverter valueConverter) { + public AbstractValueSetSetting(String name, AbstractGenericSerializableSettings settings, Iterable defaultValues, boolean emptyIsDefault, ValueConverter valueConverter) { this(name, settings, emptyIsDefault, valueConverter); setDefaultValues(defaultValues); resetToDefault(); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueSetting.java similarity index 84% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueSetting.java index 9675d9200c0..2c66e88e741 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/base/AbstractValueSetting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/base/AbstractValueSetting.java @@ -1,15 +1,15 @@ -package com.sap.sse.common.settings.base; +package com.sap.sse.common.settings.generic.base; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.ValueConverter; -import com.sap.sse.common.settings.ValueSetting; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.ValueConverter; +import com.sap.sse.common.settings.generic.ValueSetting; import com.sap.sse.common.settings.value.Value; public abstract class AbstractValueSetting extends AbstractHasValueSetting implements ValueSetting { private T defaultValue; - protected AbstractValueSetting(String name, AbstractSettings settings, T defaultValue, ValueConverter valueConverter) { + protected AbstractValueSetting(String name, AbstractGenericSerializableSettings settings, T defaultValue, ValueConverter valueConverter) { super(name, settings, valueConverter); this.defaultValue = defaultValue; if(settings.getValue(settingName) == null) { diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/BooleanConverter.java similarity index 89% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/BooleanConverter.java index 8fc805cb62c..e7ac0e80900 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/BooleanConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/BooleanConverter.java @@ -1,6 +1,6 @@ -package com.sap.sse.common.settings.converter; +package com.sap.sse.common.settings.generic.converter; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.BooleanValue; import com.sap.sse.common.settings.value.Value; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/DecimalConverter.java similarity index 90% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/DecimalConverter.java index 81c702ea5c8..153005314c0 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DecimalConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/DecimalConverter.java @@ -1,8 +1,8 @@ -package com.sap.sse.common.settings.converter; +package com.sap.sse.common.settings.generic.converter; import java.math.BigDecimal; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.DecimalValue; import com.sap.sse.common.settings.value.Value; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/DoubleConverter.java similarity index 89% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/DoubleConverter.java index 8f07748095a..4eca20624a8 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/DoubleConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/DoubleConverter.java @@ -1,6 +1,6 @@ -package com.sap.sse.common.settings.converter; +package com.sap.sse.common.settings.generic.converter; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.DoubleValue; import com.sap.sse.common.settings.value.Value; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/EnumConverter.java similarity index 86% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/EnumConverter.java index 64c55bf8d53..9d66738c2e3 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/EnumConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/EnumConverter.java @@ -1,7 +1,7 @@ -package com.sap.sse.common.settings.converter; +package com.sap.sse.common.settings.generic.converter; -import com.sap.sse.common.settings.StringToEnumConverter; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.StringToEnumConverter; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.StringValue; import com.sap.sse.common.settings.value.Value; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/StringConverter.java similarity index 88% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/StringConverter.java index d7397ad993e..fc72bea4dbc 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/StringConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/StringConverter.java @@ -1,6 +1,6 @@ -package com.sap.sse.common.settings.converter; +package com.sap.sse.common.settings.generic.converter; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.StringValue; import com.sap.sse.common.settings.value.Value; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/UUIDConverter.java similarity index 89% rename from java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java rename to java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/UUIDConverter.java index e621c956d98..e1e18c3b63c 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/converter/UUIDConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/converter/UUIDConverter.java @@ -1,8 +1,8 @@ -package com.sap.sse.common.settings.converter; +package com.sap.sse.common.settings.generic.converter; import java.util.UUID; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.ValueConverter; import com.sap.sse.common.settings.value.UUIDValue; import com.sap.sse.common.settings.value.Value; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java index ed839c9e69f..516ba58d90f 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/AbstractSettingsToJsonSerializer.java @@ -4,13 +4,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import com.sap.sse.common.settings.CollectionSetting; -import com.sap.sse.common.settings.Setting; import com.sap.sse.common.settings.Settings; -import com.sap.sse.common.settings.SettingsListSetting; -import com.sap.sse.common.settings.ValueCollectionSetting; -import com.sap.sse.common.settings.ValueConverter; -import com.sap.sse.common.settings.ValueSetting; +import com.sap.sse.common.settings.generic.CollectionSetting; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; +import com.sap.sse.common.settings.generic.Setting; +import com.sap.sse.common.settings.generic.SettingsListSetting; +import com.sap.sse.common.settings.generic.ValueCollectionSetting; +import com.sap.sse.common.settings.generic.ValueConverter; +import com.sap.sse.common.settings.generic.ValueSetting; /** * Base class for {@link Settings} serializers that produce JSON objects using some generic object model. This base @@ -36,7 +37,7 @@ public abstract class AbstractSettingsToJsonSerializer { protected abstract Iterable fromJsonArray(ARRAY jsonArray); - public OBJECT serialize(Settings settings) { + public OBJECT serialize(GenericSerializableSettings settings) { final OBJECT jsonObject = newOBJECT(); for (Map.Entry entry : settings.getChildSettings().entrySet()) { Setting setting = entry.getValue(); @@ -52,8 +53,8 @@ public abstract class AbstractSettingsToJsonSerializer { return serializeValueSetting((ValueSetting) setting); } else if (setting instanceof CollectionSetting) { return serializeListSetting((CollectionSetting) setting); - } else if (setting instanceof Settings) { - return serialize((Settings) setting); + } else if (setting instanceof GenericSerializableSettings) { + return serialize((GenericSerializableSettings) setting); } else { throw new IllegalStateException("Unknown Setting type"); } @@ -73,7 +74,7 @@ public abstract class AbstractSettingsToJsonSerializer { } } else if (listSetting instanceof SettingsListSetting) { SettingsListSetting settingsListSetting = (SettingsListSetting) listSetting; - for (Settings value : settingsListSetting.getValues()) { + for (GenericSerializableSettings value : settingsListSetting.getValues()) { jsonValues.add(serialize(value)); } } else { @@ -82,7 +83,7 @@ public abstract class AbstractSettingsToJsonSerializer { return ToJsonArray(jsonValues); } - public T deserialize(T settings, OBJECT json) { + public T deserialize(T settings, OBJECT json) { if (json != null) { for (Map.Entry entry : settings.getChildSettings().entrySet()) { Setting setting = entry.getValue(); @@ -100,15 +101,15 @@ public abstract class AbstractSettingsToJsonSerializer { deserializeValueSetting(jsonValue, (ValueSetting) setting); } else if (setting instanceof CollectionSetting) { deserializeListSetting(jsonValue, (CollectionSetting) setting); - } else if (setting instanceof Settings) { - deserializeObject((Settings) setting, jsonValue); + } else if (setting instanceof GenericSerializableSettings) { + deserializeObject((GenericSerializableSettings) setting, jsonValue); } else { throw new IllegalStateException("Unknown Setting type"); } } @SuppressWarnings("unchecked") - private T deserializeObject(T setting, Object jsonValue) { + private T deserializeObject(T setting, Object jsonValue) { return deserialize(setting, (OBJECT) jsonValue); } @@ -134,7 +135,7 @@ public abstract class AbstractSettingsToJsonSerializer { } } - private void deserializeSettingsListSetting(ARRAY jsonArray, SettingsListSetting settingsListSetting) { + private void deserializeSettingsListSetting(ARRAY jsonArray, SettingsListSetting settingsListSetting) { List values = new ArrayList<>(); for (Object value : fromJsonArray(jsonArray)) { values.add(deserializeObject(settingsListSetting.getSettingsFactory().newInstance(), value)); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java index 86a1a2f8b3b..e95032e1853 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/serializer/SettingsToStringMapSerializer.java @@ -9,29 +9,29 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; -import com.sap.sse.common.settings.HasValueSetting; -import com.sap.sse.common.settings.Setting; -import com.sap.sse.common.settings.Settings; -import com.sap.sse.common.settings.SettingsListSetting; -import com.sap.sse.common.settings.ValueConverter; -import com.sap.sse.common.settings.ValueCollectionSetting; -import com.sap.sse.common.settings.ValueSetting; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; +import com.sap.sse.common.settings.generic.HasValueSetting; +import com.sap.sse.common.settings.generic.Setting; +import com.sap.sse.common.settings.generic.SettingsListSetting; +import com.sap.sse.common.settings.generic.ValueCollectionSetting; +import com.sap.sse.common.settings.generic.ValueConverter; +import com.sap.sse.common.settings.generic.ValueSetting; /** - * {@link Settings} serializer that constructs flattened String keys with associated String values from the hierarchical - * {@link Settings} structures. This is necessary for cases where hierarchical structures aren't mappable (e.g. URL + * {@link GenericSerializableSettings} serializer that constructs flattened String keys with associated String values from the hierarchical + * {@link GenericSerializableSettings} structures. This is necessary for cases where hierarchical structures aren't mappable (e.g. URL * serialization). * */ public class SettingsToStringMapSerializer { - public Map> serialize(Settings settings) { + public Map> serialize(GenericSerializableSettings settings) { final Map> result = new HashMap<>(); serialize("", settings, result); return result; } - private void serialize(String prefix, Settings settings, Map> serialized) { + private void serialize(String prefix, GenericSerializableSettings settings, Map> serialized) { for (Map.Entry entry : settings.getChildSettings().entrySet()) { final Setting setting = entry.getValue(); if (!setting.isDefaultValue()) { @@ -47,9 +47,9 @@ public class SettingsToStringMapSerializer { } else if (setting instanceof ValueCollectionSetting) { serialized.put(key, serializeValueListSetting(key, (ValueCollectionSetting) setting)); } else { - String prefix = key + Settings.PATH_SEPARATOR; - if (setting instanceof Settings) { - serialize(prefix, (Settings) setting, serialized); + String prefix = key + GenericSerializableSettings.PATH_SEPARATOR; + if (setting instanceof GenericSerializableSettings) { + serialize(prefix, (GenericSerializableSettings) setting, serialized); } else if (setting instanceof SettingsListSetting) { serializeSettingsListSetting(prefix, (SettingsListSetting) setting, serialized); } else { @@ -58,11 +58,11 @@ public class SettingsToStringMapSerializer { } } - private void serializeSettingsListSetting(String prefix, SettingsListSetting setting, + private void serializeSettingsListSetting(String prefix, SettingsListSetting setting, Map> serialized) { int index = 0; for (T childSettings : setting.getValues()) { - String nestedPrefix = prefix + index + Settings.PATH_SEPARATOR; + String nestedPrefix = prefix + index + GenericSerializableSettings.PATH_SEPARATOR; serialize(nestedPrefix, childSettings, serialized); index++; } @@ -81,7 +81,7 @@ public class SettingsToStringMapSerializer { return result; } - public T deserialize(T settings, Map> values) { + public T deserialize(T settings, Map> values) { Map>> mappedInnerValues = mapNested(values); for (Map.Entry entry : settings.getChildSettings().entrySet()) { final String key = entry.getKey(); @@ -107,8 +107,8 @@ public class SettingsToStringMapSerializer { } else { final Map> innerValues = mappedInnerValues.get(key); if (innerValues != null) { - if (setting instanceof Settings) { - deserialize((Settings) setting, innerValues); + if (setting instanceof GenericSerializableSettings) { + deserialize((GenericSerializableSettings) setting, innerValues); } else if (setting instanceof SettingsListSetting) { deserializeSettingsListSetting((SettingsListSetting) setting, innerValues); } else { @@ -136,7 +136,7 @@ public class SettingsToStringMapSerializer { valueSetting.setValues(deserializedValues); } - private void deserializeSettingsListSetting(SettingsListSetting valueSetting, + private void deserializeSettingsListSetting(SettingsListSetting valueSetting, Map> values) { Map>> mappedNestedListValues = mapNestedWithIndexOrder(values); List deserializedValues = new ArrayList<>(); @@ -156,7 +156,7 @@ public class SettingsToStringMapSerializer { Map>> result = new HashMap<>(); for (Map.Entry> entry : values.entrySet()) { String key = entry.getKey(); - int separatorIndex = key.indexOf(Settings.PATH_SEPARATOR); + int separatorIndex = key.indexOf(GenericSerializableSettings.PATH_SEPARATOR); if (separatorIndex > 0) { String group = key.substring(0, separatorIndex); String nestedKey = key.substring(separatorIndex + 1); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java index e321ae5f926..1bc8da872b5 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollection.java @@ -1,6 +1,6 @@ package com.sap.sse.common.settings.value; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.ValueConverter; public interface ValueCollection extends Value { Iterable getValues(ValueConverter converter); diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java index 8c6452fe7a9..80c49aad086 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/value/ValueCollectionValue.java @@ -3,7 +3,7 @@ package com.sap.sse.common.settings.value; import java.util.Collection; import java.util.Collections; -import com.sap.sse.common.settings.ValueConverter; +import com.sap.sse.common.settings.generic.ValueConverter; public abstract class ValueCollectionValue> implements ValueCollection { private static final long serialVersionUID = -5820765644801217519L; diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java index a4db16a9061..878460e4021 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/AbstractEntryPointWithSettingsLinkFactory.java @@ -1,15 +1,15 @@ package com.sap.sse.gwt.settings; import com.google.gwt.http.client.UrlBuilder; -import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; public abstract class AbstractEntryPointWithSettingsLinkFactory { private static final SettingsToUrlSerializer serializer = new SettingsToUrlSerializer(); - protected static String createEntryPointLink(String baseLink, Settings... settings) { + protected static String createEntryPointLink(String baseLink, GenericSerializableSettings... settings) { UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters(baseLink); - for (Settings setting : settings) { + for (GenericSerializableSettings setting : settings) { serializer.serializeToUrlBuilder(setting, urlBuilder); } return urlBuilder.buildString(); diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java index 5c4d2905aaf..b15e96b9cf6 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java @@ -10,7 +10,7 @@ import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.json.client.JSONString; import com.google.gwt.json.client.JSONValue; -import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; /** @@ -20,11 +20,11 @@ import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; */ public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerializer { - public String serializeToString(Settings settings) { + public String serializeToString(GenericSerializableSettings settings) { return serialize(settings).toString(); } - public T deserialize(T settings, String jsonString) { + public T deserialize(T settings, String jsonString) { if (jsonString != null && !jsonString.isEmpty()) { JSONValue jsonValue = JSONParser.parseStrict(jsonString); if (jsonValue != null) { diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java index 839d3b8b67b..dd2edb81cf5 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToUrlSerializer.java @@ -5,13 +5,13 @@ import java.util.Map; import com.google.gwt.http.client.UrlBuilder; import com.google.gwt.user.client.Window; import com.sap.sse.common.Util; -import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; import com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer; /** - * Serializes {@link Settings} objects to the URL by constructing flat keys from the hierarchical object graph. + * Serializes {@link GenericSerializableSettings} objects to the URL by constructing flat keys from the hierarchical object graph. * - * This type of serialzation has some limitations: + * This type of serialization has some limitations: *
        *
      • Empty collections can not be serialized. This can only occur for collection settings that have their default value set to be non-empty and there is no actual value.
      • *
      • Null values can not be distinguished from empty strings
      • @@ -22,31 +22,31 @@ public class SettingsToUrlSerializer { private final SettingsToStringMapSerializer settingsToStringMapSerializer = new SettingsToStringMapSerializer(); - public String serializeBasedOnCurrentLocation(Settings settings) { + public String serializeBasedOnCurrentLocation(GenericSerializableSettings settings) { final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); serializeToUrlBuilder(settings, urlBuilder); return urlBuilder.buildString(); } - public String serializeBasedOnCurrentLocationWithCleanParameters(Settings settings) { + public String serializeBasedOnCurrentLocationWithCleanParameters(GenericSerializableSettings settings) { final UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters(); serializeToUrlBuilder(settings, urlBuilder); return urlBuilder.buildString(); } - public UrlBuilder serializeUrlBuilderBasedOnCurrentLocation(Settings settings) { + public UrlBuilder serializeUrlBuilderBasedOnCurrentLocation(GenericSerializableSettings settings) { final UrlBuilder urlBuilder = Window.Location.createUrlBuilder(); serializeToUrlBuilder(settings, urlBuilder); return urlBuilder; } - public UrlBuilder serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(Settings settings) { + public UrlBuilder serializeUrlBuilderBasedOnCurrentLocationWithCleanParameters(GenericSerializableSettings settings) { final UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters(); serializeToUrlBuilder(settings, urlBuilder); return urlBuilder; } - public void serializeToUrlBuilder(Settings settings, UrlBuilder urlBuilder) { + public void serializeToUrlBuilder(GenericSerializableSettings settings, UrlBuilder urlBuilder) { Map> serializedValues = settingsToStringMapSerializer.serialize(settings); for(Map.Entry> entry : serializedValues.entrySet()) { Iterable parameterValues = entry.getValue(); @@ -57,7 +57,7 @@ public class SettingsToUrlSerializer { } } - public T deserializeFromCurrentLocation(T settings) { + public T deserializeFromCurrentLocation(T settings) { @SuppressWarnings({ "rawtypes", "unchecked" }) Map> values = (Map) Window.Location.getParameterMap(); return settingsToStringMapSerializer.deserialize(settings, values); diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java index 48b73fc1d21..40b8d468a9d 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/AbstractSettingsSerializationTest.java @@ -9,21 +9,20 @@ import org.junit.Test; import com.sap.sse.common.filter.TextOperator; import com.sap.sse.common.filter.TextOperator.Operators; -import com.sap.sse.common.settings.AbstractSettings; -import com.sap.sse.common.settings.BooleanSetting; -import com.sap.sse.common.settings.DecimalListSetting; -import com.sap.sse.common.settings.DecimalSetting; -import com.sap.sse.common.settings.EnumListSetting; -import com.sap.sse.common.settings.EnumSetting; -import com.sap.sse.common.settings.SerializableSettings; -import com.sap.sse.common.settings.Settings; -import com.sap.sse.common.settings.SettingsList; -import com.sap.sse.common.settings.StringSetting; -import com.sap.sse.common.settings.StringToEnumConverter; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.BooleanSetting; +import com.sap.sse.common.settings.generic.DecimalListSetting; +import com.sap.sse.common.settings.generic.DecimalSetting; +import com.sap.sse.common.settings.generic.EnumListSetting; +import com.sap.sse.common.settings.generic.EnumSetting; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; +import com.sap.sse.common.settings.generic.SettingsList; +import com.sap.sse.common.settings.generic.StringSetting; +import com.sap.sse.common.settings.generic.StringToEnumConverter; public abstract class AbstractSettingsSerializationTest { - private static class TestOuterSettings extends SerializableSettings { + private static class TestOuterSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -7379232503773525915L; private transient SimpleTestSettings nested; @@ -36,7 +35,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestListSettings extends SerializableSettings { + private static class TestListSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = 6919127895749914961L; private transient SettingsList l; @@ -49,7 +48,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class SimpleTestSettings extends SerializableSettings { + private static class SimpleTestSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -4134836978411240572L; private transient StringSetting string; private transient DecimalSetting num; @@ -62,7 +61,7 @@ public abstract class AbstractSettingsSerializationTest { this.num.setValue(num); } - public SimpleTestSettings(String name, AbstractSettings parent) { + public SimpleTestSettings(String name, AbstractGenericSerializableSettings parent) { super(name, parent); } @@ -73,7 +72,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestSettings extends SerializableSettings { + private static class TestSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -611806711715538293L; private transient StringSetting humba; private transient BooleanSetting bumpa; @@ -94,7 +93,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class TestEnumListSettings extends SerializableSettings { + private static class TestEnumListSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = 93688955681544920L; private transient EnumListSetting l; @@ -113,7 +112,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class DuplicateFieldSettings extends SerializableSettings { + private static class DuplicateFieldSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = 4058775568295038177L; @SuppressWarnings("unused") private transient StringSetting humba; @@ -127,7 +126,7 @@ public abstract class AbstractSettingsSerializationTest { } } - private static class DisallowedKeySettings extends SerializableSettings { + private static class DisallowedKeySettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -2265305217290147424L; @SuppressWarnings("unused") private transient StringSetting disallowedKey; @@ -138,20 +137,20 @@ public abstract class AbstractSettingsSerializationTest { } } - protected abstract SOT serialize(T settings) throws Exception; + protected abstract SOT serialize(T settings) throws Exception; - protected T deserialize(SOT serializedObject, Class settingsClass) throws Exception { + protected T deserialize(SOT serializedObject, Class settingsClass) throws Exception { T deserializedInstance = settingsClass.newInstance(); return deserialize(serializedObject, deserializedInstance); } - protected T deserialize(SOT serializedObject, T settings) throws Exception { + protected T deserialize(SOT serializedObject, T settings) throws Exception { return null; }; @SuppressWarnings("unchecked") - private T serializeAndDeserialize(T objectToSerialize) { + private T serializeAndDeserialize(T objectToSerialize) { try { SOT serialized = serialize(objectToSerialize); return deserialize(serialized, (Class) objectToSerialize.getClass()); diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java index 3dc5d73347b..598c1469ac8 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsJavaSerializationTest.java @@ -5,12 +5,12 @@ import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; public class SettingsJavaSerializationTest extends AbstractSettingsSerializationTest { @Override - protected byte[] serialize(T settings) throws Exception { + protected byte[] serialize(T settings) throws Exception { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos);) { oos.writeObject(settings); @@ -22,7 +22,7 @@ public class SettingsJavaSerializationTest extends AbstractSettingsSerialization @SuppressWarnings("unchecked") @Override - protected T deserialize(byte[] serializedObject, Class settingsClass) throws Exception { + protected T deserialize(byte[] serializedObject, Class settingsClass) throws Exception { try (ByteArrayInputStream bais = new ByteArrayInputStream(serializedObject); ObjectInputStream ois = new ObjectInputStream(bais);) { return (T) ois.readObject(); diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java index b2c9d84dc83..15ed2f44d7a 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java @@ -3,7 +3,7 @@ package com.sap.sse.shared.android.test; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; -import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; import com.sap.sse.shared.settings.SettingsToJsonSerializer; public class SettingsToJsonSerializationTest extends AbstractSettingsSerializationTest { @@ -11,14 +11,14 @@ public class SettingsToJsonSerializationTest extends AbstractSettingsSerializati private final SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); @Override - protected String serialize(T settings) throws Exception { + protected String serialize(T settings) throws Exception { // Do not change this to return a JSONOBject instance. // JSONOBject is just a HashMap and you only know if it is really JSON serializable if you do it! return serializer.serialize(settings).toJSONString(); } @Override - protected T deserialize(String serializedObject, T settings) throws Exception { + protected T deserialize(String serializedObject, T settings) throws Exception { return serializer.deserialize(settings, (JSONObject) new JSONParser().parse(serializedObject)); } } diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java index 46a2fa66fe5..877fe13fa75 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToStringMapSerializationTest.java @@ -2,7 +2,7 @@ package com.sap.sse.shared.android.test; import java.util.Map; -import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; import com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer; public class SettingsToStringMapSerializationTest extends AbstractSettingsSerializationTest>> { @@ -10,12 +10,12 @@ public class SettingsToStringMapSerializationTest extends AbstractSettingsSerial private final SettingsToStringMapSerializer serializer = new SettingsToStringMapSerializer(); @Override - protected Map> serialize(T settings) throws Exception { + protected Map> serialize(T settings) throws Exception { return serializer.serialize(settings); } @Override - protected T deserialize(Map> serializedObject, T settings) throws Exception { + protected T deserialize(Map> serializedObject, T settings) throws Exception { return serializer.deserialize(settings, serializedObject); } } diff --git a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF index 289d7b06dcd..2f82b40baf2 100644 --- a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF @@ -12,6 +12,7 @@ Export-Package: com.sap.sse.concurrent, com.sap.sse.shared.media.impl, com.sap.sse.util.impl Import-Package: com.sap.sse.common.settings, - com.sap.sse.common.settings.base, - com.sap.sse.common.settings.converter, + com.sap.sse.common.settings.generic, + com.sap.sse.common.settings.generic.base, + com.sap.sse.common.settings.generic.converter, com.sap.sse.common.settings.serializer From 965f8a01fdc97693093ae541e8a545451147e476 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 30 Jun 2016 14:32:12 +0200 Subject: [PATCH 081/259] Updated the RegattaOverview Settings to the current development state --- .../regattaoverview/RegattaOverviewBaseSettings.java | 4 ++-- .../client/regattaoverview/RegattaRaceStatesSettings.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java index 412d4d57bc3..ab4c985b218 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaOverviewBaseSettings.java @@ -8,8 +8,8 @@ import com.sap.sse.common.settings.generic.UUIDSetting; public final class RegattaOverviewBaseSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -8541790130000694098L; - private UUIDSetting event; - private BooleanSetting ignoreLocalSettings; + private transient UUIDSetting event; + private transient BooleanSetting ignoreLocalSettings; public RegattaOverviewBaseSettings() { } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java index e32720c857d..2a46f55cb01 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/settings/client/regattaoverview/RegattaRaceStatesSettings.java @@ -14,10 +14,10 @@ import com.sap.sse.common.settings.generic.UUIDSetSetting; public final class RegattaRaceStatesSettings extends AbstractGenericSerializableSettings { private static final long serialVersionUID = 7059340304556830062L; - private UUIDSetSetting visibleCourseAreas; - private StringSetSetting visibleRegattas; - private BooleanSetting showOnlyRacesOfSameDay; - private BooleanSetting showOnlyCurrentlyRunningRaces; + private transient UUIDSetSetting visibleCourseAreas; + private transient StringSetSetting visibleRegattas; + private transient BooleanSetting showOnlyRacesOfSameDay; + private transient BooleanSetting showOnlyCurrentlyRunningRaces; public RegattaRaceStatesSettings() { } From 98410df36a2b3afbdb4f64660dd4bcd1af9287ca Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 30 Jun 2016 15:03:40 +0200 Subject: [PATCH 082/259] Added additional export package concerning settings --- java/com.sap.sse.common/META-INF/MANIFEST.MF | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.common/META-INF/MANIFEST.MF b/java/com.sap.sse.common/META-INF/MANIFEST.MF index 397e8dde2ee..290b7f09b55 100644 --- a/java/com.sap.sse.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.common/META-INF/MANIFEST.MF @@ -17,6 +17,7 @@ Export-Package: com.sap.sse.common, com.sap.sse.common.settings.generic.base, com.sap.sse.common.settings.generic.converter, com.sap.sse.common.settings.serializer, + com.sap.sse.common.settings.value, com.sap.sse.common.util Require-Bundle: com.sap.sse.datamining.annotations Bundle-ActivationPolicy: lazy From 716969dee696c977d84866690bdf8ec485e9e0bc Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 30 Jun 2016 16:25:31 +0200 Subject: [PATCH 083/259] Added convenience methods for preferences to client-side UserService --- .../sse/security/ui/client/UserService.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserService.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserService.java index a02996c83bc..cd660b0a46e 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserService.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserService.java @@ -8,10 +8,13 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.Random; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; import com.sap.sse.gwt.client.Storage; import com.sap.sse.gwt.client.StorageEvent; import com.sap.sse.gwt.client.StorageEvent.Handler; import com.sap.sse.gwt.client.async.MarkedAsyncCallback; +import com.sap.sse.gwt.settings.SettingsToJsonSerializerGWT; import com.sap.sse.security.ui.client.i18n.StringMessages; import com.sap.sse.security.ui.oauth.client.util.ClientUtils; import com.sap.sse.security.ui.shared.SuccessInfo; @@ -44,6 +47,8 @@ public class UserService { * and windows about changes in the currently logged-in user. */ private static final String LOCAL_STORAGE_UPDATE_KEY = "current-user-has-changed"; + + private final SettingsToJsonSerializerGWT serializer = new SettingsToJsonSerializerGWT(); private final UserManagementServiceAsync userManagementService; @@ -205,5 +210,87 @@ public class UserService { public UserManagementServiceAsync getUserManagementService() { return userManagementService; } + + /** + * Loads the {@link #getCurrentUser() current user}'s preference with the given {@link String key} from server. + * Because the preference is persisted as JSON on server, the loaded data will be deserialized into the provided + * {@link GenericSerializableSettings} instance. + * + * @param key + * key of the preference to load + * @param emptyInstance + * an empty {@link GenericSerializableSettings} instance, where the loaded data is deserialized to + * @param callback + * {@link AsyncCallback} for GWT RPC call + * + * @see GenericSerializableSettings + * @see AbstractGenericSerializableSettings + */ + public void getPreference(String key, final T emptyInstance, + final AsyncCallback callback) { + String username = getCurrentUser().getName(); // TODO: Can username be determined via session on server-side + getUserManagementService().getPreference(username, key, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + callback.onFailure(caught); + } + + @Override + public void onSuccess(String result) { + callback.onSuccess(serializer.deserialize(emptyInstance, result)); + } + }); + } + /** + * Sets the {@link #getCurrentUser() current user}'s preference with the given {@link String key} on server. + * Because preferences are persisted as JSON, the provided {@link GenericSerializableSettings} instance + * will be serialized before it is sent to the server. + * + * @param key + * key of the preference to set + * @param instance + * {@link GenericSerializableSettings} instance containing the preference value + * + * @see GenericSerializableSettings + * @see AbstractGenericSerializableSettings + */ + public void setPreference(String key, GenericSerializableSettings instance) { + String username = getCurrentUser().getName(); // TODO: Can username be determined via session on server-side + String json = serializer.serializeToString(instance); + getUserManagementService().setPreference(username, key, json, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + // TODO What to do in case of failure? + } + + @Override + public void onSuccess(Void result) { + // TODO Do anything in case of success? + } + }); + } + + /** + * Unsets the {@link #getCurrentUser() current user}'s preference with the given key on server. + * + * @param key key of the preference to unset + * + * @see GenericSerializableSettings + * @see AbstractGenericSerializableSettings + */ + public void unsetPreference(String key) { + String username = getCurrentUser().getName(); // TODO: Can username be determined via session on server-side + getUserManagementService().unsetPreference(username, key, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + // TODO What to do in case of failure? + } + + @Override + public void onSuccess(Void result) { + // TODO Do anything in case of success? + } + }); + } } From 0d7c19a9843e5ac03c0a2caf84efedf1f061d9df Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 30 Jun 2016 16:26:59 +0200 Subject: [PATCH 084/259] Added JavaDocs to Settings related classes --- .../sse/common/settings/AbstractSettings.java | 62 +++---------------- .../common/settings/SerializableSettings.java | 3 + .../com/sap/sse/common/settings/Settings.java | 29 --------- .../AbstractGenericSerializableSettings.java | 2 +- .../generic/GenericSerializableSettings.java | 29 ++++++++- .../sse/common/settings/generic/Setting.java | 6 +- 6 files changed, 41 insertions(+), 90 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java index 8b732d0b7f3..6a664a19e0d 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/AbstractSettings.java @@ -1,63 +1,15 @@ package com.sap.sse.common.settings; -import com.sap.sse.common.settings.generic.Setting; - /** - * Common superclass for custom Settings used by Components. The following example shows how to implement custom - * Settings: - * - *
        - * 
        - * public final class ExampleSettings extends AbstractSettings {
        - *     private transient StringSetting myString;
        - *     private transient BooleanSetting myBoolean;
        - *     
        - *     // Used to create instances for a component
        - *     public ExampleSettings() {
        - *     }
        - *     
        - *     // Used to create nested settings
        - *     public ExampleSettings(String name, AbstractSettings parentSettings) {
        - *         super(name, parentSettings);
        - *     }
        - *     
        - *     @Override
        - *     protected void addChildSettings() {
        - *         myString = new UUIDSetting("myString", this)
        - *         myBoolean = new BooleanSetting("myBoolean", this);
        - *     }
        - *     
        - *     public String getMyString() {
        - *         return this.myString.getValue();
        - *     }
        - *     
        - *     public void setMyString(String myString) {
        - *         return this.myString.setValue(myString);
        - *     }
        - *     
        - *     public boolean isMyBoolean() {
        - *         return this.myBoolean.getValue();
        - *     }
        - *     
        - *     public void setMyBoolean(boolean myBoolean) {
        - *         return this.myBoolean.setValue(myBoolean);
        - *     }
        - * }
        - * 
        - * 
        - * - * To correctly support several kinds of Serialization (Java, GWT and Custom), you need to ensure the following: + * Common superclass for custom Settings used by Components. This kind of Settings is not serializable at all. There are + * more specific super classes for different serialization needs: *
          - *
        • the Settings class must have a default constructor
        • - *
        • child settings fields need to be transient
        • - *
        • child settings instances must be initialized in {@link #addChildSettings()} method
        • + *
        • {@link SerializableSettings} can be used for {@link Settings} that need to be Java-serializable and/or + * GWT-RPC-compatible
        • + *
        • {@link com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings} support a wide variety of serialization mechanisms by using a generic + * mechanism to declare the settings that requires that implementers comply to some specific rules
        • *
        - * - * If a custom Settings class only has {@link Setting} oder {@link Settings} children that are correctly attached by - * calling their constructor with a name and the parent {@link Settings} you do not need to implement - * {@link #hashCode()}, {@link #equals(Object)} and {@link #toString()}. There are generic implementations of those methods that are - * based on the child {@link Setting}s which should be sufficient for most cases. * */ -public abstract class AbstractSettings implements Settings { +public abstract class AbstractSettings implements Settings { } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java index a2de8e9aeb1..d46dd54608a 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/SerializableSettings.java @@ -2,6 +2,9 @@ package com.sap.sse.common.settings; import java.io.Serializable; +/** + * Super class for {@link Settings} that need to be Java-serializable or compatible with GWT-RPC. + */ public abstract class SerializableSettings extends AbstractSettings implements Serializable { private static final long serialVersionUID = -2710627501473421333L; } diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java index 053de9ab236..b73e306c612 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/Settings.java @@ -1,40 +1,11 @@ package com.sap.sse.common.settings; -import com.sap.sse.common.settings.generic.Setting; - /** * A generic format to keep the settings for a Component. Such settings may be initialized with defaults. * Usually they can be edited by a user using a SettingsDialogComponent displayed by a * SettingsDialog. The interface is homed in this server-side, shared bundle because settings may as well * be handled on the server side, e.g., in order to store them in the user store or to apply them to a server-side * component. - *

        - * - * Settings need to be serialized and de-serialized to/from different formats. In a URL they should try to follow - * reasonable URL parameter encoding conventions and be human readable/editable. They may also be stored in a cookie or - * in the user-specific preferences store where JSON may be a useful format to keep them as a {@link String}. - *

        - * - * The following serializers are available: - *

          - *
        • - * {@link com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer}: Serializes to a Map containing String - * keys and values
        • - *
        • - * {@link com.sap.sse.gwt.settings.SettingsToUrlSerializer}: Serializes to a GWT UrlBuilder
        • - *
        • - * {@link com.sap.sse.shared.settings.SettingsToJsonSerializer}: Serializes to org.json.simple objects usable in the - * backend and on Android
        • - *
        • - * {@link com.sap.sse.gwt.settings.SettingsToJsonSerializerGWT}: Serializes to GWT's JSON types. The resliting JSON - * String is compatible with the backend-side SettingsToJsonSerializer.
        • - *
        - * - * In order to enable mapping the settings to URL parameters or JSON structures, each setting needs an associated name - * and the {@link Settings} hierarchy must be ensured. For this every {@link Setting} has a constructor requiring it's - * name and parent Settings object. To make {@link Settings} able to be nested in other {@link Settings} you need to - * provide the very same constructor that can simply call super on {@link AbstractSettings}. This way, generic - * serializers/de-serializers can take over the serialization from/to the various formats. * * @author Axel Uhl (D043530) * diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java index 519b19c264c..fd3abc36c76 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/AbstractGenericSerializableSettings.java @@ -18,7 +18,7 @@ import com.sap.sse.common.settings.value.Value; * *
          * 
        - * public final class ExampleSettings extends AbstractSettings {
        + * public final class ExampleSettings extends AbstractGenericSerializableSettings {
          *     private transient StringSetting myString;
          *     private transient BooleanSetting myBoolean;
          *     
        diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java
        index 15b23ee516c..c7776666cbd 100644
        --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java
        +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/GenericSerializableSettings.java
        @@ -5,10 +5,37 @@ import java.util.Map;
         
         import com.sap.sse.common.settings.Settings;
         
        +/**
        + * {@link Settings} that need to be serialized and de-serialized to/from different formats. In a URL they should try to follow
        + * reasonable URL parameter encoding conventions and be human readable/editable. They may also be stored in a cookie or
        + * in the user-specific preferences store where JSON may be a useful format to keep them as a {@link String}.
        + * 

        + * + * The following serializers are available: + *

          + *
        • + * {@link com.sap.sse.common.settings.serializer.SettingsToStringMapSerializer}: Serializes to a Map containing String + * keys and values
        • + *
        • + * {@link com.sap.sse.gwt.settings.SettingsToUrlSerializer}: Serializes to a GWT UrlBuilder
        • + *
        • + * {@link com.sap.sse.shared.settings.SettingsToJsonSerializer}: Serializes to org.json.simple objects usable in the + * backend and on Android
        • + *
        • + * {@link com.sap.sse.gwt.settings.SettingsToJsonSerializerGWT}: Serializes to GWT's JSON types. The resulting JSON + * String is compatible with the backend-side SettingsToJsonSerializer.
        • + *
        + * + * In order to enable mapping the settings to URL parameters or JSON structures, each setting needs an associated name + * and the {@link Settings} hierarchy must be ensured. For this every {@link Setting} has a constructor requiring it's + * name and parent Settings object. To make {@link Settings} able to be nested in other {@link Settings} you need to + * provide the very same constructor that can simply call super on {@link AbstractSettings}. This way, generic + * serializers/de-serializers can take over the serialization from/to the various formats. + */ public interface GenericSerializableSettings extends Settings, Setting, Serializable { /** - * Path separator for serializers that construct flat keys for the hierachical settings structures (e.g. URL). + * Path separator for serializers that construct flat keys for the hierarchical settings structures (e.g. URL). */ public static final String PATH_SEPARATOR = "."; diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/Setting.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/Setting.java index 8de8ca7fc0d..10f57113dba 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/Setting.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/Setting.java @@ -1,10 +1,8 @@ package com.sap.sse.common.settings.generic; -import com.sap.sse.common.settings.AbstractSettings; - /** - * A setting as contained as values in the map returned by {@link AbstractSettings#getSettings()}. This generic - * view on a {@link AbstractSettings} object can then be used by one or more serializer / de-serializer combos + * A setting as contained as values in the map returned by {@link GenericSerializableSettings#getSettings()}. This generic + * view on a {@link GenericSerializableSettings} object can then be used by one or more serializer / de-serializer combos * for different serialized formats such as URLs, human-readable strings, obfuscated strings, JSON, or * a binary format. * From 6a81ebd0d938c103b141e4c3e8dcd990080348f0 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Fri, 1 Jul 2016 12:00:27 +0200 Subject: [PATCH 085/259] SettingsToJsonSerializer can now directly (de)serialize from/to Strings Changed the test accordingly --- .../test/SettingsToJsonSerializationTest.java | 7 ++----- .../settings/SettingsToJsonSerializer.java | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java index 15ed2f44d7a..d39895fe4f9 100644 --- a/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java +++ b/java/com.sap.sse.shared.android.test/src/com/sap/sse/shared/android/test/SettingsToJsonSerializationTest.java @@ -1,8 +1,5 @@ package com.sap.sse.shared.android.test; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; - import com.sap.sse.common.settings.generic.GenericSerializableSettings; import com.sap.sse.shared.settings.SettingsToJsonSerializer; @@ -14,11 +11,11 @@ public class SettingsToJsonSerializationTest extends AbstractSettingsSerializati protected String serialize(T settings) throws Exception { // Do not change this to return a JSONOBject instance. // JSONOBject is just a HashMap and you only know if it is really JSON serializable if you do it! - return serializer.serialize(settings).toJSONString(); + return serializer.serializeToString(settings); } @Override protected T deserialize(String serializedObject, T settings) throws Exception { - return serializer.deserialize(settings, (JSONObject) new JSONParser().parse(serializedObject)); + return serializer.deserialize(settings, serializedObject); } } diff --git a/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java index f57df9da4a7..4634ac9ec64 100644 --- a/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java +++ b/java/com.sap.sse.shared.android/src/com/sap/sse/shared/settings/SettingsToJsonSerializer.java @@ -2,8 +2,11 @@ package com.sap.sse.shared.settings; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; import com.sap.sse.common.settings.Settings; +import com.sap.sse.common.settings.generic.GenericSerializableSettings; import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; /** @@ -14,6 +17,20 @@ import com.sap.sse.common.settings.serializer.AbstractSettingsToJsonSerializer; * */ public class SettingsToJsonSerializer extends AbstractSettingsToJsonSerializer { + public String serializeToString(GenericSerializableSettings settings) { + return serialize(settings).toJSONString(); + } + + public T deserialize(T settings, String jsonString) { + if (jsonString != null && !jsonString.isEmpty()) { + try { + deserialize(settings, (JSONObject) new JSONParser().parse(jsonString)); + } catch (ParseException e) { + throw new RuntimeException("Could not parse settings as JSON: " + jsonString, e); + } + } + return settings; + } @Override protected JSONObject newOBJECT() { From 33e6ec018c72b5bc47742330596fb3e221075789 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Fri, 1 Jul 2016 12:01:23 +0200 Subject: [PATCH 086/259] Exporting the SettingsToJsonSerializer from com.sap.sse.shared.android to make it accessible in other bundles --- java/com.sap.sse.shared.android/META-INF/MANIFEST.MF | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF index 2f82b40baf2..3ac90edcb68 100644 --- a/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.shared.android/META-INF/MANIFEST.MF @@ -10,6 +10,7 @@ Require-Bundle: com.sap.sse.common, Export-Package: com.sap.sse.concurrent, com.sap.sse.shared.media, com.sap.sse.shared.media.impl, + com.sap.sse.shared.settings, com.sap.sse.util.impl Import-Package: com.sap.sse.common.settings, com.sap.sse.common.settings.generic, From 1696623e2629f96708f5dbd909172ef92413be16 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Fri, 1 Jul 2016 15:12:43 +0200 Subject: [PATCH 087/259] Adjusted GWT Module hierarchy for settings serialization --- .../src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml | 1 - .../main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml index afdbf67d372..e89424161aa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml @@ -44,7 +44,6 @@ - diff --git a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml index b2be37e6831..66f2dbca0ec 100644 --- a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml +++ b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml @@ -11,6 +11,7 @@ --> + From 2b27ce21541aaafaa03a909aca88d9bb4297b8f2 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Fri, 1 Jul 2016 15:35:44 +0200 Subject: [PATCH 088/259] Adjusted GWT Module hierarchy for settings serialization --- .../src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml index e89424161aa..afdbf67d372 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/Home.gwt.xml @@ -44,6 +44,7 @@ + From 37e47d5fdc19f9040372b96c27d1f6048b735f1c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 4 Jul 2016 14:44:57 +0200 Subject: [PATCH 089/259] First stubs to register PreferenceConverters on the UserStore --- .../sap/sailing/server/impl/Activator.java | 30 ++++++++++++++++++- .../impl/GenericJSONPreferenceConverter.java | 28 +++++++++++++++++ .../sap/sse/security/PreferenceConverter.java | 7 +++++ .../src/com/sap/sse/security/UserStore.java | 2 ++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java create mode 100644 java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index edd915de82f..395f272958a 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -34,7 +34,9 @@ import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.Util; import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; import com.sap.sse.replication.Replicable; +import com.sap.sse.security.UserStore; import com.sap.sse.util.ClearStateTestSupport; +import com.sap.sse.util.ServiceTrackerFactory; public class Activator implements BundleActivator { @@ -108,6 +110,9 @@ public class Activator implements BundleActivator { // legacy type name; some DBs may still contain fixes marked with this old package name: properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl"); registrations.add(context.registerService(GPSFixMongoHandler.class, gpsFixMovingMongoHandler, properties)); + + registerPreferenceConvertersWhenUserStoreIsAvailable(context); + // Add an MBean for the service to the JMX bean server: RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); @@ -116,7 +121,30 @@ public class Activator implements BundleActivator { logger.log(Level.INFO, "Started "+context.getBundle().getSymbolicName()+". Character encoding: "+ Charset.defaultCharset()); } - + + private void registerPreferenceConvertersWhenUserStoreIsAvailable(BundleContext bundleContext) { + ServiceTracker userStoreTracker = ServiceTrackerFactory.createAndOpen(bundleContext, + UserStore.class); + new Thread("ServiceTracker waiting for UserStore service") { + @Override + public void run() { + try { + logger.info("Waiting for UserStore service..."); + UserStore userStore = userStoreTracker.waitForService(0); + logger.info("Obtained UserStore service " + userStore); + registerPreferenceConvertersForUserStore(userStore); + } catch (InterruptedException e) { + logger.log(Level.SEVERE, "Interrupted while waiting for UserStore service", e); + } + } + }.start(); + } + + protected void registerPreferenceConvertersForUserStore(UserStore userStore) { + // TODO implement for favorite settings + // userStore.registerPreferenceConverter("TODO", new GenericJSONPreferenceConverter(null)); + } + public void stop(BundleContext context) throws Exception { masterDataImportClassLoaderServiceTracker.close(); if (extenderBundleTracker != null) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java new file mode 100644 index 00000000000..55f8cfd8320 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java @@ -0,0 +1,28 @@ +package com.sap.sailing.server.impl; + +import java.util.function.Supplier; + +import com.sap.sse.common.settings.generic.GenericSerializableSettings; +import com.sap.sse.security.PreferenceConverter; +import com.sap.sse.shared.settings.SettingsToJsonSerializer; + +public class GenericJSONPreferenceConverter implements PreferenceConverter { + + private final SettingsToJsonSerializer serializer = new SettingsToJsonSerializer(); + private final Supplier emptyInstanceFactory; + + public GenericJSONPreferenceConverter(Supplier emptyInstanceFactory) { + this.emptyInstanceFactory = emptyInstanceFactory; + } + + @Override + public String toString(PREF preference) { + return serializer.serializeToString(preference); + } + + @Override + public PREF toPreference(String stringPreference) { + return serializer.deserialize(emptyInstanceFactory.get(), stringPreference); + } + +} diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java new file mode 100644 index 00000000000..90a5b144db2 --- /dev/null +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java @@ -0,0 +1,7 @@ +package com.sap.sse.security; + +public interface PreferenceConverter { + String toString(PREF preference); + + PREF toPreference(String stringPreference); +} diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index f51bcb8423b..88e10ab8b20 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -106,4 +106,6 @@ public interface UserStore extends Named { * {@code username} no access token has previously been {@link #setAccessToken(String, String) set}. */ String getAccessToken(String username); + +// void registerPreferenceConverter(String preferenceKey, PreferenceConverter converter); } From 4d03dc6a1d95d91f7b07c67c22c3c97eff9abf36 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 4 Jul 2016 16:03:30 +0200 Subject: [PATCH 090/259] Moved keyProvider to AbstractSuggestedMultiSelectionDataProvider --- .../AbstractSuggestedMultiSelectionDataProvider.java | 12 ++++++++++++ .../SuggestedMultiSelectionListDataProvider.java | 8 +------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java index 931a7b6f140..13f6b30b4c6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java @@ -6,12 +6,24 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.google.gwt.view.client.ProvidesKey; + public abstract class AbstractSuggestedMultiSelectionDataProvider implements SuggestedMultiSelectionDataProvider { + private final ProvidesKey keyProvider; private final Map selectedItemsMap = new HashMap<>(); private boolean notificationsEnabled; + protected AbstractSuggestedMultiSelectionDataProvider(ProvidesKey keyProvider) { + this.keyProvider = keyProvider; + } + + @Override + public final Object getKey(T item) { + return keyProvider == null ? item : keyProvider.getKey(item); + } + @Override public final void addSelection(T item) { Object key = getKey(item); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java index c65a48e5837..2716d42b113 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java @@ -8,18 +8,12 @@ import com.google.gwt.view.client.ProvidesKey; public class SuggestedMultiSelectionListDataProvider extends AbstractSuggestedMultiSelectionDataProvider { - private final ProvidesKey keyProvider; private final List suggestionItemsList = new ArrayList(); public SuggestedMultiSelectionListDataProvider(ProvidesKey keyProvider) { - this.keyProvider = keyProvider; + super(keyProvider); } - @Override - public Object getKey(T item) { - return keyProvider == null ? item : keyProvider.getKey(item); - } - public void setSuggestionItems(Collection suggestionItems) { suggestionItemsList.clear(); suggestionItemsList.addAll(suggestionItems); From d77f6adb4394983363014afb62fdf1180fd64327 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 4 Jul 2016 17:06:32 +0200 Subject: [PATCH 091/259] Initial implementation to register PreferenceConverters on the UserStore and set/get preference objects that are being held in memory for fast access --- .../userstore/mongodb/UserStoreImpl.java | 117 ++++++++++++++++++ .../src/com/sap/sse/security/UserStore.java | 26 +++- 2 files changed, 141 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 574d38ba348..4237f395c2c 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -7,10 +7,12 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; import java.util.logging.Logger; import org.apache.shiro.SecurityUtils; +import com.sap.sse.security.PreferenceConverter; import com.sap.sse.security.SocialSettingsKeys; import com.sap.sse.security.User; import com.sap.sse.security.UserStore; @@ -48,6 +50,18 @@ public class UserStoreImpl implements UserStore { */ private final ConcurrentHashMap> preferences; + /** + * Converter objects to map preference Strings to Objects. + * The keys must match the keys of the preferences. + */ + private final ConcurrentHashMap> preferenceConverters; + + /** + * This is another view of the String preferences mapped by {@link #preferenceConverters} to Objects. + * Keys are the usernames, values are the key/value pairs representing the user's preferences. + */ + private final ConcurrentHashMap> preferenceObjects; + /** * Won't be serialized and remains null on the de-serializing end. */ @@ -65,6 +79,8 @@ public class UserStoreImpl implements UserStore { settingTypes = new ConcurrentHashMap<>(); usersByAccessToken = new ConcurrentHashMap<>(); preferences = new ConcurrentHashMap<>(); + preferenceConverters = new ConcurrentHashMap<>(); + preferenceObjects = new ConcurrentHashMap<>(); this.mongoObjectFactory = mongoObjectFactory; if (domainObjectFactory != null) { for (Entry> e : domainObjectFactory.loadSettingTypes().entrySet()) { @@ -105,6 +121,8 @@ public class UserStoreImpl implements UserStore { @Override public void clear() { preferences.clear(); + preferenceConverters.clear(); + preferenceObjects.clear(); emailForUsername.clear(); settings.clear(); settingTypes.clear(); @@ -405,6 +423,11 @@ public class UserStoreImpl implements UserStore { @Override public void setPreference(String username, String key, String value) { + setPreferenceInternal(username, key, value); + loadPreferenceIfConverterIsAvailable(username, key); + } + + private void setPreferenceInternal(String username, String key, String value) { Map userMap = preferences.get(username); if (userMap == null) { synchronized (preferences) { @@ -431,6 +454,7 @@ public class UserStoreImpl implements UserStore { mongoObjectFactory.storePreferences(username, userMap); } } + unsetPreferenceObject(username, key); } @Override @@ -466,4 +490,97 @@ public class UserStoreImpl implements UserStore { public Map> getAllSettingTypes() { return settingTypes; } + + @Override + public void registerPreferenceConverter(String preferenceKey, PreferenceConverter converter) { + PreferenceConverter alreadyAssociatedConverter = preferenceConverters.putIfAbsent(preferenceKey, converter); + + if(alreadyAssociatedConverter == null) { + final Set usersToProcess = new HashSet<>(preferences.keySet()); + for (String user : usersToProcess) { + loadPreferenceWithConverter(user, preferenceKey, converter); + } + } else { + logger.log(Level.SEVERE, "PreferenceConverter " + alreadyAssociatedConverter + " for key " + preferenceKey + + " is already registered. Converter " + converter + " will not be registered"); + } + } + + private void loadPreferenceIfConverterIsAvailable(String username, String key) { + PreferenceConverter preferenceConverter = preferenceConverters.get(key); + if (preferenceConverter != null) { + loadPreferenceWithConverter(username, key, preferenceConverter); + } + } + + private void loadPreferenceWithConverter(String username, String key, PreferenceConverter preferenceConverter) { + final String preferenceString = getPreference(username, key); + if (preferenceString != null) { + try { + final Object convertedObject = preferenceConverter.toPreference(preferenceString); + setPreferenceObjectInternal(username, key, convertedObject); + } catch (Throwable t) { + logger.log(Level.SEVERE, "Error while converting preference for key " + key + " from String \"" + + preferenceString + "\"", t); + } + } + } + + private void setPreferenceObjectInternal(String username, String key, final Object convertedObject) { + Map userMap = preferenceObjects.get(username); + if (userMap == null) { + synchronized (preferenceObjects) { + // only synchronize when necessary + userMap = preferenceObjects.get(username); + if (userMap == null) { + userMap = new ConcurrentHashMap<>(); + preferenceObjects.put(username, userMap); + } + } + } + userMap.put(key, convertedObject); + } + + private void unsetPreferenceObject(String username, String key) { + Map userObjectMap = preferenceObjects.get(username); + if (userObjectMap != null) { + userObjectMap.remove(key); + } + } + + @Override + public T getPreferenceObject(String username, String key) { + final Object result; + Map userMap = preferenceObjects.get(username); + if (userMap != null) { + result = userMap.get(key); + } else { + result = null; + } + @SuppressWarnings("unchecked") + T resultT = (T) result; + return resultT; + } + + @Override + public void setPreferenceObject(String username, String key, Object preferenceObject) + throws IllegalArgumentException { + @SuppressWarnings("unchecked") + PreferenceConverter preferenceConverter = (PreferenceConverter) preferenceConverters.get(key); + if (preferenceConverter == null) { + throw new IllegalArgumentException("Setting preference for key "+key+" but there is no converter associated!"); + } + if(preferenceObject == null) { + unsetPreference(username, key); + } else { + try { + String stringPreference = preferenceConverter.toString(preferenceObject); + setPreferenceInternal(username, key, stringPreference); + setPreferenceObjectInternal(username, key, preferenceObject); + } catch (Throwable t) { + logger.log(Level.SEVERE, "Error while converting preference for key " + key + " from Object \"" + + preferenceObject + "\"", t); + } + } + } } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index 88e10ab8b20..b08ba8c9fe8 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -53,6 +53,30 @@ public interface UserStore extends Named { void unsetPreference(String username, String key); String getPreference(String username, String key); + + /** + * Registers a converter objects for a preference key that is used to convert preference Strings to Objects. This + * makes it possible to access deserialized settings without the need to do the deserialization over and over again. + * + * @param key the key to associate the converter with + * @param converter the converter to use for (de)serialization + */ + void registerPreferenceConverter(String key, PreferenceConverter converter); + + /** + * Gets a preference object. Always returns null if there is no converter associated with the given key -> see + * {@link #registerPreferenceConverter(String, PreferenceConverter)}. + */ + T getPreferenceObject(String username, String key); + + /** + * Sets a preference as Object. This converts the given Object to a preference String using a + * {@link PreferenceConverter} that was registered through + * {@link #registerPreferenceConverter(String, PreferenceConverter)}. + * + * @throws IllegalArgumentException if there is no {@link PreferenceConverter} registered with the given key. + */ + void setPreferenceObject(String username, String key, Object preferenceObject) throws IllegalArgumentException; /** * Sets a value for a key if that key was previously added to this store using {@link #addSetting(String, Class)}. @@ -106,6 +130,4 @@ public interface UserStore extends Named { * {@code username} no access token has previously been {@link #setAccessToken(String, String) set}. */ String getAccessToken(String username); - -// void registerPreferenceConverter(String preferenceKey, PreferenceConverter converter); } From bb5a5b0b36c947b7717c8f8813073a5922e5184c Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 4 Jul 2016 17:36:07 +0200 Subject: [PATCH 092/259] Added DTO interface to SimpleCompetitorDTO --- .../gwt/home/communication/event/SimpleCompetitorDTO.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorDTO.java index 1a05fa966cd..ebde9a2c6af 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorDTO.java @@ -8,8 +8,9 @@ import com.sap.sailing.domain.base.Nationality; import com.sap.sailing.domain.common.dto.CompetitorDTO; import com.sap.sailing.domain.common.dto.NamedDTO; import com.sap.sse.common.CountryCode; +import com.sap.sse.gwt.dispatch.shared.commands.DTO; -public class SimpleCompetitorDTO extends NamedDTO implements Serializable, Comparable { +public class SimpleCompetitorDTO extends NamedDTO implements DTO, Serializable, Comparable { private static final long serialVersionUID = -5743976446085202047L; From 4190da82db9dfa75ca38da1720e02f7835c593b0 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 4 Jul 2016 17:57:00 +0200 Subject: [PATCH 093/259] Added dispatch action and result for competitor suggestions --- .../profile/CompetitorSuggestionResult.java | 27 ++++++++ .../GetCompetitorSuggestionAction.java | 67 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java new file mode 100644 index 00000000000..3964ddddabe --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java @@ -0,0 +1,27 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.Collection; + +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; + +public class CompetitorSuggestionResult extends SortedSetResult { + + private int moreSuggestionsCount; + + protected CompetitorSuggestionResult() { + } + + public CompetitorSuggestionResult(Collection values, int moreSuggestionsCount) { + super(values); + this.moreSuggestionsCount = moreSuggestionsCount; + } + + public int getMoreSuggestionsCount() { + return moreSuggestionsCount; + } + + public boolean hasMoreSuggestions() { + return moreSuggestionsCount > 0; + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java new file mode 100644 index 00000000000..8a57d73cb1e --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java @@ -0,0 +1,67 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.gwt.home.communication.SailingAction; +import com.sap.sailing.gwt.home.communication.SailingDispatchContext; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sse.common.Util; +import com.sap.sse.common.filter.AbstractListFilter; +import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; + +public class GetCompetitorSuggestionAction implements SailingAction { + + private String query; + private int limit; + + @GwtIncompatible + private final AbstractListFilter competitorFilter = new AbstractListFilter() { + @Override + public Iterable getStrings(Competitor competitor) { + if (competitor.getBoat() == null) return Arrays.asList(competitor.getName()); + return Arrays.asList(competitor.getBoat().getSailID(), competitor.getName()); + } + }; + + @SuppressWarnings("unused") + private GetCompetitorSuggestionAction() { + } + + public GetCompetitorSuggestionAction(String query, int limit) { + this.query = query; + this.limit = limit; + } + + @Override + @GwtIncompatible + public CompetitorSuggestionResult execute(SailingDispatchContext ctx) throws DispatchException { + Iterable filteredCompetitors = getFilteredCompetitors(ctx); + Collection result = convertToSimpleCompetitorDTOs(filteredCompetitors); + return new CompetitorSuggestionResult(result, Math.max(0, Util.size(filteredCompetitors) - limit)); + } + + @GwtIncompatible + private Iterable getFilteredCompetitors(SailingDispatchContext ctx) { + Iterable allCompetitors = ctx.getRacingEventService().getCompetitorStore().getCompetitors(); + Set normalizedQuery = Collections.singleton(query.trim()); + return competitorFilter.applyFilter(normalizedQuery, Util.addAll(allCompetitors, new ArrayList())); + } + + @GwtIncompatible + private Collection convertToSimpleCompetitorDTOs(Iterable filteredCompetitors) { + Collection result = new ArrayList<>(); + int count = 0; + for (Competitor competitor : filteredCompetitors) { + result.add(new SimpleCompetitorDTO(competitor)); + if(++count >= limit) break; + } + return result; + } + +} From 6b41b9b87b1c4c798eca7d4db94d6852450bf122 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 4 Jul 2016 17:57:22 +0200 Subject: [PATCH 094/259] Added dispatch action and result for competitor suggestions --- .../profile/CompetitorSuggestionResult.java | 12 ++++++++++++ .../profile/GetCompetitorSuggestionAction.java | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java index 3964ddddabe..bc1caf9a7df 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java @@ -5,6 +5,11 @@ import java.util.Collection; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; +/** + * {@link SortedSetResult} extension for suggested competitor search. This result contains a set of + * {@link SimpleCompetitorDTO competitor}s representing the suggestions, as well as information if there are more + * suggestions possible. + */ public class CompetitorSuggestionResult extends SortedSetResult { private int moreSuggestionsCount; @@ -17,10 +22,17 @@ public class CompetitorSuggestionResult extends SortedSetResulttrue if there is at least one {@link #getMoreSuggestionsCount() additional suggestion + * possible}, false otherwise + */ public boolean hasMoreSuggestions() { return moreSuggestionsCount > 0; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java index 8a57d73cb1e..a3e0ea80711 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java @@ -7,6 +7,7 @@ import java.util.Collections; import java.util.Set; import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Boat; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.gwt.home.communication.SailingAction; import com.sap.sailing.gwt.home.communication.SailingDispatchContext; @@ -15,6 +16,14 @@ import com.sap.sse.common.Util; import com.sap.sse.common.filter.AbstractListFilter; import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; +/** + * {@link SailingAction} implementation to load competitor data to be shown in a suggestion box depending on the + * {@link #GetCompetitorSuggestionAction(String, int) given query string}, where the amount of loaded entries can be + * limited. + * + * The given query string is matched against the competitor's {@link Competitor#getName() name} and + * {@link Boat#getSailID() sail-id} (which is determined from its {@link Competitor#getBoat() boat}, if any). + */ public class GetCompetitorSuggestionAction implements SailingAction { private String query; @@ -33,6 +42,15 @@ public class GetCompetitorSuggestionAction implements SailingAction Date: Mon, 4 Jul 2016 17:57:59 +0200 Subject: [PATCH 095/259] Connected user preferences competitor selection to the backend logic --- .../user/profile/UserProfileActivity.java | 6 ++++ .../profile/UserProfileClientFactory.java | 3 +- .../places/user/profile/UserProfileView.java | 2 ++ .../UserProfilePreferencesPresenter.java | 35 +++++++++++++------ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java index 094b20b1d0c..2211d9cd219 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java @@ -8,6 +8,7 @@ import com.google.gwt.safehtml.shared.SafeUri; import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.sap.sailing.gwt.common.client.controls.tabbar.TabView; +import com.sap.sailing.gwt.home.communication.SailingDispatchSystem; import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator; import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper; import com.sap.sailing.gwt.home.shared.app.NavigationPathDisplay; @@ -111,4 +112,9 @@ public class UserProfileActivity extends AbstractActivity implements UserProfile public UserManagementServiceAsync getUserManagementService() { return clientFactory.getUserManagementService(); } + + @Override + public SailingDispatchSystem getDispatch() { + return clientFactory.getDispatch(); + } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileClientFactory.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileClientFactory.java index bedc9c5a2bf..79ed2b265c5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileClientFactory.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileClientFactory.java @@ -1,8 +1,9 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile; +import com.sap.sailing.gwt.home.shared.app.ClientFactoryWithDispatch; import com.sap.sailing.gwt.ui.client.SailingClientFactory; import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory; import com.sap.sse.security.ui.authentication.WithAuthenticationManager; -public interface UserProfileClientFactory extends SailingClientFactory, ErrorAndBusyClientFactory, WithAuthenticationManager { +public interface UserProfileClientFactory extends ClientFactoryWithDispatch, SailingClientFactory, ErrorAndBusyClientFactory, WithAuthenticationManager { } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java index aa0daa52deb..0bebcf4a340 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java @@ -4,6 +4,7 @@ import com.google.gwt.place.shared.Place; import com.google.gwt.safehtml.shared.SafeUri; import com.google.gwt.user.client.ui.IsWidget; import com.sap.sailing.gwt.common.client.controls.tabbar.TabView; +import com.sap.sailing.gwt.home.communication.SailingDispatchSystem; import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; import com.sap.sailing.gwt.home.shared.places.fakeseries.AbstractSeriesPlace; import com.sap.sailing.gwt.home.shared.places.start.StartPlace; @@ -27,6 +28,7 @@ public interface UserProfileView getFavoriteCompetitorsDataProvider() { - SuggestedMultiSelectionListDataProvider dataProvider = - new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { + return new AbstractSuggestedMultiSelectionDataProvider(new ProvidesKey() { @Override public Object getKey(SimpleCompetitorDTO item) { return item.getSailID(); } - }); - dataProvider.setSuggestionItems(competitorsDummyData); - return dataProvider; + }) { + + @Override + protected void getSuggestions(String query, final SuggestionItemsCallback callback) { + userProfilePresenter.getDispatch().execute(new GetCompetitorSuggestionAction(query, 20), + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Window.alert("Error while loading competitor suggestion"); + } + + @Override + public void onSuccess(CompetitorSuggestionResult result) { + callback.setSuggestionItems(result.getValues()); + } + }); + } + }; } - private final List competitorsDummyData = Arrays.asList( - new SimpleCompetitorDTO("John Doe", "GBR001", "gb", null), - new SimpleCompetitorDTO("Max Mustermann", "GER001", "de", null), - new SimpleCompetitorDTO("Competitor with a long name to test wrapping in favourite list", "USA 1337", "us", null)); } From cd5ca3741ebfe204013255344624a09094a333c2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 10:40:20 +0200 Subject: [PATCH 096/259] It's now possible to get notified on preference object changes in UserStore --- .../src/com/sap/sse/common/Util.java | 6 ++ .../userstore/mongodb/UserStoreImpl.java | 65 ++++++++++++++++++- .../src/com/sap/sse/security/UserStore.java | 4 ++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java index dd8a03dffb3..42d6092bff5 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java @@ -364,6 +364,12 @@ public class Util { } map.get(key).add(value); } + + public static void removeFromAllValueSets(Map> map, V value) { + for (Set set : map.values()) { + set.remove(value); + } + } public static String join(String separator, String... strings) { return joinStrings(separator, Arrays.asList(strings)); diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 4237f395c2c..f9f94bec1e4 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -1,7 +1,11 @@ package com.sap.sse.security.userstore.mongodb; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; @@ -12,7 +16,9 @@ import java.util.logging.Logger; import org.apache.shiro.SecurityUtils; +import com.sap.sse.common.Util; import com.sap.sse.security.PreferenceConverter; +import com.sap.sse.security.PreferenceObjectListener; import com.sap.sse.security.SocialSettingsKeys; import com.sap.sse.security.User; import com.sap.sse.security.UserStore; @@ -62,6 +68,8 @@ public class UserStoreImpl implements UserStore { */ private final ConcurrentHashMap> preferenceObjects; + private transient Map>> listeners; + /** * Won't be serialized and remains null on the de-serializing end. */ @@ -81,6 +89,7 @@ public class UserStoreImpl implements UserStore { preferences = new ConcurrentHashMap<>(); preferenceConverters = new ConcurrentHashMap<>(); preferenceObjects = new ConcurrentHashMap<>(); + listeners = new HashMap<>(); this.mongoObjectFactory = mongoObjectFactory; if (domainObjectFactory != null) { for (Entry> e : domainObjectFactory.loadSettingTypes().entrySet()) { @@ -117,6 +126,15 @@ public class UserStoreImpl implements UserStore { } } } + + private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { + ois.defaultReadObject(); + listeners = new HashMap<>(); + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } @Override public void clear() { @@ -538,13 +556,15 @@ public class UserStoreImpl implements UserStore { } } } - userMap.put(key, convertedObject); + Object oldPreference = userMap.put(key, convertedObject); + notifyListenersOnPreferenceObjectChange(username, key, oldPreference, convertedObject); } private void unsetPreferenceObject(String username, String key) { Map userObjectMap = preferenceObjects.get(username); if (userObjectMap != null) { - userObjectMap.remove(key); + Object oldPreference = userObjectMap.remove(key); + notifyListenersOnPreferenceObjectChange(username, key, oldPreference, null); } } @@ -583,4 +603,45 @@ public class UserStoreImpl implements UserStore { } } } + + private void notifyListenersOnPreferenceObjectChange(String username, String key, Object oldPreference, + Object newPreference) { + synchronized (listeners) { + for (PreferenceObjectListener listener : Util.get(listeners, key, + Collections.> emptySet())) { + @SuppressWarnings("unchecked") + PreferenceObjectListener listenerToFire = (PreferenceObjectListener) listener; + listenerToFire.preferenceObjectChanged(username, key, oldPreference, newPreference); + } + } + } + + @Override + public void addPreferenceObjectListener(String key, PreferenceObjectListener listener, + boolean fireForAlreadyExistingPreferences) { + synchronized (listeners) { + Util.addToValueSet(listeners, key, listener); + if (fireForAlreadyExistingPreferences) { + final Set usersToProcess = new HashSet<>(preferences.keySet()); + for (String username : usersToProcess) { + Map userMap = preferenceObjects.get(username); + if (userMap != null) { + Object preferenceObject = userMap.get(key); + if (preferenceObject != null) { + @SuppressWarnings("unchecked") + PreferenceObjectListener listenerToFire = (PreferenceObjectListener) listener; + listenerToFire.preferenceObjectChanged(username, key, null, preferenceObject); + } + } + } + } + } + } + + @Override + public void removePreferenceObjectListener(PreferenceObjectListener listener) { + synchronized (listeners) { + Util.removeFromAllValueSets(listeners, listener); + } + } } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index b08ba8c9fe8..b47c7227075 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -130,4 +130,8 @@ public interface UserStore extends Named { * {@code username} no access token has previously been {@link #setAccessToken(String, String) set}. */ String getAccessToken(String username); + + void addPreferenceObjectListener(String key, PreferenceObjectListener listener, boolean fireForAlreadyExistingPreferences); + + void removePreferenceObjectListener(PreferenceObjectListener listener); } From 69d697843fc7455d2e3fd4189633ca639fea3084 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 10:57:53 +0200 Subject: [PATCH 097/259] Forgot to commit one file It's now possible to get notified on preference object changes in UserStore --- .../src/com/sap/sse/security/PreferenceObjectListener.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java new file mode 100644 index 00000000000..92a81c65be3 --- /dev/null +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java @@ -0,0 +1,5 @@ +package com.sap.sse.security; + +public interface PreferenceObjectListener { + void preferenceObjectChanged(String username, String key, PrefT oldPreference, PrefT newPreference); +} From 4edc91f10b859f5673f3bc4f6ff901b797d495c6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 13:34:02 +0200 Subject: [PATCH 098/259] Added JavaDoc to PreferenceObjectListener --- .../src/com/sap/sse/security/PreferenceObjectListener.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java index 92a81c65be3..6d594d3169a 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java @@ -1,5 +1,10 @@ package com.sap.sse.security; +/** + * Listener used by UserStore to notify about changes of stored preference objects. + * + * @param The type of preference object this Listener handles. + */ public interface PreferenceObjectListener { void preferenceObjectChanged(String username, String key, PrefT oldPreference, PrefT newPreference); } From 52a750d3bd973776241ffce702a6c712b8e108bb Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 13:35:11 +0200 Subject: [PATCH 099/259] Added utility class that makes it possible to hold optimized asociations for which users should be notified about a specific object --- .../src/com/sap/sse/common/Util.java | 7 ++ .../PreferenceObjectBasedNotificationSet.java | 93 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java index 42d6092bff5..5569ae173f6 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java @@ -370,6 +370,13 @@ public class Util { set.remove(value); } } + + public static void removeFromValueSet(Map> map, K key, V value) { + final Set valuesPerKey = map.get(key); + if(valuesPerKey != null) { + valuesPerKey.remove(value); + } + } public static String join(String separator, String... strings) { return joinStrings(separator, Arrays.asList(strings)); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java new file mode 100644 index 00000000000..8e553145c79 --- /dev/null +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -0,0 +1,93 @@ +package com.sap.sse.security; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.sap.sse.common.Util; + +/** + * Holds an optimized association of who to notify about specific objects. + * + * @param + * The type of preference object on which the calculation of the objects to notify is based on. + * @param + * The type of object for which the users to notify is managed. + */ +public abstract class PreferenceObjectBasedNotificationSet { + private static final Logger logger = Logger.getLogger(PreferenceObjectBasedNotificationSet.class.getName()); + + private final UserStore store; + private final PreferenceObjectListener listener = new PreferenceObjectListenerImpl(); + + /** + * The keys are the objects to notify for. The values are the names of the users to notify about an object. + */ + private final Map> notifications = new HashMap<>(); + + public PreferenceObjectBasedNotificationSet(String key, UserStore store) { + this.store = store; + store.addPreferenceObjectListener(key, listener, true); + } + + public void stop() { + store.removePreferenceObjectListener(listener); + } + + protected abstract Collection calculateObjectsToNotify(PrefT preference); + + private Iterable getUsersToNotifyFor(T object) { + // TODO use read lock + synchronized (notifications) { + return new HashSet<>(Util.get(notifications, object, Collections.emptySet())); + } + } + + /** + * The given consumer will be called for every user that needs to be notified about the given object. + */ + public void forUsersMappedTo(T object, Consumer consumer) { + for (String username : getUsersToNotifyFor(object)) { + // User objects can change silently. So we just keep the usernames and get the associated user objects on + // the fly. + User user = store.getUserByName(username); + if (user == null) { + logger.log(Level.SEVERE, "Could not get User for name \"" + username + "\""); + } else { + consumer.accept(user); + } + } + } + + private class PreferenceObjectListenerImpl implements PreferenceObjectListener { + @Override + public void preferenceObjectChanged(String username, String key, PrefT oldPreference, PrefT newPreference) { + Collection oldObjectsToNotify = oldPreference == null ? Collections.emptySet() + : calculateObjectsToNotify(oldPreference); + Collection newObjectsToNotify = newPreference == null ? Collections.emptySet() + : calculateObjectsToNotify(newPreference); + + Set objectsToRemove = new HashSet<>(oldObjectsToNotify); + objectsToRemove.removeAll(newObjectsToNotify); + + Set objectsToAdd = new HashSet<>(newObjectsToNotify); + objectsToAdd.removeAll(oldObjectsToNotify); + + // TODO use write lock + synchronized (notifications) { + for (T objectToRemove : objectsToRemove) { + Util.removeFromValueSet(notifications, objectToRemove, username); + } + for (T objectToAdd : objectsToAdd) { + Util.addToValueSet(notifications, objectToAdd, username); + } + } + } + } +} From d8118553c83da701e56ac01b127cbb81f01284bb Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 13:41:32 +0200 Subject: [PATCH 100/259] Added missing GWT module inherits because UserService was extended to used additional stuff from com.sap.sse.gwt --- .../src/main/resources/com/sap/sse/security/ui/Register.gwt.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/Register.gwt.xml b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/Register.gwt.xml index 83d302198c9..554473fbc13 100644 --- a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/Register.gwt.xml +++ b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/Register.gwt.xml @@ -12,6 +12,7 @@ --> + From ac2b1987090b4af85eef20e645887b70e99cc883 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 15:10:18 +0200 Subject: [PATCH 101/259] Initial implementation of NotificationPreferences --- .../BoatClassNotificationPreference.java | 41 +++++++++++++++++++ .../BoatClassNotificationPreferences.java | 36 ++++++++++++++++ .../CompetitorNotificationPreference.java | 34 +++++++++++++++ .../CompetitorNotificationPreferences.java | 36 ++++++++++++++++ .../preferences/NotificationPreferences.java | 38 +++++++++++++++++ 5 files changed, 185 insertions(+) create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java new file mode 100644 index 00000000000..c0d21281ee1 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java @@ -0,0 +1,41 @@ +package com.sap.sailing.domain.common.preferences; + +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.BooleanSetting; +import com.sap.sse.common.settings.generic.StringSetting; + +public class BoatClassNotificationPreference extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -6510535362114348707L; + + private transient StringSetting boatClassName; + private transient BooleanSetting notifyAboutUpcomingRaces; + private transient BooleanSetting notifyAboutResults; + + public BoatClassNotificationPreference() { + } + + public BoatClassNotificationPreference(String boatClassName, boolean notifyAboutRaces, boolean notifyAboutResults) { + this.boatClassName.setValue(boatClassName); + this.notifyAboutUpcomingRaces.setValue(notifyAboutRaces); + this.notifyAboutResults.setValue(notifyAboutResults); + } + + @Override + protected void addChildSettings() { + boatClassName = new StringSetting("boatClassName", this); + notifyAboutUpcomingRaces = new BooleanSetting("notifyAboutUpcomingRaces", this, false); + notifyAboutResults = new BooleanSetting("notifyAboutResults", this, false); + } + + public String getBoatClassName() { + return boatClassName.getValue(); + } + + public boolean isNotifyAboutUpcomingRaces() { + return Boolean.TRUE.equals(notifyAboutUpcomingRaces.getValue()); + } + + public boolean isNotifyAboutResults() { + return Boolean.TRUE.equals(notifyAboutResults.getValue()); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java new file mode 100644 index 00000000000..e2c0b05a1a6 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java @@ -0,0 +1,36 @@ +package com.sap.sailing.domain.common.preferences; + +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.SettingsFactory; +import com.sap.sse.common.settings.generic.SettingsList; + +public class BoatClassNotificationPreferences extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -3682996540081614053L; + + private transient SettingsList boatClasses; + + public BoatClassNotificationPreferences() { + } + + public BoatClassNotificationPreferences(String name, AbstractGenericSerializableSettings settings) { + super(name, settings); + } + + @Override + protected void addChildSettings() { + boatClasses = new SettingsList<>("boatClasses", this, new SettingsFactory() { + @Override + public BoatClassNotificationPreference newInstance() { + return new BoatClassNotificationPreference(); + } + }); + } + + public Iterable getBoatClasses() { + return boatClasses.getValues(); + } + + public void setBoatClasses(Iterable boatClasses) { + this.boatClasses.setValues(boatClasses); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java new file mode 100644 index 00000000000..a146fbdcdd1 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java @@ -0,0 +1,34 @@ +package com.sap.sailing.domain.common.preferences; + +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.BooleanSetting; +import com.sap.sse.common.settings.generic.StringSetting; + +public class CompetitorNotificationPreference extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -6510535362114348707L; + + private transient StringSetting competitorId; + private transient BooleanSetting notifyAboutResults; + + public CompetitorNotificationPreference() { + } + + public CompetitorNotificationPreference(String competitorId, boolean notifyAboutResults) { + this.competitorId.setValue(competitorId); + this.notifyAboutResults.setValue(notifyAboutResults); + } + + @Override + protected void addChildSettings() { + competitorId = new StringSetting("competitorId", this); + notifyAboutResults = new BooleanSetting("notifyAboutResults", this, false); + } + + public String getCompetitorId() { + return competitorId.getValue(); + } + + public boolean isNotifyAboutResults() { + return Boolean.TRUE.equals(notifyAboutResults.getValue()); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java new file mode 100644 index 00000000000..e0ed4c50003 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java @@ -0,0 +1,36 @@ +package com.sap.sailing.domain.common.preferences; + +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.SettingsFactory; +import com.sap.sse.common.settings.generic.SettingsList; + +public class CompetitorNotificationPreferences extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -3682996540081614053L; + + private transient SettingsList competitors; + + public CompetitorNotificationPreferences() { + } + + public CompetitorNotificationPreferences(String name, AbstractGenericSerializableSettings settings) { + super(name, settings); + } + + @Override + protected void addChildSettings() { + competitors = new SettingsList<>("competitors", this, new SettingsFactory() { + @Override + public CompetitorNotificationPreference newInstance() { + return new CompetitorNotificationPreference(); + } + }); + } + + public Iterable getCompetitors() { + return competitors.getValues(); + } + + public void setCompetitors(Iterable boatClasses) { + this.competitors.setValues(boatClasses); + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java new file mode 100644 index 00000000000..f4939589b1a --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java @@ -0,0 +1,38 @@ +package com.sap.sailing.domain.common.preferences; + +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; + +/** + * Preferences for Sailing users that define for which Objects a user wants to receive specific notifications. + * This currently includes: + *
          + *
        • Results for a favourite Competitor
        • + *
        • Results for a favourite BoatClass
        • + *
        • Upcoming races for a favourite BoatClass
        • + *
        + */ +public class NotificationPreferences extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = 8865010526321472376L; + + public static final String PREF_NAME = "sailing.notifications"; + + private transient BoatClassNotificationPreferences boatClassPreferences; + private transient CompetitorNotificationPreferences competitorPreferences; + + public NotificationPreferences() { + } + + @Override + protected void addChildSettings() { + boatClassPreferences = new BoatClassNotificationPreferences("boatClassPreferences", this); + competitorPreferences = new CompetitorNotificationPreferences("competitorPreferences", this); + } + + public BoatClassNotificationPreferences getBoatClassPreferences() { + return boatClassPreferences; + } + + public CompetitorNotificationPreferences getCompetitorPreferences() { + return competitorPreferences; + } +} From 051b5448d221a97264369a977ae42d2d10e90a35 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 15:11:22 +0200 Subject: [PATCH 102/259] Registered NotificationPreferences on UserStore to hold instances in memory --- java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF | 1 + .../src/com/sap/sailing/server/impl/Activator.java | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF index c058553927b..66913ee2003 100644 --- a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF @@ -14,6 +14,7 @@ Export-Package: com.sap.sailing.domain.common, com.sap.sailing.domain.common.i18n, com.sap.sailing.domain.common.impl, com.sap.sailing.domain.common.media, + com.sap.sailing.domain.common.preferences, com.sap.sailing.domain.common.quadtree, com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test", com.sap.sailing.domain.common.racelog, diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 395f272958a..c476d258cc0 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -21,6 +21,7 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.common.preferences.NotificationPreferences; import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; import com.sap.sailing.domain.persistence.racelog.tracking.GPSFixMongoHandler; @@ -141,8 +142,8 @@ public class Activator implements BundleActivator { } protected void registerPreferenceConvertersForUserStore(UserStore userStore) { - // TODO implement for favorite settings - // userStore.registerPreferenceConverter("TODO", new GenericJSONPreferenceConverter(null)); + userStore.registerPreferenceConverter(NotificationPreferences.PREF_NAME, + new GenericJSONPreferenceConverter(NotificationPreferences::new)); } public void stop(BundleContext context) throws Exception { From 86a84eae8f4018b5a2a47a0f05a4963c34052eb6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 15:11:42 +0200 Subject: [PATCH 103/259] Implemented addValue for SettingsList --- .../com/sap/sse/common/settings/generic/SettingsList.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsList.java b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsList.java index 68d367db16f..6933b8ea0e2 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsList.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/settings/generic/SettingsList.java @@ -86,6 +86,12 @@ public class SettingsList extends } } } + + public void addValue(T value) { + ValueCollectionValue> valueObject = ensureValue(); + this.values.add(value); + valueObject.addValue(value.getInnerValueObject()); + } @Override public int hashCode() { From 77d35c75c6450098f6b5b238b82f706411f4c925 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 5 Jul 2016 17:42:23 +0200 Subject: [PATCH 104/259] Adjusted SuggestBoxFilter hierarchy to enhance flexibility --- ...ctSuggestedMultiSelectionDataProvider.java | 10 ++-- .../filter/AbstractAsyncSuggestBoxFilter.java | 31 ++++++++++ .../filter/AbstractListSuggestBoxFilter.java | 37 ++++++++++++ .../filter/AbstractSuggestBoxFilter.java | 60 ++++++++----------- .../RacesByCompetitorTextBoxFilter.java | 2 +- 5 files changed, 100 insertions(+), 40 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractAsyncSuggestBoxFilter.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractListSuggestBoxFilter.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java index 13f6b30b4c6..b6b0e3a20e5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java @@ -47,7 +47,8 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider } @Override - public final void getSuggestionItems(String query, final SuggestionItemsCallback callback) { + public final void getSuggestionItems(Iterable queryTokens, int limit, + final SuggestionItemsCallback callback) { final SuggestionItemsCallback internalCallback = new SuggestionItemsCallback() { @Override public void setSuggestionItems(Collection suggestionItems) { @@ -61,10 +62,11 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider callback.setSuggestionItems(filteredSuggestionItems); } }; - this.getSuggestions(query, internalCallback); + this.getSuggestions(queryTokens, limit, internalCallback); } - - protected abstract void getSuggestions(String query, SuggestionItemsCallback callback); + + protected abstract void getSuggestions(Iterable queryTokens, int limit, + SuggestionItemsCallback callback); public boolean isNotificationsEnabled() { return notificationsEnabled; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractAsyncSuggestBoxFilter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractAsyncSuggestBoxFilter.java new file mode 100644 index 00000000000..9c60703beb7 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractAsyncSuggestBoxFilter.java @@ -0,0 +1,31 @@ +package com.sap.sailing.gwt.home.shared.partials.filter; + +import java.util.Collection; + +import com.sap.sse.common.filter.Filter; + +public abstract class AbstractAsyncSuggestBoxFilter extends AbstractSuggestBoxFilter { + + protected AbstractAsyncSuggestBoxFilter(String placeholderText) { + super(placeholderText); + } + + @Override + public final void setSelectableValues(Collection selectableValues) { + // Nothing to do here, because of external filtering + } + + @Override + protected final Iterable getMatchingStrings(C value) { + return null; // Not required here, because of external filtering + } + + @Override + protected final Filter getFilter(String searchString) { + return new Filter() { // Return an always matching filter, because of external filtering + @Override public boolean matches(T object) { return true; } + @Override public String getName() { return "alwaysMatchingFilter"; } + }; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractListSuggestBoxFilter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractListSuggestBoxFilter.java new file mode 100644 index 00000000000..05a3e986e0c --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractListSuggestBoxFilter.java @@ -0,0 +1,37 @@ +package com.sap.sailing.gwt.home.shared.partials.filter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.google.gwt.user.client.ui.SuggestOracle.Callback; +import com.google.gwt.user.client.ui.SuggestOracle.Request; +import com.sap.sse.common.filter.AbstractListFilter; + +public abstract class AbstractListSuggestBoxFilter extends AbstractSuggestBoxFilter { + + private final List suggestionObjectList = new ArrayList<>(); + protected final AbstractListFilter suggestionMatchingFilter = new AbstractListFilter() { + @Override + public Iterable getStrings(C value) { + return getMatchingStrings(value); + } + }; + + protected AbstractListSuggestBoxFilter(String placeholderText) { + super(placeholderText); + } + + @Override + protected void getSuggestions(Request request, Callback callback, Iterable queryTokens) { + Iterable filteredList = suggestionMatchingFilter.applyFilter(queryTokens, suggestionObjectList); + this.setSuggestions(request, callback, filteredList, queryTokens); + } + + @Override + public void setSelectableValues(Collection selectableValues) { + suggestionObjectList.clear(); + suggestionObjectList.addAll(selectableValues); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java index bb9467b2907..b7a0748ee39 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/AbstractSuggestBoxFilter.java @@ -14,21 +14,16 @@ import com.google.gwt.user.client.ui.SuggestBox; import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay; import com.google.gwt.user.client.ui.SuggestBox.SuggestionCallback; import com.google.gwt.user.client.ui.SuggestOracle; +import com.google.gwt.user.client.ui.SuggestOracle.Callback; +import com.google.gwt.user.client.ui.SuggestOracle.Request; +import com.google.gwt.user.client.ui.SuggestOracle.Response; import com.google.gwt.user.client.ui.SuggestOracle.Suggestion; import com.google.gwt.user.client.ui.TextBox; import com.sap.sse.common.Util; -import com.sap.sse.common.filter.AbstractListFilter; public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFilter { private final ContainsSuggestOracle suggestOracle = new ContainsSuggestOracle(); - private final List suggestionObjectList = new ArrayList<>(); - protected final AbstractListFilter suggestionMatchingFilter = new AbstractListFilter() { - @Override - public Iterable getStrings(C value) { - return getMatchingStrings(value); - } - }; protected AbstractSuggestBoxFilter(String placeholderText) { final SuggestBox suggestBox = new SuggestBox(suggestOracle, new TextBox(), new CustomSuggestionDisplay()); @@ -44,12 +39,27 @@ public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFi }); } - @Override - public void setSelectableValues(Collection selectableValues) { - suggestionObjectList.clear(); - suggestionObjectList.addAll(selectableValues); + protected final void setSuggestions(Request request, Callback callback, Iterable suggestionObjects, + Iterable queryTokens) { + List suggestions = new ArrayList<>(); + List normalizedQueryTokens = new ArrayList<>(); + for (String token : queryTokens) { + normalizedQueryTokens.add(token.toLowerCase()); + } + int count = 0; + for (C match : suggestionObjects) { + suggestions.add(new SimpleSuggestion(match, normalizedQueryTokens)); + if (++count >= request.getLimit()) { + break; + } + } + Response response = new Response(suggestions); + response.setMoreSuggestionsCount(Util.size(suggestionObjects) - count); + callback.onSuggestionsReady(request, response); } + protected abstract void getSuggestions(Request request, Callback callback, Iterable queryTokens); + protected abstract void onSuggestionSelected(C selectedItem); protected abstract String createSuggestionKeyString(C value); @@ -71,7 +81,7 @@ public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFi @Override public void requestDefaultSuggestions(Request request, Callback callback) { - setSuggestions(request, callback, suggestionObjectList, Collections.emptyList()); + getSuggestions(request, callback, Collections.emptyList()); } @Override @@ -81,33 +91,13 @@ public abstract class AbstractSuggestBoxFilter extends AbstractTextInputFi requestDefaultSuggestions(request, callback); } else { Iterable queryTokens = Collections.singleton(normalizedQuery); - Iterable filteredList = suggestionMatchingFilter.applyFilter(queryTokens, suggestionObjectList); - setSuggestions(request, callback, filteredList, queryTokens); + getSuggestions(request, callback, queryTokens); } } - private void setSuggestions(Request request, Callback callback, Iterable suggestionObjects, - Iterable queryTokens) { - List suggestions = new ArrayList<>(); - List normalizedQueryTokens = new ArrayList<>(); - for (String token : queryTokens) { - normalizedQueryTokens.add(token.toLowerCase()); - } - int count = 0; - for (C match : suggestionObjects) { - suggestions.add(new SimpleSuggestion(match, normalizedQueryTokens)); - if (++count >= request.getLimit()) { - break; - } - } - Response response = new Response(suggestions); - response.setMoreSuggestionsCount(Util.size(suggestionObjects) - count); - callback.onSuggestionsReady(request, response); - } - @Override public boolean isDisplayStringHTML() { - return true; + return true; } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java index 4280e233e66..fae3a0e0c02 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/filter/RacesByCompetitorTextBoxFilter.java @@ -10,7 +10,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.common.Util; import com.sap.sse.common.filter.Filter; -public class RacesByCompetitorTextBoxFilter extends AbstractSuggestBoxFilter { +public class RacesByCompetitorTextBoxFilter extends AbstractListSuggestBoxFilter { private final RacesByCompetitorFilter filter = new RacesByCompetitorFilter(); From 928fd004859f5d4ca39ba1f8de477b3a3cc23a20 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 5 Jul 2016 17:46:25 +0200 Subject: [PATCH 105/259] Adjusted user preferences competitor/boatclass loading --- .../GetCompetitorSuggestionAction.java | 17 ++-- .../UserProfilePreferencesPresenter.java | 91 ++++++++++++------- .../selection/SuggestedMultiSelection.java | 44 ++++----- .../SuggestedMultiSelectionDataProvider.java | 2 +- ...ggestedMultiSelectionListDataProvider.java | 27 ------ 5 files changed, 82 insertions(+), 99 deletions(-) delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java index a3e0ea80711..ae8c9889a98 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java @@ -3,8 +3,6 @@ package com.sap.sailing.gwt.home.communication.user.profile; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.Set; import com.google.gwt.core.shared.GwtIncompatible; import com.sap.sailing.domain.base.Boat; @@ -18,7 +16,7 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; /** * {@link SailingAction} implementation to load competitor data to be shown in a suggestion box depending on the - * {@link #GetCompetitorSuggestionAction(String, int) given query string}, where the amount of loaded entries can be + * {@link #GetCompetitorSuggestionAction(String, int) given query tokens}, where the amount of loaded entries can be * limited. * * The given query string is matched against the competitor's {@link Competitor#getName() name} and @@ -26,7 +24,7 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; */ public class GetCompetitorSuggestionAction implements SailingAction { - private String query; + private ArrayList queryTokens; private int limit; @GwtIncompatible @@ -46,13 +44,13 @@ public class GetCompetitorSuggestionAction implements SailingAction queryTokens, int limit) { + this.queryTokens = (ArrayList) Util.addAll(queryTokens, new ArrayList()); this.limit = limit; } @@ -67,8 +65,7 @@ public class GetCompetitorSuggestionAction implements SailingAction getFilteredCompetitors(SailingDispatchContext ctx) { Iterable allCompetitors = ctx.getRacingEventService().getCompetitorStore().getCompetitors(); - Set normalizedQuery = Collections.singleton(query.trim()); - return competitorFilter.applyFilter(normalizedQuery, Util.addAll(allCompetitors, new ArrayList())); + return competitorFilter.applyFilter(queryTokens, Util.addAll(allCompetitors, new ArrayList())); } @GwtIncompatible diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 2b8029afaab..4ad4569a4c3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -1,6 +1,7 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; import java.util.Arrays; +import java.util.List; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; @@ -12,7 +13,8 @@ import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggesti import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionListDataProvider; +import com.sap.sse.common.Util; +import com.sap.sse.common.filter.AbstractListFilter; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; public class UserProfilePreferencesPresenter implements UserProfilePreferencesView.Presenter { @@ -41,42 +43,65 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi @Override public SuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider() { - SuggestedMultiSelectionListDataProvider dataProvider = - new SuggestedMultiSelectionListDataProvider<>(new ProvidesKey() { - @Override - public Object getKey(BoatClassMasterdata item) { - return item.getDisplayName(); - } - }); - dataProvider.setSuggestionItems(Arrays.asList(BoatClassMasterdata.values())); - return dataProvider; + return new BoatClassSuggestedMultiSelectionDataProvider(); } @Override public SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider() { - return new AbstractSuggestedMultiSelectionDataProvider(new ProvidesKey() { - @Override - public Object getKey(SimpleCompetitorDTO item) { - return item.getSailID(); - } - }) { - - @Override - protected void getSuggestions(String query, final SuggestionItemsCallback callback) { - userProfilePresenter.getDispatch().execute(new GetCompetitorSuggestionAction(query, 20), - new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - Window.alert("Error while loading competitor suggestion"); - } - - @Override - public void onSuccess(CompetitorSuggestionResult result) { - callback.setSuggestionItems(result.getValues()); - } - }); - } - }; + return new CompetitorSuggestedMultiSelectionDataProvider(); } + private class BoatClassSuggestedMultiSelectionDataProvider + extends AbstractSuggestedMultiSelectionDataProvider { + private final AbstractListFilter filter = new AbstractListFilter() { + @Override + public Iterable getStrings(BoatClassMasterdata item) { + return item.getBoatClassNames(); + } + }; + + private BoatClassSuggestedMultiSelectionDataProvider() { + super(new ProvidesKey() { + @Override + public Object getKey(BoatClassMasterdata item) { + return item.getDisplayName(); + } + }); + } + @Override + protected void getSuggestions(Iterable queryTokens, int limit, + SuggestionItemsCallback callback) { + List boatClasses = Arrays.asList(BoatClassMasterdata.values()); + callback.setSuggestionItems(Util.asList(filter.applyFilter(queryTokens, boatClasses))); + } + } + + private class CompetitorSuggestedMultiSelectionDataProvider + extends AbstractSuggestedMultiSelectionDataProvider { + private CompetitorSuggestedMultiSelectionDataProvider() { + super(new ProvidesKey() { + @Override + public Object getKey(SimpleCompetitorDTO item) { + return item.getSailID(); + } + }); + } + + @Override + protected void getSuggestions(Iterable queryTokens, int limit, + final SuggestionItemsCallback callback) { + userProfilePresenter.getDispatch().execute(new GetCompetitorSuggestionAction(queryTokens, limit), + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Window.alert("Error while loading competitor suggestion"); + } + + @Override + public void onSuccess(CompetitorSuggestionResult result) { + callback.setSuggestionItems(result.getValues()); + } + }); + } + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index f6b4e0b0296..1c3df2d4c77 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -1,6 +1,5 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; -import java.util.Arrays; import java.util.Collection; import com.google.gwt.core.client.GWT; @@ -14,14 +13,16 @@ import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.IsWidget; +import com.google.gwt.user.client.ui.SuggestOracle.Callback; +import com.google.gwt.user.client.ui.SuggestOracle.Request; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.SuggestionItemsCallback; +import com.sap.sailing.gwt.home.shared.partials.filter.AbstractAsyncSuggestBoxFilter; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractFilterWidget; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sse.common.filter.Filter; public final class SuggestedMultiSelection extends Composite { @@ -98,8 +99,8 @@ public final class SuggestedMultiSelection extends Composite { removeAllButtonUi.setEnabled(itemContainerUi.getWidgetCount() > 0); } - private static abstract class AbstractSuggestedMultiSelectionFilter extends AbstractSuggestBoxFilter { - protected final SuggestedMultiSelectionDataProvider dataProvider; + private static abstract class AbstractSuggestedMultiSelectionFilter extends AbstractAsyncSuggestBoxFilter { + private final SuggestedMultiSelectionDataProvider dataProvider; private final SelectionCallback selectionCallback; protected AbstractSuggestedMultiSelectionFilter(SuggestedMultiSelectionDataProvider dataProvider, @@ -109,6 +110,17 @@ public final class SuggestedMultiSelection extends Composite { this.selectionCallback = selectionCallback; } + @Override + protected void getSuggestions(final Request request, final Callback callback, + final Iterable queryTokens) { + dataProvider.getSuggestionItems(queryTokens, request.getLimit(), new SuggestionItemsCallback() { + @Override + public void setSuggestionItems(Collection suggestionItems) { + setSuggestions(request, callback, suggestionItems, queryTokens); + } + }); + } + @Override protected final String createSuggestionKeyString(T value) { return String.valueOf(dataProvider.getKey(value)); @@ -119,20 +131,6 @@ public final class SuggestedMultiSelection extends Composite { AbstractSuggestedMultiSelectionFilter.this.clear(); selectionCallback.onSuggestionSelected(selectedItem); } - - @Override - protected final Filter getFilter(String searchString) { - dataProvider.getSuggestionItems(searchString, new SuggestionItemsCallback() { - @Override - public void setSuggestionItems(Collection suggestionItems) { - AbstractSuggestedMultiSelectionFilter.this.setSelectableValues(suggestionItems); - } - }); - return new Filter() { - @Override public boolean matches(T object) { return true; } - @Override public String getName() { return "alwaysMatchingFilter"; } - }; - } } private interface SelectionCallback { @@ -161,11 +159,6 @@ public final class SuggestedMultiSelection extends Composite { protected String createSuggestionAdditionalDisplayString(SimpleCompetitorDTO value) { return value.getName(); } - - @Override - protected Iterable getMatchingStrings(SimpleCompetitorDTO value) { - return Arrays.asList(value.getSailID(), value.getName()); - } }; } }, headerTitle); @@ -188,11 +181,6 @@ public final class SuggestedMultiSelection extends Composite { protected String createSuggestionAdditionalDisplayString(BoatClassMasterdata value) { return null; } - - @Override - protected Iterable getMatchingStrings(BoatClassMasterdata value) { - return value.getBoatClassNames(); - } }; } }, headerTitle); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java index ff7373da51a..884423fed84 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java @@ -14,7 +14,7 @@ public interface SuggestedMultiSelectionDataProvider extends ProvidesKey { void setNotifications(boolean enabled); - void getSuggestionItems(String query, final SuggestionItemsCallback callback); + void getSuggestionItems(Iterable queryTokens, int limit, final SuggestionItemsCallback callback); interface SuggestionItemsCallback { void setSuggestionItems(Collection suggestionItems); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java deleted file mode 100644 index 2716d42b113..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionListDataProvider.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.google.gwt.view.client.ProvidesKey; - -public class SuggestedMultiSelectionListDataProvider extends AbstractSuggestedMultiSelectionDataProvider { - - private final List suggestionItemsList = new ArrayList(); - - public SuggestedMultiSelectionListDataProvider(ProvidesKey keyProvider) { - super(keyProvider); - } - - public void setSuggestionItems(Collection suggestionItems) { - suggestionItemsList.clear(); - suggestionItemsList.addAll(suggestionItems); - } - - @Override - protected void getSuggestions(String query, SuggestionItemsCallback callback) { - callback.setSuggestionItems(suggestionItemsList); - } - -} From bc81c1c35d7d3a9327c8c9ae3047b7717d8080ea Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 17:47:09 +0200 Subject: [PATCH 106/259] Added initial tests for preference object handling and conversion in UserStore --- .../UserPreferenceObjectAndConverterTest.java | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java new file mode 100644 index 00000000000..ef15aedccf7 --- /dev/null +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java @@ -0,0 +1,172 @@ +package com.sap.sse.security.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.UnknownHostException; +import java.util.Base64; + +import org.junit.Before; +import org.junit.Test; + +import com.mongodb.DB; +import com.mongodb.MongoException; +import com.sap.sse.mongodb.MongoDBConfiguration; +import com.sap.sse.mongodb.MongoDBService; +import com.sap.sse.security.PreferenceConverter; +import com.sap.sse.security.userstore.mongodb.UserStoreImpl; +import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; + +import junit.framework.Assert; + +public class UserPreferenceObjectAndConverterTest { + + private UserStoreImpl store; + + private String user1 = "me"; + private String user2 = "somebody_else"; + + private JavaIoSerializablePreferenceConverter prefConverter = new JavaIoSerializablePreferenceConverter<>(); + private String prefKey1 = "prefKey1"; + private SimplePreferenceForSerialization pref1 = new SimplePreferenceForSerialization("test12345", false, 432.567); + private String serializedPref1 = prefConverter.toString(pref1); + private String prefKey2 = "prefKey2"; + private SimplePreferenceForSerialization pref2 = new SimplePreferenceForSerialization("some sailing value", true, 9.87654321); + private String serializedPref2 = prefConverter.toString(pref2); + + @Before + public void setUp() throws UnknownHostException, MongoException { + final MongoDBConfiguration dbConfiguration = MongoDBConfiguration.getDefaultTestConfiguration(); + final MongoDBService service = dbConfiguration.getService(); + DB db = service.getDB(); + db.getCollection(CollectionNames.USERS.name()).drop(); + db.getCollection(CollectionNames.SETTINGS.name()).drop(); + db.getCollection(CollectionNames.PREFERENCES.name()).drop(); + db.getCollection(CollectionNames.PREFERENCES.name()).drop(); + store = new UserStoreImpl(); + } + + @Test + public void noConverterSetTest() { + store.setPreference(user1, prefKey1, serializedPref1); + Assert.assertNull(store.getPreferenceObject(user1, prefKey1)); + } + + @Test + public void converterAlreadyRegisteredWhenSettingPreferenceTest() { + store.registerPreferenceConverter(prefKey1, prefConverter); + store.setPreference(user1, prefKey1, serializedPref1); + Assert.assertEquals(pref1, store.getPreferenceObject(user1, prefKey1)); + } + + @Test + public void converterSetWhenPreferenceAlreadyRegisteredTest() { + store.setPreference(user1, prefKey1, serializedPref1); + store.registerPreferenceConverter(prefKey1, prefConverter); + Assert.assertEquals(pref1, store.getPreferenceObject(user1, prefKey1)); + } + + @Test + public void preferencesForTwoUsersTest() { + store.setPreference(user1, prefKey1, serializedPref1); + store.setPreference(user2, prefKey1, serializedPref2); + store.registerPreferenceConverter(prefKey1, prefConverter); + Assert.assertEquals(pref1, store.getPreferenceObject(user1, prefKey1)); + Assert.assertEquals(pref2, store.getPreferenceObject(user2, prefKey1)); + } + + @Test + public void twoPreferencesForOneUserTest() { + store.setPreference(user1, prefKey1, serializedPref1); + store.setPreference(user1, prefKey2, serializedPref2); + store.registerPreferenceConverter(prefKey1, prefConverter); + store.registerPreferenceConverter(prefKey2, prefConverter); + Assert.assertEquals(pref1, store.getPreferenceObject(user1, prefKey1)); + Assert.assertEquals(pref2, store.getPreferenceObject(user1, prefKey2)); + } + + @Test + public void setPreferenceObjectTest() { + store.registerPreferenceConverter(prefKey1, prefConverter); + store.setPreferenceObject(user1, prefKey1, pref1); + Assert.assertEquals(serializedPref1, store.getPreference(user1, prefKey1)); + Assert.assertEquals(pref1, store.getPreferenceObject(user1, prefKey1)); + } + + public static class SimplePreferenceForSerialization implements Serializable { + private static final long serialVersionUID = -580569932709860895L; + + private String someString; + private boolean someBoolean; + private double soumeDouble; + + public SimplePreferenceForSerialization(String someString, boolean someBoolean, double soumeDouble) { + super(); + this.someString = someString; + this.someBoolean = someBoolean; + this.soumeDouble = soumeDouble; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (someBoolean ? 1231 : 1237); + result = prime * result + ((someString == null) ? 0 : someString.hashCode()); + long temp; + temp = Double.doubleToLongBits(soumeDouble); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SimplePreferenceForSerialization other = (SimplePreferenceForSerialization) obj; + if (someBoolean != other.someBoolean) + return false; + if (someString == null) { + if (other.someString != null) + return false; + } else if (!someString.equals(other.someString)) + return false; + if (Double.doubleToLongBits(soumeDouble) != Double.doubleToLongBits(other.soumeDouble)) + return false; + return true; + } + } + + + public static class JavaIoSerializablePreferenceConverter implements PreferenceConverter { + @Override + public String toString(T preference) { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(stream); + oos.writeObject(preference); + oos.flush(); + return Base64.getEncoder().encodeToString(stream.toByteArray()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @SuppressWarnings("unchecked") + @Override + public T toPreference(String stringPreference) { + try { + return (T) new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(stringPreference))).readObject(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } +} From 55ed9c93a129c3add056eb86170cb6d05761f44d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 17:56:37 +0200 Subject: [PATCH 107/259] Added missing GWT module inherits because UserService was extended to used additional stuff from com.sap.sse.gwt --- .../main/resources/com/sap/sse/security/ui/EditProfile.gwt.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EditProfile.gwt.xml b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EditProfile.gwt.xml index 8b8b2e0929f..bfedaf891e1 100755 --- a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EditProfile.gwt.xml +++ b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EditProfile.gwt.xml @@ -14,6 +14,7 @@ --> + From 0f93d35bcf6b0dbfc115ffaf26654ef80a8a8972 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 18:28:31 +0200 Subject: [PATCH 108/259] Added initial tests for PreferenceObjectBasedNotificationSet --- ...JavaIoSerializablePreferenceConverter.java | 36 +++++ ...ferenceObjectBasedNotificationSetTest.java | 136 ++++++++++++++++++ .../UserPreferenceObjectAndConverterTest.java | 33 ----- .../PreferenceObjectBasedNotificationSet.java | 4 +- 4 files changed, 174 insertions(+), 35 deletions(-) create mode 100644 java/com.sap.sse.security.test/src/com/sap/sse/security/test/JavaIoSerializablePreferenceConverter.java create mode 100644 java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/JavaIoSerializablePreferenceConverter.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/JavaIoSerializablePreferenceConverter.java new file mode 100644 index 00000000000..f8dad9f5246 --- /dev/null +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/JavaIoSerializablePreferenceConverter.java @@ -0,0 +1,36 @@ +package com.sap.sse.security.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Base64; + +import com.sap.sse.security.PreferenceConverter; + +public class JavaIoSerializablePreferenceConverter implements PreferenceConverter { + @Override + public String toString(T preference) { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(stream); + oos.writeObject(preference); + oos.flush(); + return Base64.getEncoder().encodeToString(stream.toByteArray()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @SuppressWarnings("unchecked") + @Override + public T toPreference(String stringPreference) { + try { + return (T) new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(stringPreference))) + .readObject(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} \ No newline at end of file diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java new file mode 100644 index 00000000000..897b86767f9 --- /dev/null +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -0,0 +1,136 @@ +package com.sap.sse.security.test; + +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; + +import org.junit.Before; +import org.junit.Test; + +import com.mongodb.DB; +import com.mongodb.MongoException; +import com.sap.sse.common.Util; +import com.sap.sse.mongodb.MongoDBConfiguration; +import com.sap.sse.mongodb.MongoDBService; +import com.sap.sse.security.PreferenceObjectBasedNotificationSet; +import com.sap.sse.security.UserStore; +import com.sap.sse.security.userstore.mongodb.UserStoreImpl; +import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; + +import junit.framework.Assert; + +public class PreferenceObjectBasedNotificationSetTest { + + private static final String A = "a"; + private static final String B = "b"; + private static final String C = "c"; + + private UserStoreImpl store; + + private String user1 = "me"; + private String user2 = "somebody_else"; + + private JavaIoSerializablePreferenceConverter> prefConverter = new JavaIoSerializablePreferenceConverter<>(); + private String prefKey = "prefKey"; + private String otherPrefKey = "otherPrefKey"; + private HashSet values1 = values(A, B); + private HashSet values2 = values(B, C); + + @Before + public void setUp() throws UnknownHostException, MongoException { + final MongoDBConfiguration dbConfiguration = MongoDBConfiguration.getDefaultTestConfiguration(); + final MongoDBService service = dbConfiguration.getService(); + DB db = service.getDB(); + db.getCollection(CollectionNames.USERS.name()).drop(); + db.getCollection(CollectionNames.SETTINGS.name()).drop(); + db.getCollection(CollectionNames.PREFERENCES.name()).drop(); + db.getCollection(CollectionNames.PREFERENCES.name()).drop(); + store = new UserStoreImpl(); + } + + @Test + public void noPreferenceAvailableTest() { + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + Assert.assertTrue(Util.isEmpty(notificationSet.getUsersnamesToNotifyFor(prefKey))); + } + + @Test + public void preferenceAllreadySetTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); + } + + @Test + public void preferenceSetAfterNotificationSetCreationTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + store.setPreferenceObject(user1, prefKey, values1); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); + } + + @Test + public void preferenceSetForTwoUsersTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + store.setPreferenceObject(user2, prefKey, values2); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values(user1, user2))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values(user2))); + } + + @Test + public void preferenceUpdateTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + store.setPreferenceObject(user1, prefKey, values2); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values(user1))); + } + + @Test + public void testForObjectThatIsntKnownTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor("x"), values())); + } + + @Test + public void otherPrefDoesntInfluenceCalculationTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.registerPreferenceConverter(otherPrefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + store.setPreferenceObject(user1, otherPrefKey, values2); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values(user1))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); + } + + private static HashSet values(String... values) { + return new HashSet<>(Arrays.asList(values)); + } + + private static class PreferenceObjectBasedNotificationSetImpl extends PreferenceObjectBasedNotificationSet, String> { + + public PreferenceObjectBasedNotificationSetImpl(String key, UserStore store) { + super(key, store); + } + + @Override + protected Collection calculateObjectsToNotify(HashSet preference) { + return preference; + } + + } +} diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java index ef15aedccf7..5ea736fe73a 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java @@ -1,13 +1,7 @@ package com.sap.sse.security.test; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.Serializable; import java.net.UnknownHostException; -import java.util.Base64; import org.junit.Before; import org.junit.Test; @@ -16,7 +10,6 @@ import com.mongodb.DB; import com.mongodb.MongoException; import com.sap.sse.mongodb.MongoDBConfiguration; import com.sap.sse.mongodb.MongoDBService; -import com.sap.sse.security.PreferenceConverter; import com.sap.sse.security.userstore.mongodb.UserStoreImpl; import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; @@ -143,30 +136,4 @@ public class UserPreferenceObjectAndConverterTest { return true; } } - - - public static class JavaIoSerializablePreferenceConverter implements PreferenceConverter { - @Override - public String toString(T preference) { - try { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(stream); - oos.writeObject(preference); - oos.flush(); - return Base64.getEncoder().encodeToString(stream.toByteArray()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - @SuppressWarnings("unchecked") - @Override - public T toPreference(String stringPreference) { - try { - return (T) new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(stringPreference))).readObject(); - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - } } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 8e553145c79..a86844772c9 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -42,7 +42,7 @@ public abstract class PreferenceObjectBasedNotificationSet { protected abstract Collection calculateObjectsToNotify(PrefT preference); - private Iterable getUsersToNotifyFor(T object) { + public Iterable getUsersnamesToNotifyFor(T object) { // TODO use read lock synchronized (notifications) { return new HashSet<>(Util.get(notifications, object, Collections.emptySet())); @@ -53,7 +53,7 @@ public abstract class PreferenceObjectBasedNotificationSet { * The given consumer will be called for every user that needs to be notified about the given object. */ public void forUsersMappedTo(T object, Consumer consumer) { - for (String username : getUsersToNotifyFor(object)) { + for (String username : getUsersnamesToNotifyFor(object)) { // User objects can change silently. So we just keep the usernames and get the associated user objects on // the fly. User user = store.getUserByName(username); From ee5eda7ff0ad61227c0f6df311e49649c4ab82ca Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 5 Jul 2016 18:47:48 +0200 Subject: [PATCH 109/259] More tests for preference object handling and notification set calculation --- ...ferenceObjectBasedNotificationSetTest.java | 36 +++++++++++++++++++ .../UserPreferenceObjectAndConverterTest.java | 16 +++++++++ 2 files changed, 52 insertions(+) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 897b86767f9..6dc25fbbcc1 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -36,6 +36,7 @@ public class PreferenceObjectBasedNotificationSetTest { private String otherPrefKey = "otherPrefKey"; private HashSet values1 = values(A, B); private HashSet values2 = values(B, C); + private HashSet allValues = values(A, B, C); @Before public void setUp() throws UnknownHostException, MongoException { @@ -97,6 +98,41 @@ public class PreferenceObjectBasedNotificationSetTest { Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values(user1))); } + @Test + public void preferenceUpdateDoesntInfluenceOtherUserTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + store.setPreferenceObject(user2, prefKey, allValues); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + store.setPreferenceObject(user1, prefKey, values2); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values(user2))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values(user1, user2))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values(user1, user2))); + } + + @Test + public void preferenceUnsetDoesntInfluenceOtherUserTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + store.setPreferenceObject(user2, prefKey, values2); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + store.unsetPreference(user1, prefKey); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values(user2))); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values(user2))); + } + + @Test + public void preferenceUnsetTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + store.setPreferenceObject(user1, prefKey, values1); + store.unsetPreference(user1, prefKey); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); + } + @Test public void testForObjectThatIsntKnownTest() { store.registerPreferenceConverter(prefKey, prefConverter); diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java index 5ea736fe73a..817fb76f20d 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java @@ -88,6 +88,22 @@ public class UserPreferenceObjectAndConverterTest { Assert.assertEquals(serializedPref1, store.getPreference(user1, prefKey1)); Assert.assertEquals(pref1, store.getPreferenceObject(user1, prefKey1)); } + + @Test + public void unsetPreferenceTest() { + store.registerPreferenceConverter(prefKey1, prefConverter); + store.setPreferenceObject(user1, prefKey1, pref1); + store.unsetPreference(user1, prefKey1); + Assert.assertEquals(null, store.getPreferenceObject(user1, prefKey1)); + } + + @Test + public void setPreferenceObjectToNullTest() { + store.registerPreferenceConverter(prefKey1, prefConverter); + store.setPreferenceObject(user1, prefKey1, pref1); + store.setPreferenceObject(user1, prefKey1, null); + Assert.assertEquals(null, store.getPreferenceObject(user1, prefKey1)); + } public static class SimplePreferenceForSerialization implements Serializable { private static final long serialVersionUID = -580569932709860895L; From 1b641011404f746d426d2f86d55cad454a4138ad Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 09:06:09 +0200 Subject: [PATCH 110/259] Added more tests for PreferenceObjectBasedNotificationSet --- ...ferenceObjectBasedNotificationSetTest.java | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 6dc25fbbcc1..9a74a1c896d 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -4,6 +4,7 @@ import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.function.Consumer; import org.junit.Before; import org.junit.Test; @@ -14,7 +15,9 @@ import com.sap.sse.common.Util; import com.sap.sse.mongodb.MongoDBConfiguration; import com.sap.sse.mongodb.MongoDBService; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; +import com.sap.sse.security.User; import com.sap.sse.security.UserStore; +import com.sap.sse.security.shared.UserManagementException; import com.sap.sse.security.userstore.mongodb.UserStoreImpl; import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; @@ -30,6 +33,7 @@ public class PreferenceObjectBasedNotificationSetTest { private String user1 = "me"; private String user2 = "somebody_else"; + private String mail = "anonymous@sapsailing.com"; private JavaIoSerializablePreferenceConverter> prefConverter = new JavaIoSerializablePreferenceConverter<>(); private String prefKey = "prefKey"; @@ -153,10 +157,69 @@ public class PreferenceObjectBasedNotificationSetTest { Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); } + @Test + public void noUserMappingTest() { + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + + UserConsumerMock mock = new UserConsumerMock(); + notificationSet.forUsersMappedTo(A, mock); + Assert.assertEquals(0, mock.calls.size()); + } + + @Test + public void userMappingTest() throws UserManagementException { + store.createUser(user1, mail); + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + + UserConsumerMock mock = new UserConsumerMock(); + + notificationSet.forUsersMappedTo(A, mock); + Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); + } + + @Test + public void userMappingWithTwoUsersTest() throws UserManagementException { + store.createUser(user1, mail); + store.createUser(user2, mail); + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + store.setPreferenceObject(user2, prefKey, values2); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + + UserConsumerMock mock = new UserConsumerMock(); + notificationSet.forUsersMappedTo(A, mock); + Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); + + mock = new UserConsumerMock(); + notificationSet.forUsersMappedTo(B, mock); + Assert.assertTrue(Util.equals(users(store.getUserByName(user1), store.getUserByName(user2)), mock.calls)); + } + + @Test + public void userMappingWithOneExistingAndOneUnknownUserTest() throws UserManagementException { + store.createUser(user1, mail); + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + store.setPreferenceObject(user2, prefKey, values2); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + + UserConsumerMock mock = new UserConsumerMock(); + notificationSet.forUsersMappedTo(B, mock); + Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); + } + private static HashSet values(String... values) { return new HashSet<>(Arrays.asList(values)); } + private static HashSet users(User... values) { + return new HashSet<>(Arrays.asList(values)); + } + private static class PreferenceObjectBasedNotificationSetImpl extends PreferenceObjectBasedNotificationSet, String> { public PreferenceObjectBasedNotificationSetImpl(String key, UserStore store) { @@ -167,6 +230,17 @@ public class PreferenceObjectBasedNotificationSetTest { protected Collection calculateObjectsToNotify(HashSet preference) { return preference; } - + } + + private static class UserConsumerMock implements Consumer { + HashSet calls = new HashSet<>(); + + @Override + public void accept(User user) { + if(user == null) { + throw new IllegalArgumentException("User is null"); + } + calls.add(user); + } } } From e5d38e7455bc0f4c8a394f88415d47c3c7b5b4ea Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 09:16:08 +0200 Subject: [PATCH 111/259] Added JavaDocs to PreferenceConverter --- .../src/com/sap/sse/security/PreferenceConverter.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java index 90a5b144db2..d4b26b7e79d 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java @@ -1,5 +1,11 @@ package com.sap.sse.security; +/** + * Converter to be used by {@link UserStore} to convert preference objects to/from Strings. + * @see UserStore#registerPreferenceConverter(String, PreferenceConverter) + * + * @param The type of preference object, this converter handles. + */ public interface PreferenceConverter { String toString(PREF preference); From 7ea2df0e53c6a9c2590ce245fa597e63a2495c6e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 09:21:43 +0200 Subject: [PATCH 112/259] Added missing GWT module inherits because UserService was extended to used additional stuff from com.sap.sse.gwt --- .../resources/com/sap/sse/security/ui/EmailValidation.gwt.xml | 1 + .../main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml | 1 + .../main/resources/com/sap/sse/security/ui/OAuthLogin.gwt.xml | 1 + .../resources/com/sap/sse/security/ui/UserManagement.gwt.xml | 1 + 4 files changed, 4 insertions(+) diff --git a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EmailValidation.gwt.xml b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EmailValidation.gwt.xml index a8cb13ad687..734eede5c40 100755 --- a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EmailValidation.gwt.xml +++ b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/EmailValidation.gwt.xml @@ -14,6 +14,7 @@ --> + diff --git a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml index 66f2dbca0ec..3d2df62e948 100644 --- a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml +++ b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/LoginPanel.gwt.xml @@ -13,6 +13,7 @@ --> + diff --git a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/OAuthLogin.gwt.xml b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/OAuthLogin.gwt.xml index 5f64a3b98f4..1560b67199e 100644 --- a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/OAuthLogin.gwt.xml +++ b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/OAuthLogin.gwt.xml @@ -16,6 +16,7 @@ --> + diff --git a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/UserManagement.gwt.xml b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/UserManagement.gwt.xml index 8cc1b6d694c..5ab0b6332b0 100644 --- a/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/UserManagement.gwt.xml +++ b/java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/UserManagement.gwt.xml @@ -11,6 +11,7 @@ --> + From 38733e750256dc075672fd6beda98184dc2d7b9a Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 09:45:09 +0200 Subject: [PATCH 113/259] Renamed methods to make more clear what they are used for --- .../sailing/server/impl/GenericJSONPreferenceConverter.java | 4 ++-- .../security/test/JavaIoSerializablePreferenceConverter.java | 4 ++-- .../src/com/sap/sse/security/PreferenceConverter.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java index 55f8cfd8320..383e61430c5 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/GenericJSONPreferenceConverter.java @@ -16,12 +16,12 @@ public class GenericJSONPreferenceConverter implements PreferenceConverter { @Override - public String toString(T preference) { + public String toPreferenceString(T preference) { try { ByteArrayOutputStream stream = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(stream); @@ -25,7 +25,7 @@ public class JavaIoSerializablePreferenceConverter implements PreferenceConve @SuppressWarnings("unchecked") @Override - public T toPreference(String stringPreference) { + public T toPreferenceObject(String stringPreference) { try { return (T) new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(stringPreference))) .readObject(); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java index d4b26b7e79d..7fb62123211 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java @@ -7,7 +7,7 @@ package com.sap.sse.security; * @param The type of preference object, this converter handles. */ public interface PreferenceConverter { - String toString(PREF preference); + String toPreferenceString(PREF preference); - PREF toPreference(String stringPreference); + PREF toPreferenceObject(String stringPreference); } From c80bca9c87060b63bf0c9c8ae87d961aad58f628 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 09:45:21 +0200 Subject: [PATCH 114/259] Renamed methods to make more clear what they are used for --- .../security/test/UserPreferenceObjectAndConverterTest.java | 4 ++-- .../com/sap/sse/security/userstore/mongodb/UserStoreImpl.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java index 817fb76f20d..0bf83a0560f 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java @@ -25,10 +25,10 @@ public class UserPreferenceObjectAndConverterTest { private JavaIoSerializablePreferenceConverter prefConverter = new JavaIoSerializablePreferenceConverter<>(); private String prefKey1 = "prefKey1"; private SimplePreferenceForSerialization pref1 = new SimplePreferenceForSerialization("test12345", false, 432.567); - private String serializedPref1 = prefConverter.toString(pref1); + private String serializedPref1 = prefConverter.toPreferenceString(pref1); private String prefKey2 = "prefKey2"; private SimplePreferenceForSerialization pref2 = new SimplePreferenceForSerialization("some sailing value", true, 9.87654321); - private String serializedPref2 = prefConverter.toString(pref2); + private String serializedPref2 = prefConverter.toPreferenceString(pref2); @Before public void setUp() throws UnknownHostException, MongoException { diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index f9f94bec1e4..6cfb672df8d 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -535,7 +535,7 @@ public class UserStoreImpl implements UserStore { final String preferenceString = getPreference(username, key); if (preferenceString != null) { try { - final Object convertedObject = preferenceConverter.toPreference(preferenceString); + final Object convertedObject = preferenceConverter.toPreferenceObject(preferenceString); setPreferenceObjectInternal(username, key, convertedObject); } catch (Throwable t) { logger.log(Level.SEVERE, "Error while converting preference for key " + key + " from String \"" @@ -594,7 +594,7 @@ public class UserStoreImpl implements UserStore { unsetPreference(username, key); } else { try { - String stringPreference = preferenceConverter.toString(preferenceObject); + String stringPreference = preferenceConverter.toPreferenceString(preferenceObject); setPreferenceInternal(username, key, stringPreference); setPreferenceObjectInternal(username, key, preferenceObject); } catch (Throwable t) { From 8059be9fb725c34a567851e295b582bfc62bb009 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 11:40:28 +0200 Subject: [PATCH 115/259] Implemented specific setting to handle BoatClassMasterdata --- .../BoatClassNotificationPreference.java | 14 ++--- .../common/preferences/BoatClassSetting.java | 58 +++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java index c0d21281ee1..43919f4e7ff 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java @@ -1,34 +1,34 @@ package com.sap.sailing.domain.common.preferences; +import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; import com.sap.sse.common.settings.generic.BooleanSetting; -import com.sap.sse.common.settings.generic.StringSetting; public class BoatClassNotificationPreference extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -6510535362114348707L; - private transient StringSetting boatClassName; + private transient BoatClassSetting boatClass; private transient BooleanSetting notifyAboutUpcomingRaces; private transient BooleanSetting notifyAboutResults; public BoatClassNotificationPreference() { } - public BoatClassNotificationPreference(String boatClassName, boolean notifyAboutRaces, boolean notifyAboutResults) { - this.boatClassName.setValue(boatClassName); + public BoatClassNotificationPreference(BoatClassMasterdata boatClass, boolean notifyAboutRaces, boolean notifyAboutResults) { + this.boatClass.setValue(boatClass); this.notifyAboutUpcomingRaces.setValue(notifyAboutRaces); this.notifyAboutResults.setValue(notifyAboutResults); } @Override protected void addChildSettings() { - boatClassName = new StringSetting("boatClassName", this); + boatClass = new BoatClassSetting("boatClass", this); notifyAboutUpcomingRaces = new BooleanSetting("notifyAboutUpcomingRaces", this, false); notifyAboutResults = new BooleanSetting("notifyAboutResults", this, false); } - public String getBoatClassName() { - return boatClassName.getValue(); + public BoatClassMasterdata getBoatClass() { + return boatClass.getValue(); } public boolean isNotifyAboutUpcomingRaces() { diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java new file mode 100644 index 00000000000..4967a995888 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java @@ -0,0 +1,58 @@ +package com.sap.sailing.domain.common.preferences; + +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.EnumSetting; +import com.sap.sse.common.settings.generic.ValueConverter; +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.value.StringValue; +import com.sap.sse.common.settings.value.Value; + +/** + * We could use {@link EnumSetting} but this woul lead to problems if a enum constant in {@link BoatClassMasterdata} is + * renamed. This Setting instead used the display name that is also used in the backend to store which boat class is + * meant. {@link BoatClassMasterdata} can resolve the enum values from the display named which also works with some + * alternative names so that we don'T rely on the exact display name but that the display name will at least be + * available as alternative name. + */ +public class BoatClassSetting extends AbstractValueSetting { + + protected BoatClassSetting(String name, AbstractGenericSerializableSettings settings) { + super(name, settings, null, Converter.INSTANCE); + } + + public static class Converter implements ValueConverter { + + public static final Converter INSTANCE = new Converter(); + + @Override + public Object toJSONValue(BoatClassMasterdata value) { + return value == null ? null : value.getDisplayName(); + } + + @Override + public BoatClassMasterdata fromJSONValue(Object jsonValue) { + return fromStringValue((String) jsonValue); + } + + @Override + public String toStringValue(BoatClassMasterdata value) { + return value == null ? null : value.getDisplayName(); + } + + @Override + public BoatClassMasterdata fromStringValue(String stringValue) { + return stringValue == null ? null : BoatClassMasterdata.resolveBoatClass(stringValue); + } + + @Override + public BoatClassMasterdata fromValue(Value value) { + return fromStringValue(((StringValue) value).getValue()); + } + + @Override + public Value toValue(BoatClassMasterdata value) { + return new StringValue(toStringValue(value)); + } + } +} From ed20afd4b8c90e64b8f81670a6b73d00b3a6b34a Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 6 Jul 2016 11:45:47 +0200 Subject: [PATCH 116/259] Adjusted access to clientFactory in UserProfileActivity --- .../user/profile/UserProfileActivity.java | 16 ++----------- .../places/user/profile/UserProfileView.java | 9 +------- .../UserProfileDetailsPresenter.java | 3 ++- .../UserProfilePreferencesPresenter.java | 23 ++++++++++--------- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java index 2211d9cd219..fb850c0e925 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileActivity.java @@ -8,7 +8,6 @@ import com.google.gwt.safehtml.shared.SafeUri; import com.google.gwt.safehtml.shared.UriUtils; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.sap.sailing.gwt.common.client.controls.tabbar.TabView; -import com.sap.sailing.gwt.home.communication.SailingDispatchSystem; import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator; import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper; import com.sap.sailing.gwt.home.shared.app.NavigationPathDisplay; @@ -18,9 +17,7 @@ import com.sap.sailing.gwt.home.shared.places.fakeseries.AbstractSeriesPlace; import com.sap.sailing.gwt.home.shared.places.start.StartPlace; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sse.security.ui.authentication.AuthenticationContextEvent; -import com.sap.sse.security.ui.authentication.AuthenticationManager; import com.sap.sse.security.ui.authentication.AuthenticationRequestEvent; -import com.sap.sse.security.ui.client.UserManagementServiceAsync; import com.sap.sse.security.ui.client.i18n.StringMessages; public class UserProfileActivity extends AbstractActivity implements UserProfileView.Presenter { @@ -98,8 +95,8 @@ public class UserProfileActivity extends AbstractActivity implements UserProfile } @Override - public AuthenticationManager getAuthenticationManager() { - return clientFactory.getAuthenticationManager(); + public UserProfileClientFactory getClientFactory() { + return clientFactory; } @Override @@ -108,13 +105,4 @@ public class UserProfileActivity extends AbstractActivity implements UserProfile .getMailVerifiedConfirmationNavigation().getTargetUrl(); } - @Override - public UserManagementServiceAsync getUserManagementService() { - return clientFactory.getUserManagementService(); - } - - @Override - public SailingDispatchSystem getDispatch() { - return clientFactory.getDispatch(); - } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java index 0bebcf4a340..86298d7e8dd 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/UserProfileView.java @@ -4,15 +4,12 @@ import com.google.gwt.place.shared.Place; import com.google.gwt.safehtml.shared.SafeUri; import com.google.gwt.user.client.ui.IsWidget; import com.sap.sailing.gwt.common.client.controls.tabbar.TabView; -import com.sap.sailing.gwt.home.communication.SailingDispatchSystem; import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; import com.sap.sailing.gwt.home.shared.places.fakeseries.AbstractSeriesPlace; import com.sap.sailing.gwt.home.shared.places.start.StartPlace; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; -import com.sap.sse.security.ui.authentication.AuthenticationManager; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; -import com.sap.sse.security.ui.client.UserManagementServiceAsync; public interface UserProfileView extends IsWidget, NeedsAuthenticationContext { @@ -25,11 +22,7 @@ public interface UserProfileView getHomeNavigation(); PlaceNavigation getUserProfileNavigation(); - AuthenticationManager getAuthenticationManager(); - - UserManagementServiceAsync getUserManagementService(); - SailingDispatchSystem getDispatch(); - + UserProfileClientFactory getClientFactory(); String getMailVerifiedUrl(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/detailstab/UserProfileDetailsPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/detailstab/UserProfileDetailsPresenter.java index 97ca4c126e7..cc5b7717c9b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/detailstab/UserProfileDetailsPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/detailstab/UserProfileDetailsPresenter.java @@ -15,7 +15,8 @@ public class UserProfileDetailsPresenter implements UserProfileDetailsView.Prese this.userProfilePresenter = userProfilePresenter; view.setPresenter(this); this.userDetailsPresenter = new UserDetailsPresenter(view.getUserDetailsView(), - userProfilePresenter.getAuthenticationManager(), userProfilePresenter.getUserManagementService(), + userProfilePresenter.getClientFactory().getAuthenticationManager(), + userProfilePresenter.getClientFactory().getUserManagementService(), userProfilePresenter.getMailVerifiedUrl()); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 4ad4569a4c3..61f0ba4a759 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -90,18 +90,19 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi @Override protected void getSuggestions(Iterable queryTokens, int limit, final SuggestionItemsCallback callback) { - userProfilePresenter.getDispatch().execute(new GetCompetitorSuggestionAction(queryTokens, limit), - new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - Window.alert("Error while loading competitor suggestion"); - } + userProfilePresenter.getClientFactory().getDispatch().execute( + new GetCompetitorSuggestionAction(queryTokens, limit), + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Window.alert("Error while loading competitor suggestion"); + } - @Override - public void onSuccess(CompetitorSuggestionResult result) { - callback.setSuggestionItems(result.getValues()); - } - }); + @Override + public void onSuccess(CompetitorSuggestionResult result) { + callback.setSuggestionItems(result.getValues()); + } + }); } } } From 2c62edcb8cb9d9f07d21b1e0929cffc5624ec413 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 6 Jul 2016 13:33:10 +0200 Subject: [PATCH 117/259] Fixed missing JSONObject in SettingsToJsonSerializerGWT --- .../com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java index b15e96b9cf6..eaa90ec1114 100755 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/settings/SettingsToJsonSerializerGWT.java @@ -52,6 +52,8 @@ public class SettingsToJsonSerializerGWT extends AbstractSettingsToJsonSerialize return JSONNull.getInstance(); } else if (value instanceof JSONArray) { return (JSONArray) value; + } else if (value instanceof JSONObject) { + return (JSONObject) value; } else if (value instanceof String) { return new JSONString((String) value); } else if (value instanceof Number) { From a7172666e9a2f854d0aa724ef0168853f57b2bc8 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 6 Jul 2016 13:39:12 +0200 Subject: [PATCH 118/259] Connected user preferences saving and loading to the backend logic --- .../event/SimpleCompetitorWithIdDTO.java | 45 +++++++++ .../profile/CompetitorSuggestionResult.java | 8 +- .../GetCompetitorSuggestionAction.java | 11 ++- .../user/profile/GetCompetitorsAction.java | 50 ++++++++++ .../UserProfilePreferencesPresenter.java | 98 +++++++++++++++++-- .../UserProfilePreferencesTabView.java | 1 + .../UserProfilePreferencesView.java | 10 +- .../UserProfilePreferencesViewImpl.java | 6 +- ...ctSuggestedMultiSelectionDataProvider.java | 8 +- .../selection/SuggestedMultiSelection.java | 33 ++++--- .../SuggestedMultiSelectionDataProvider.java | 2 + 11 files changed, 228 insertions(+), 44 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorWithIdDTO.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorsAction.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorWithIdDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorWithIdDTO.java new file mode 100644 index 00000000000..21860294e5e --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/event/SimpleCompetitorWithIdDTO.java @@ -0,0 +1,45 @@ +package com.sap.sailing.gwt.home.communication.event; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.common.dto.CompetitorDTO; + +public class SimpleCompetitorWithIdDTO extends SimpleCompetitorDTO { + + private static final long serialVersionUID = -1236159499763467614L; + + private String idAsString; + + protected SimpleCompetitorWithIdDTO() { + } + + @GwtIncompatible + public SimpleCompetitorWithIdDTO(Competitor competitor) { + super(competitor); + this.idAsString = competitor.getId().toString(); + } + + @GwtIncompatible + public SimpleCompetitorWithIdDTO(CompetitorDTO competitor) { + super(competitor); + this.idAsString = competitor.getIdAsString(); + } + + public SimpleCompetitorWithIdDTO(String idAsString, String name, String sailID, + String twoLetterIsoCountryCode, String flagImageURL) { + super(name, sailID, twoLetterIsoCountryCode, flagImageURL); + this.idAsString = idAsString; + } + + public String getIdAsString() { + return idAsString; + } + + @Override + public int compareTo(SimpleCompetitorDTO obj) { + int compareTo = super.compareTo(obj); + return (compareTo == 0 && obj instanceof SimpleCompetitorWithIdDTO) + ? this.idAsString.compareTo(((SimpleCompetitorWithIdDTO) obj).idAsString) : compareTo; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java index bc1caf9a7df..3d15aa2eda0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/CompetitorSuggestionResult.java @@ -2,22 +2,22 @@ package com.sap.sailing.gwt.home.communication.user.profile; import java.util.Collection; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; /** * {@link SortedSetResult} extension for suggested competitor search. This result contains a set of - * {@link SimpleCompetitorDTO competitor}s representing the suggestions, as well as information if there are more + * {@link SimpleCompetitorWithIdDTO competitor}s representing the suggestions, as well as information if there are more * suggestions possible. */ -public class CompetitorSuggestionResult extends SortedSetResult { +public class CompetitorSuggestionResult extends SortedSetResult { private int moreSuggestionsCount; protected CompetitorSuggestionResult() { } - public CompetitorSuggestionResult(Collection values, int moreSuggestionsCount) { + public CompetitorSuggestionResult(Collection values, int moreSuggestionsCount) { super(values); this.moreSuggestionsCount = moreSuggestionsCount; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java index ae8c9889a98..8b70fe591f4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorSuggestionAction.java @@ -9,7 +9,7 @@ import com.sap.sailing.domain.base.Boat; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.gwt.home.communication.SailingAction; import com.sap.sailing.gwt.home.communication.SailingDispatchContext; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sse.common.Util; import com.sap.sse.common.filter.AbstractListFilter; import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; @@ -58,7 +58,7 @@ public class GetCompetitorSuggestionAction implements SailingAction filteredCompetitors = getFilteredCompetitors(ctx); - Collection result = convertToSimpleCompetitorDTOs(filteredCompetitors); + Collection result = convertToSimpleCompetitorDTOs(filteredCompetitors); return new CompetitorSuggestionResult(result, Math.max(0, Util.size(filteredCompetitors) - limit)); } @@ -69,11 +69,12 @@ public class GetCompetitorSuggestionAction implements SailingAction convertToSimpleCompetitorDTOs(Iterable filteredCompetitors) { - Collection result = new ArrayList<>(); + private Collection convertToSimpleCompetitorDTOs( + Iterable filteredCompetitors) { + Collection result = new ArrayList<>(); int count = 0; for (Competitor competitor : filteredCompetitors) { - result.add(new SimpleCompetitorDTO(competitor)); + result.add(new SimpleCompetitorWithIdDTO(competitor)); if(++count >= limit) break; } return result; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorsAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorsAction.java new file mode 100644 index 00000000000..df0ffda1120 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetCompetitorsAction.java @@ -0,0 +1,50 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.ArrayList; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.CompetitorStore; +import com.sap.sailing.gwt.home.communication.SailingAction; +import com.sap.sailing.gwt.home.communication.SailingDispatchContext; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sse.common.Util; +import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; +import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; + +/** + * {@link SailingAction} implementation to load competitor data to be shown on the preferences page for the + * {@link #GetCompetitorSuggestionAction(String, int) given ids}. + */ +public class GetCompetitorsAction implements SailingAction> { + + private ArrayList ids; + + @SuppressWarnings("unused") + private GetCompetitorsAction() { + } + + /** + * Creates a {@link GetCompetitorsAction} instance with the given ids. + * + * @param ids + * ids to load competitors for + */ + public GetCompetitorsAction(Iterable ids) { + this.ids = (ArrayList) Util.addAll(ids, new ArrayList()); + } + + @Override + @GwtIncompatible + public SortedSetResult execute(SailingDispatchContext ctx) throws DispatchException { + CompetitorStore competitorStore = ctx.getRacingEventService().getCompetitorStore(); + SortedSetResult result = new SortedSetResult<>(); + for (String id : ids) { + Competitor competitor = competitorStore.getExistingCompetitorByIdAsString(id); + result.addValue(competitor == null ? new SimpleCompetitorWithIdDTO(id, id, "", null, null) + : new SimpleCompetitorWithIdDTO(competitor)); + } + return result; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 61f0ba4a759..908f7ae52b7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -1,34 +1,88 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; +import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreferences; +import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; +import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreferences; +import com.sap.sailing.domain.common.preferences.NotificationPreferences; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.communication.user.profile.CompetitorSuggestionResult; import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggestionAction; +import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorsAction; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; import com.sap.sse.common.Util; import com.sap.sse.common.filter.AbstractListFilter; +import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; public class UserProfilePreferencesPresenter implements UserProfilePreferencesView.Presenter { private final UserProfilePreferencesView view; private final UserProfileView.Presenter userProfilePresenter; + private NotificationPreferences notificationPreferences; public UserProfilePreferencesPresenter(UserProfilePreferencesView view, UserProfileView.Presenter userProfilePresenter) { this.view = view; this.userProfilePresenter = userProfilePresenter; view.setPresenter(this); - view.setFavouriteBoatClasses(Arrays.asList( - BoatClassMasterdata.KIELZUGVOGEL, - BoatClassMasterdata.J22)); + } + + @Override + public void start() { + userProfilePresenter.getClientFactory().getUserService().getPreference(NotificationPreferences.PREF_NAME, + new NotificationPreferences(), new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + userProfilePresenter.getClientFactory().createErrorView( + "Error while loading notification preferences!", caught); + } + + @Override + public void onSuccess(NotificationPreferences result) { + notificationPreferences = result; + setFavoriteCompetitors(result.getCompetitorPreferences()); + setFavoriteBoatClasses(result.getBoatClassPreferences()); + } + }); + } + + private void setFavoriteCompetitors(CompetitorNotificationPreferences preferences) { + List favoriteCompetitorIds = new ArrayList<>(); + for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { + favoriteCompetitorIds.add(pref.getCompetitorId()); + } + userProfilePresenter.getClientFactory().getDispatch().execute(new GetCompetitorsAction(favoriteCompetitorIds), + new AsyncCallback>() { + @Override + public void onFailure(Throwable caught) { + userProfilePresenter.getClientFactory() + .createErrorView("Error while loading notification preferences!", caught); + } + + @Override + public void onSuccess(SortedSetResult result) { + view.setFavouriteCompetitors(result.getValues()); + } + }); + } + + private void setFavoriteBoatClasses(BoatClassNotificationPreferences preferences) { + List favoriteBoatClasses = new ArrayList<>(); + for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { + favoriteBoatClasses.add(pref.getBoatClass()); + } + view.setFavouriteBoatClasses(favoriteBoatClasses); } @Override @@ -47,7 +101,7 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider() { + public SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider() { return new CompetitorSuggestedMultiSelectionDataProvider(); } @@ -68,28 +122,41 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } }); } + @Override protected void getSuggestions(Iterable queryTokens, int limit, SuggestionItemsCallback callback) { List boatClasses = Arrays.asList(BoatClassMasterdata.values()); callback.setSuggestionItems(Util.asList(filter.applyFilter(queryTokens, boatClasses))); } + + @Override + public void persist(Collection selectedItems) { + List preferences = new ArrayList<>(); + for (BoatClassMasterdata boatClass : selectedItems) { + preferences.add(new BoatClassNotificationPreference(boatClass, + isNotificationsEnabled(), isNotificationsEnabled())); + } + notificationPreferences.getBoatClassPreferences().setBoatClasses(preferences); + userProfilePresenter.getClientFactory().getUserService().setPreference( + NotificationPreferences.PREF_NAME, notificationPreferences); + } } private class CompetitorSuggestedMultiSelectionDataProvider - extends AbstractSuggestedMultiSelectionDataProvider { + extends AbstractSuggestedMultiSelectionDataProvider { private CompetitorSuggestedMultiSelectionDataProvider() { - super(new ProvidesKey() { + super(new ProvidesKey() { @Override - public Object getKey(SimpleCompetitorDTO item) { - return item.getSailID(); + public Object getKey(SimpleCompetitorWithIdDTO item) { + return item.getIdAsString(); } }); } @Override protected void getSuggestions(Iterable queryTokens, int limit, - final SuggestionItemsCallback callback) { + final SuggestionItemsCallback callback) { userProfilePresenter.getClientFactory().getDispatch().execute( new GetCompetitorSuggestionAction(queryTokens, limit), new AsyncCallback() { @@ -104,5 +171,16 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } }); } + + @Override + public void persist(Collection selectedItems) { + List preferences = new ArrayList<>(); + for (SimpleCompetitorWithIdDTO competitor : selectedItems) { + preferences.add(new CompetitorNotificationPreference(competitor.getIdAsString(), isNotificationsEnabled())); + } + notificationPreferences.getCompetitorPreferences().setCompetitors(preferences); + userProfilePresenter.getClientFactory().getUserService().setPreference( + NotificationPreferences.PREF_NAME, notificationPreferences); + } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java index 5429da2ac33..c6d28ad1d07 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java @@ -26,6 +26,7 @@ public class UserProfilePreferencesTabView extends Composite implements UserProf @Override public void start(UserProfilePreferencesPlace myPlace, AcceptsOneWidget contentArea) { contentArea.setWidget(view); + currentPresenter.start(); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index ee3169a1ff0..8a3401158a1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -4,26 +4,24 @@ import java.util.Collection; import com.google.gwt.user.client.ui.IsWidget; import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; -import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView; public interface UserProfilePreferencesView extends IsWidget { void setPresenter(Presenter presenter); - UserDetailsView getUserDetailsView(); - NeedsAuthenticationContext getDecorator(); - void setFavouriteCompetitors(Collection selectedItems); + void setFavouriteCompetitors(Collection selectedItems); void setFavouriteBoatClasses(Collection selectedItems); public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext { SuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider(); - SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider(); + SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider(); + void start(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 2734d477ba8..6aec587300c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -8,7 +8,7 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; @@ -22,7 +22,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro private static MyBinder uiBinder = GWT.create(MyBinder.class); @UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi; - @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; public UserDetailsView getUserDetailsView() { @@ -40,7 +40,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro } @Override - public void setFavouriteCompetitors(Collection selectedItems) { + public void setFavouriteCompetitors(Collection selectedItems) { favoriteCompetitorsSelctionUi.setSelectedItems(selectedItems); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java index b6b0e3a20e5..a482a725ec0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java @@ -28,22 +28,26 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider public final void addSelection(T item) { Object key = getKey(item); selectedItemsMap.put(key, item); + persist(); } @Override public final void removeSelection(T item) { Object key = getKey(item); selectedItemsMap.remove(key); + persist(); } @Override public final void clearSelection() { selectedItemsMap.clear(); + persist(); } @Override public final void setNotifications(boolean enabled) { notificationsEnabled = enabled; + persist(); } @Override @@ -72,8 +76,8 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider return notificationsEnabled; } - public Collection getSelectedItems() { - return new ArrayList<>(selectedItemsMap.values()); + private void persist() { + persist(new ArrayList<>(selectedItemsMap.values())); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index 1c3df2d4c77..aaea63362b2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -17,7 +17,7 @@ import com.google.gwt.user.client.ui.SuggestOracle.Callback; import com.google.gwt.user.client.ui.SuggestOracle.Request; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.SuggestionItemsCallback; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractAsyncSuggestBoxFilter; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractFilterWidget; @@ -121,11 +121,6 @@ public final class SuggestedMultiSelection extends Composite { }); } - @Override - protected final String createSuggestionKeyString(T value) { - return String.valueOf(dataProvider.getKey(value)); - } - @Override protected final void onSuggestionSelected(T selectedItem) { AbstractSuggestedMultiSelectionFilter.this.clear(); @@ -142,21 +137,26 @@ public final class SuggestedMultiSelection extends Composite { AbstractSuggestBoxFilter getSuggestBoxFilter(SelectionCallback selectionCallback); } - public static SuggestedMultiSelection forCompetitors( - final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { - return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { + public static SuggestedMultiSelection forCompetitors( + final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { + return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { @Override - public IsWidget getItemDescriptionWidget(SimpleCompetitorDTO item) { + public IsWidget getItemDescriptionWidget(SimpleCompetitorWithIdDTO item) { return new SuggestedMultiSelectionCompetitorItemDescription(item); } @Override - public AbstractSuggestBoxFilter getSuggestBoxFilter( - SelectionCallback selectionCallback) { - return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, + public AbstractSuggestBoxFilter getSuggestBoxFilter( + SelectionCallback selectionCallback) { + return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, StringMessages.INSTANCE.add(StringMessages.INSTANCE.competitor())) { @Override - protected String createSuggestionAdditionalDisplayString(SimpleCompetitorDTO value) { + protected String createSuggestionKeyString(SimpleCompetitorWithIdDTO value) { + return value.getSailID(); + } + + @Override + protected String createSuggestionAdditionalDisplayString(SimpleCompetitorWithIdDTO value) { return value.getName(); } }; @@ -177,6 +177,11 @@ public final class SuggestedMultiSelection extends Composite { SelectionCallback selectionCallback) { return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, StringMessages.INSTANCE.add(StringMessages.INSTANCE.boatClass())) { + @Override + protected String createSuggestionKeyString(BoatClassMasterdata value) { + return value.getDisplayName(); + } + @Override protected String createSuggestionAdditionalDisplayString(BoatClassMasterdata value) { return null; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java index 884423fed84..f4b41312d38 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java @@ -16,6 +16,8 @@ public interface SuggestedMultiSelectionDataProvider extends ProvidesKey { void getSuggestionItems(Iterable queryTokens, int limit, final SuggestionItemsCallback callback); + void persist(Collection selectedItems); + interface SuggestionItemsCallback { void setSuggestionItems(Collection suggestionItems); } From a59ee5ae1eb697e9653558cebf8240cfb207b732 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 15:15:27 +0200 Subject: [PATCH 119/259] Initially added an information test regarding notifications to the preferences page --- .../profile/preferencestab/UserProfilePreferencesViewImpl.java | 3 +++ .../preferencestab/UserProfilePreferencesViewImpl.ui.xml | 3 +++ .../java/com/sap/sailing/gwt/ui/client/StringMessages.java | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages.properties | 3 ++- .../com/sap/sailing/gwt/ui/client/StringMessages_de.properties | 3 ++- 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 6aec587300c..83d67c460b8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -3,6 +3,7 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; import java.util.Collection; import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; @@ -24,6 +25,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi; @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; + @UiField DivElement notificationsTextUi; public UserDetailsView getUserDetailsView() { return null; @@ -37,6 +39,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro favoriteBoatClassesSelctionUi = SuggestedMultiSelection .forBoatClasses(presenter.getFavoriteBoatClassesDataProvider(), "TODO Favourite boat classes"); initWidget(uiBinder.createAndBindUi(this)); + // TODO hide notificationsTextUi if the user's mail address is already verified } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml index 367de349c4d..4b5904e181b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml @@ -9,6 +9,9 @@ +
        + +
        diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 64e6fc3c401..535e35350ee 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1610,4 +1610,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String finishTime(String timeAsString); String showCompetitorCharts(); String showWindChart(); + String userNotificationsOnlyIfMailAddressIsVerified(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 5c5fc8a20f4..19d9a79f91e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1582,4 +1582,5 @@ loadingRegattasAndRaces=Loading Regattas and Races selectFromRacesWithOverlappingTimeRange=Select from the races whose time range overlaps with media track those to which the track shall be linked finishTime=Finish at: {0} showCompetitorCharts=Show competitor chart -showWindChart=Show wind chart \ No newline at end of file +showWindChart=Show wind chart +userNotificationsOnlyIfMailAddressIsVerified=Due to privacy reasons, mail notifications require that you enter your mail address on the user profile page and verify this mail address. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index d331ff33a74..5acd100ed97 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1567,4 +1567,5 @@ loadingRegattasAndRaces=Regatten und Rennen werden geladen selectFromRacesWithOverlappingTimeRange=Das oder die Rennen aus der Liste derer zum Verknüpfen auswählen, die zeitlich mit dem Medien-Track überlappen finishTime=Ende um: {0} showCompetitorCharts=Teilnehmer-Diagramme zeigen -showWindChart=Windiagramm zeigen \ No newline at end of file +showWindChart=Windiagramm zeigen +userNotificationsOnlyIfMailAddressIsVerified=Aus Gründen des Datenschutzes können Benachrichtigungen nur verwendet werden, wenn im Benutzerprofil eine gültige Mail-Adresse angegeben und diese verfifiziert wurde. From 38e470d0aa4ad0f1d2469ffc48d82bac019e294c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 15:23:35 +0200 Subject: [PATCH 120/259] Added messages for enabled and disabled to be used by the notification toggles --- .../main/java/com/sap/sailing/gwt/ui/client/StringMessages.java | 2 ++ .../com/sap/sailing/gwt/ui/client/StringMessages.properties | 2 ++ .../com/sap/sailing/gwt/ui/client/StringMessages_de.properties | 2 ++ 3 files changed, 6 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 535e35350ee..996b7aa10e3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1611,4 +1611,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String showCompetitorCharts(); String showWindChart(); String userNotificationsOnlyIfMailAddressIsVerified(); + String enabled(); + String disabled(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 19d9a79f91e..c3454c7da7e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1584,3 +1584,5 @@ finishTime=Finish at: {0} showCompetitorCharts=Show competitor chart showWindChart=Show wind chart userNotificationsOnlyIfMailAddressIsVerified=Due to privacy reasons, mail notifications require that you enter your mail address on the user profile page and verify this mail address. +enabled=Enabled +disabled=Disabled diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 5acd100ed97..9ae5e3a2760 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1569,3 +1569,5 @@ finishTime=Ende um: {0} showCompetitorCharts=Teilnehmer-Diagramme zeigen showWindChart=Windiagramm zeigen userNotificationsOnlyIfMailAddressIsVerified=Aus Gründen des Datenschutzes können Benachrichtigungen nur verwendet werden, wenn im Benutzerprofil eine gültige Mail-Adresse angegeben und diese verfifiziert wurde. +enabled=Aktiviert +disabled=Deaktiviert From 96b2a16e4b3d00b51d35a216701452ab7165c85d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 6 Jul 2016 15:30:29 +0200 Subject: [PATCH 121/259] I18n for preferences tab --- .../places/user/profile/TabletAndDesktopUserProfileView.ui.xml | 2 +- .../main/java/com/sap/sailing/gwt/ui/client/StringMessages.java | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages.properties | 1 + .../com/sap/sailing/gwt/ui/client/StringMessages_de.properties | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml index 829bc95e3e5..8a7b9e6c892 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml @@ -45,7 +45,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 996b7aa10e3..dd5ee23e706 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1613,4 +1613,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String userNotificationsOnlyIfMailAddressIsVerified(); String enabled(); String disabled(); + String favouritesAndNotifications(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index c3454c7da7e..2382419671f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1586,3 +1586,4 @@ showWindChart=Show wind chart userNotificationsOnlyIfMailAddressIsVerified=Due to privacy reasons, mail notifications require that you enter your mail address on the user profile page and verify this mail address. enabled=Enabled disabled=Disabled +favouritesAndNotifications=Favourites/Notifications \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 9ae5e3a2760..d0b902f927d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1571,3 +1571,4 @@ showWindChart=Windiagramm zeigen userNotificationsOnlyIfMailAddressIsVerified=Aus Gründen des Datenschutzes können Benachrichtigungen nur verwendet werden, wenn im Benutzerprofil eine gültige Mail-Adresse angegeben und diese verfifiziert wurde. enabled=Aktiviert disabled=Deaktiviert +favouritesAndNotifications=Favoriten/Benachrichtigungen From 59a3c3bb8a223e3ddbbc55c9faaa19c690ad2790 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 6 Jul 2016 17:42:27 +0200 Subject: [PATCH 122/259] Adjusted client-side user preferences saving and loading logic --- .../UserProfilePreferencesPresenter.java | 118 ++++++++---------- .../UserProfilePreferencesView.java | 15 +-- .../UserProfilePreferencesViewImpl.java | 92 +++++++++++--- ...ssSuggestedMultiSelectionDataProvider.java | 73 +++++++++++ ...orSuggestedMultiSelectionDataProvider.java | 38 ++++++ ...ctSuggestedMultiSelectionDataProvider.java | 33 +++-- ...ssSuggestedMultiSelectionDataProvider.java | 26 ++++ ...orSuggestedMultiSelectionDataProvider.java | 19 +++ .../selection/SuggestedMultiSelection.java | 52 +++++--- .../selection/SuggestedMultiSelection.ui.xml | 2 +- .../SuggestedMultiSelectionDataProvider.java | 14 ++- ...estedMultiSelectionNotificationToggle.java | 9 +- ...tedMultiSelectionNotificationToggle.ui.xml | 2 +- 13 files changed, 353 insertions(+), 140 deletions(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractBoatClassSuggestedMultiSelectionDataProvider.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractCompetitorSuggestedMultiSelectionDataProvider.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/BoatClassSuggestedMultiSelectionDataProvider.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/CompetitorSuggestedMultiSelectionDataProvider.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 908f7ae52b7..3d684b97dc2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -1,13 +1,12 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; +import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; -import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreferences; @@ -19,10 +18,10 @@ import com.sap.sailing.gwt.home.communication.user.profile.CompetitorSuggestionR import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggestionAction; import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorsAction; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; -import com.sap.sse.common.Util; -import com.sap.sse.common.filter.AbstractListFilter; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractBoatClassSuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractCompetitorSuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.BoatClassSuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider; import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; @@ -31,8 +30,13 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi private final UserProfilePreferencesView view; private final UserProfileView.Presenter userProfilePresenter; private NotificationPreferences notificationPreferences; - - public UserProfilePreferencesPresenter(UserProfilePreferencesView view, UserProfileView.Presenter userProfilePresenter) { + private final CompetitorSuggestedMultiSelectionDataProvider competitorDataProvider = + new CompetitorSuggestedMultiSelectionDataProviderImpl(); + private final BoatClassSuggestedMultiSelectionDataProvider boatClassDataProvider = + new BoatClassSuggestedMultiSelectionDataProviderImpl(); + + public UserProfilePreferencesPresenter(final UserProfilePreferencesView view, + final UserProfileView.Presenter userProfilePresenter) { this.view = view; this.userProfilePresenter = userProfilePresenter; view.setPresenter(this); @@ -40,28 +44,31 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi @Override public void start() { - userProfilePresenter.getClientFactory().getUserService().getPreference(NotificationPreferences.PREF_NAME, + userProfilePresenter.getClientFactory().getUserService().getPreference(NotificationPreferences.PREF_NAME, new NotificationPreferences(), new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - userProfilePresenter.getClientFactory().createErrorView( - "Error while loading notification preferences!", caught); - } - - @Override - public void onSuccess(NotificationPreferences result) { - notificationPreferences = result; - setFavoriteCompetitors(result.getCompetitorPreferences()); - setFavoriteBoatClasses(result.getBoatClassPreferences()); - } - }); + @Override + public void onFailure(Throwable caught) { + userProfilePresenter.getClientFactory().createErrorView( + "Error while loading notification preferences!", caught); + } + + @Override + public void onSuccess(NotificationPreferences result) { + notificationPreferences = result; + initFavoriteCompetitors(result.getCompetitorPreferences()); + initFavoriteBoatClasses(result.getBoatClassPreferences()); + } + }); } - private void setFavoriteCompetitors(CompetitorNotificationPreferences preferences) { + private void initFavoriteCompetitors(CompetitorNotificationPreferences preferences) { + boolean initialNotifyAboutResults = false; List favoriteCompetitorIds = new ArrayList<>(); for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { favoriteCompetitorIds.add(pref.getCompetitorId()); + initialNotifyAboutResults |= pref.isNotifyAboutResults(); } + competitorDataProvider.initNotifications(initialNotifyAboutResults); userProfilePresenter.getClientFactory().getDispatch().execute(new GetCompetitorsAction(favoriteCompetitorIds), new AsyncCallback>() { @Override @@ -72,19 +79,23 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi @Override public void onSuccess(SortedSetResult result) { - view.setFavouriteCompetitors(result.getValues()); + competitorDataProvider.initSelectedItems(result.getValues()); } }); } - private void setFavoriteBoatClasses(BoatClassNotificationPreferences preferences) { + private void initFavoriteBoatClasses(BoatClassNotificationPreferences preferences) { + boolean initialNotifyAboutResults = false, initialNotifyAboutUpcomingRaces = false; List favoriteBoatClasses = new ArrayList<>(); for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { favoriteBoatClasses.add(pref.getBoatClass()); + initialNotifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); + initialNotifyAboutResults |= pref.isNotifyAboutResults(); } - view.setFavouriteBoatClasses(favoriteBoatClasses); + boatClassDataProvider.initSelectedItems(favoriteBoatClasses); + boatClassDataProvider.initNotifications(initialNotifyAboutUpcomingRaces, initialNotifyAboutResults); } - + @Override public void setAuthenticationContext(AuthenticationContext authenticationContext) { view.getDecorator().setAuthenticationContext(authenticationContext); @@ -96,46 +107,24 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public SuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider() { - return new BoatClassSuggestedMultiSelectionDataProvider(); + public BoatClassSuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider() { + return boatClassDataProvider; } @Override - public SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider() { - return new CompetitorSuggestedMultiSelectionDataProvider(); + public CompetitorSuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider() { + return competitorDataProvider; } - private class BoatClassSuggestedMultiSelectionDataProvider - extends AbstractSuggestedMultiSelectionDataProvider { - private final AbstractListFilter filter = new AbstractListFilter() { - @Override - public Iterable getStrings(BoatClassMasterdata item) { - return item.getBoatClassNames(); - } - }; - - private BoatClassSuggestedMultiSelectionDataProvider() { - super(new ProvidesKey() { - @Override - public Object getKey(BoatClassMasterdata item) { - return item.getDisplayName(); - } - }); - } - - @Override - protected void getSuggestions(Iterable queryTokens, int limit, - SuggestionItemsCallback callback) { - List boatClasses = Arrays.asList(BoatClassMasterdata.values()); - callback.setSuggestionItems(Util.asList(filter.applyFilter(queryTokens, boatClasses))); - } - + private class BoatClassSuggestedMultiSelectionDataProviderImpl + extends AbstractBoatClassSuggestedMultiSelectionDataProvider { @Override public void persist(Collection selectedItems) { + GWT.debugger(); List preferences = new ArrayList<>(); for (BoatClassMasterdata boatClass : selectedItems) { preferences.add(new BoatClassNotificationPreference(boatClass, - isNotificationsEnabled(), isNotificationsEnabled())); + isNotifyAboutUpcomingRaces(), isNotifyAboutResults())); } notificationPreferences.getBoatClassPreferences().setBoatClasses(preferences); userProfilePresenter.getClientFactory().getUserService().setPreference( @@ -143,16 +132,8 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } } - private class CompetitorSuggestedMultiSelectionDataProvider - extends AbstractSuggestedMultiSelectionDataProvider { - private CompetitorSuggestedMultiSelectionDataProvider() { - super(new ProvidesKey() { - @Override - public Object getKey(SimpleCompetitorWithIdDTO item) { - return item.getIdAsString(); - } - }); - } + private class CompetitorSuggestedMultiSelectionDataProviderImpl + extends AbstractCompetitorSuggestedMultiSelectionDataProvider { @Override protected void getSuggestions(Iterable queryTokens, int limit, @@ -174,9 +155,10 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi @Override public void persist(Collection selectedItems) { + GWT.debugger(); List preferences = new ArrayList<>(); for (SimpleCompetitorWithIdDTO competitor : selectedItems) { - preferences.add(new CompetitorNotificationPreference(competitor.getIdAsString(), isNotificationsEnabled())); + preferences.add(new CompetitorNotificationPreference(competitor.getIdAsString(), isNotifyAboutResults())); } notificationPreferences.getCompetitorPreferences().setCompetitors(preferences); userProfilePresenter.getClientFactory().getUserService().setPreference( diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index 8a3401158a1..5a19d431691 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -1,11 +1,8 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; -import java.util.Collection; - import com.google.gwt.user.client.ui.IsWidget; -import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.BoatClassSuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; @@ -15,13 +12,9 @@ public interface UserProfilePreferencesView extends IsWidget { NeedsAuthenticationContext getDecorator(); - void setFavouriteCompetitors(Collection selectedItems); - - void setFavouriteBoatClasses(Collection selectedItems); - public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext { - SuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider(); - SuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider(); + BoatClassSuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider(); + CompetitorSuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider(); void start(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 83d67c460b8..af5f03db628 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -7,13 +7,16 @@ import com.google.gwt.dom.client.DivElement; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.BoatClassSuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection.NotificationCallback; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; -import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView; public class UserProfilePreferencesViewImpl extends Composite implements UserProfilePreferencesView { @@ -27,33 +30,84 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; @UiField DivElement notificationsTextUi; - public UserDetailsView getUserDetailsView() { - return null; - } - @Override public void setPresenter(Presenter presenter) { decoratorUi = new AuthorizedContentDecoratorDesktop(presenter); - favoriteCompetitorsSelctionUi = SuggestedMultiSelection - .forCompetitors(presenter.getFavoriteCompetitorsDataProvider(), "TODO Favourite competitors"); - favoriteBoatClassesSelctionUi = SuggestedMultiSelection - .forBoatClasses(presenter.getFavoriteBoatClassesDataProvider(), "TODO Favourite boat classes"); + favoriteCompetitorsSelctionUi = new CompetitorDisplayImpl( + presenter.getFavoriteCompetitorsDataProvider()).selectionUi; + favoriteBoatClassesSelctionUi = new BoatClassDisplayImpl( + presenter.getFavoriteBoatClassesDataProvider()).selectionUi; initWidget(uiBinder.createAndBindUi(this)); // TODO hide notificationsTextUi if the user's mail address is already verified } - @Override - public void setFavouriteCompetitors(Collection selectedItems) { - favoriteCompetitorsSelctionUi.setSelectedItems(selectedItems); - } - - @Override - public void setFavouriteBoatClasses(Collection selectedItems) { - favoriteBoatClassesSelctionUi.setSelectedItems(selectedItems); - } - @Override public NeedsAuthenticationContext getDecorator() { return decoratorUi; } + + private class CompetitorDisplayImpl implements CompetitorSuggestedMultiSelectionDataProvider.Display { + private final SuggestedMultiSelection selectionUi; + private final HasEnabled notifyAboutResultsUi; + + private CompetitorDisplayImpl(final CompetitorSuggestedMultiSelectionDataProvider dataProvider) { + selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, "TODO Favourite competitors"); + notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { + @Override + public void onNotificationToggled(boolean enabled) { + dataProvider.setNotifyAboutResults(enabled); + } + }, "TODO Email notification about new results"); + dataProvider.setDisplay(this); + } + + @Override + public void setSelectedItems(Collection selectedItems) { + selectionUi.setSelectedItems(selectedItems); + } + + @Override + public void setNotifyAboutResults(boolean notifyAboutResults) { + notifyAboutResultsUi.setEnabled(notifyAboutResults); + } + } + + private class BoatClassDisplayImpl implements BoatClassSuggestedMultiSelectionDataProvider.Display { + private final SuggestedMultiSelection selectionUi; + private final HasEnabled notifyAboutUpcomingRacesUi; + private final HasEnabled notifyAboutResultsUi; + + private BoatClassDisplayImpl(final BoatClassSuggestedMultiSelectionDataProvider dataProvider) { + selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, "TODO Favourite boat classes"); + notifyAboutUpcomingRacesUi = selectionUi.addNotificationToggle(new NotificationCallback() { + @Override + public void onNotificationToggled(boolean enabled) { + dataProvider.setNotifyAboutUpcomingRaces(enabled); + } + }, "TODO Email notification about upcoming races"); + notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { + @Override + public void onNotificationToggled(boolean enabled) { + dataProvider.setNotifyAboutResults(enabled); + } + }, "TODO Email notification about new results"); + dataProvider.setDisplay(this); + } + + @Override + public void setSelectedItems(Collection selectedItems) { + selectionUi.setSelectedItems(selectedItems); + } + + @Override + public void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces) { + notifyAboutUpcomingRacesUi.setEnabled(notifyAboutUpcomingRaces); + } + + @Override + public void setNotifyAboutResults(boolean notifyAboutResults) { + notifyAboutResultsUi.setEnabled(notifyAboutResults); + } + } + } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractBoatClassSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractBoatClassSuggestedMultiSelectionDataProvider.java new file mode 100644 index 00000000000..c2a3b1fc0d8 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractBoatClassSuggestedMultiSelectionDataProvider.java @@ -0,0 +1,73 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import java.util.Arrays; +import java.util.List; + +import com.google.gwt.view.client.ProvidesKey; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sse.common.Util; +import com.sap.sse.common.filter.AbstractListFilter; + +public abstract class AbstractBoatClassSuggestedMultiSelectionDataProvider extends + AbstractSuggestedMultiSelectionDataProvider + implements BoatClassSuggestedMultiSelectionDataProvider { + + private boolean notifyAboutUpcomingRaces; + private boolean notifyAboutResults; + + private final AbstractListFilter filter = new AbstractListFilter() { + @Override + public Iterable getStrings(BoatClassMasterdata item) { + return item.getBoatClassNames(); + } + }; + + protected AbstractBoatClassSuggestedMultiSelectionDataProvider() { + super(new ProvidesKey() { + @Override + public Object getKey(BoatClassMasterdata item) { + return item.getDisplayName(); + } + }); + } + + @Override + protected void getSuggestions(Iterable queryTokens, int limit, + SuggestionItemsCallback callback) { + List boatClasses = Arrays.asList(BoatClassMasterdata.values()); + callback.setSuggestionItems(Util.asList(filter.applyFilter(queryTokens, boatClasses))); + } + + @Override + public void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults) { + this.notifyAboutUpcomingRaces = notifyAboutUpcomingRaces; + this.notifyAboutResults = notifyAboutResults; + if (display != null) { + display.setNotifyAboutUpcomingRaces(notifyAboutUpcomingRaces); + display.setNotifyAboutResults(notifyAboutResults); + } + } + + @Override + public boolean isNotifyAboutUpcomingRaces() { + return notifyAboutUpcomingRaces; + } + + @Override + public void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces) { + this.notifyAboutUpcomingRaces = notifyAboutUpcomingRaces; + this.persist(); + } + + @Override + public boolean isNotifyAboutResults() { + return notifyAboutResults; + } + + @Override + public void setNotifyAboutResults(boolean notifyAboutResults) { + this.notifyAboutResults = notifyAboutResults; + this.persist(); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractCompetitorSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractCompetitorSuggestedMultiSelectionDataProvider.java new file mode 100644 index 00000000000..735d3b6c332 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractCompetitorSuggestedMultiSelectionDataProvider.java @@ -0,0 +1,38 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.google.gwt.view.client.ProvidesKey; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; + +public abstract class AbstractCompetitorSuggestedMultiSelectionDataProvider extends + AbstractSuggestedMultiSelectionDataProvider + implements CompetitorSuggestedMultiSelectionDataProvider { + + private boolean notifyAboutResults; + + protected AbstractCompetitorSuggestedMultiSelectionDataProvider() { + super(new ProvidesKey() { + @Override + public Object getKey(SimpleCompetitorWithIdDTO item) { + return item.getIdAsString(); + } + }); + } + + @Override + public void initNotifications(boolean notifyAboutResults) { + this.notifyAboutResults = notifyAboutResults; + if (display != null) display.setNotifyAboutResults(notifyAboutResults); + } + + @Override + public void setNotifyAboutResults(boolean notifyAboutResults) { + this.notifyAboutResults = notifyAboutResults; + this.persist(); + } + + @Override + public boolean isNotifyAboutResults() { + return notifyAboutResults; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java index a482a725ec0..f669c6ed934 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java @@ -7,18 +7,24 @@ import java.util.List; import java.util.Map; import com.google.gwt.view.client.ProvidesKey; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.Display; -public abstract class AbstractSuggestedMultiSelectionDataProvider - implements SuggestedMultiSelectionDataProvider { +public abstract class AbstractSuggestedMultiSelectionDataProvider> + implements SuggestedMultiSelectionDataProvider { private final ProvidesKey keyProvider; private final Map selectedItemsMap = new HashMap<>(); - private boolean notificationsEnabled; + protected D display; protected AbstractSuggestedMultiSelectionDataProvider(ProvidesKey keyProvider) { this.keyProvider = keyProvider; } + @Override + public void setDisplay(D display) { + this.display = display; + } + @Override public final Object getKey(T item) { return keyProvider == null ? item : keyProvider.getKey(item); @@ -45,9 +51,11 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider } @Override - public final void setNotifications(boolean enabled) { - notificationsEnabled = enabled; - persist(); + public final void initSelectedItems(Collection selectedItems) { + for (T item : selectedItems) { + selectedItemsMap.put(getKey(item), item); + } + if (display != null) display.setSelectedItems(selectedItems); } @Override @@ -68,16 +76,15 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider }; this.getSuggestions(queryTokens, limit, internalCallback); } + + @Override + public void persist() { + this.persist(new ArrayList<>(selectedItemsMap.values())); + } protected abstract void getSuggestions(Iterable queryTokens, int limit, SuggestionItemsCallback callback); - public boolean isNotificationsEnabled() { - return notificationsEnabled; - } - - private void persist() { - persist(new ArrayList<>(selectedItemsMap.values())); - } + protected abstract void persist(Collection selectedItem); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/BoatClassSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/BoatClassSuggestedMultiSelectionDataProvider.java new file mode 100644 index 00000000000..f852a9661f7 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/BoatClassSuggestedMultiSelectionDataProvider.java @@ -0,0 +1,26 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.BoatClassSuggestedMultiSelectionDataProvider.Display; + +public interface BoatClassSuggestedMultiSelectionDataProvider + extends SuggestedMultiSelectionDataProvider { + + boolean isNotifyAboutUpcomingRaces(); + + void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces); + + boolean isNotifyAboutResults(); + + void setNotifyAboutResults(boolean notifyAboutResults); + + void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults); + + interface Display extends SuggestedMultiSelectionDataProvider.Display { + + void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces); + + void setNotifyAboutResults(boolean notifyAboutResults); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/CompetitorSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/CompetitorSuggestedMultiSelectionDataProvider.java new file mode 100644 index 00000000000..5cd99e6c422 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/CompetitorSuggestedMultiSelectionDataProvider.java @@ -0,0 +1,19 @@ +package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; + +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider.Display; + +public interface CompetitorSuggestedMultiSelectionDataProvider + extends SuggestedMultiSelectionDataProvider { + + boolean isNotifyAboutResults(); + + void setNotifyAboutResults(boolean notifyAboutResults); + + void initNotifications(boolean notifyAboutResults); + + public static interface Display extends SuggestedMultiSelectionDataProvider.Display { + + void setNotifyAboutResults(boolean notifyAboutResults); + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index aaea63362b2..e8221f08c59 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -24,7 +24,7 @@ import com.sap.sailing.gwt.home.shared.partials.filter.AbstractFilterWidget; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter; import com.sap.sailing.gwt.ui.client.StringMessages; -public final class SuggestedMultiSelection extends Composite { +public final class SuggestedMultiSelection extends Composite implements SuggestedMultiSelectionDataProvider.Display { private static SuggestedMultiSelectionUiBinder uiBinder = GWT.create(SuggestedMultiSelectionUiBinder.class); @@ -32,14 +32,14 @@ public final class SuggestedMultiSelection extends Composite { } @UiField SpanElement headerTitleUi; - @UiField SuggestedMultiSelectionNotificationToggle noticationToggleUi; + @UiField FlowPanel notificationToggleContainerUi; @UiField(provided = true) AbstractFilterWidget suggestionWidgetUi; @UiField Button removeAllButtonUi; @UiField FlowPanel itemContainerUi; - private final SuggestedMultiSelectionDataProvider dataProvider; + private final SuggestedMultiSelectionDataProvider dataProvider; private final WidgetProvider widgetProvider; - private SuggestedMultiSelection(SuggestedMultiSelectionDataProvider dataProvider, + private SuggestedMultiSelection(SuggestedMultiSelectionDataProvider dataProvider, WidgetProvider widgetProvider, String title) { SuggestedMultiSelectionResources.INSTANCE.css().ensureInjected(); this.dataProvider = dataProvider; @@ -47,19 +47,28 @@ public final class SuggestedMultiSelection extends Composite { this.suggestionWidgetUi = widgetProvider.getSuggestBoxFilter(new SelectionCallback() { @Override public void onSuggestionSelected(T selectedItem) { + SuggestedMultiSelection.this.dataProvider.addSelection(selectedItem); SuggestedMultiSelection.this.addSelectedItem(selectedItem); } }); initWidget(uiBinder.createAndBindUi(this)); headerTitleUi.setInnerText(title); - noticationToggleUi.toggleButtonUi.addClickHandler(new ClickHandler() { + this.updateUiState(); + } + + public SuggestedMultiSelectionNotificationToggle addNotificationToggle(final NotificationCallback callback, + String label) { + final SuggestedMultiSelectionNotificationToggle notification = + new SuggestedMultiSelectionNotificationToggle(label); + notification.toggleButtonUi.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - final boolean enabled = noticationToggleUi.isEnabled(); - SuggestedMultiSelection.this.dataProvider.setNotifications(enabled); + final boolean enabled = notification.isEnabled(); + callback.onNotificationToggled(enabled); } }); - this.updateUiState(); + notificationToggleContainerUi.add(notification); + return notification; } @UiHandler("removeAllButtonUi") @@ -69,8 +78,8 @@ public final class SuggestedMultiSelection extends Composite { this.updateUiState(); } + @Override public void setSelectedItems(Collection selectedItemsToSet) { - dataProvider.clearSelection(); itemContainerUi.clear(); for (final T item : selectedItemsToSet) { this.addSelectedItem(item); @@ -78,7 +87,6 @@ public final class SuggestedMultiSelection extends Composite { } private void addSelectedItem(final T selectedItem) { - dataProvider.addSelection(selectedItem); itemContainerUi.add(new SuggestedMultiSelectionItem() { @Override protected IsWidget getItemDescriptionWidget() { @@ -100,10 +108,10 @@ public final class SuggestedMultiSelection extends Composite { } private static abstract class AbstractSuggestedMultiSelectionFilter extends AbstractAsyncSuggestBoxFilter { - private final SuggestedMultiSelectionDataProvider dataProvider; + private final SuggestedMultiSelectionDataProvider dataProvider; private final SelectionCallback selectionCallback; - protected AbstractSuggestedMultiSelectionFilter(SuggestedMultiSelectionDataProvider dataProvider, + protected AbstractSuggestedMultiSelectionFilter(SuggestedMultiSelectionDataProvider dataProvider, SelectionCallback selectionCallback, String placeholderText) { super(placeholderText); this.dataProvider = dataProvider; @@ -128,6 +136,10 @@ public final class SuggestedMultiSelection extends Composite { } } + public interface NotificationCallback { + void onNotificationToggled(boolean enabled); + } + private interface SelectionCallback { void onSuggestionSelected(T selectedItem); } @@ -138,23 +150,23 @@ public final class SuggestedMultiSelection extends Composite { } public static SuggestedMultiSelection forCompetitors( - final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { + final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { @Override public IsWidget getItemDescriptionWidget(SimpleCompetitorWithIdDTO item) { return new SuggestedMultiSelectionCompetitorItemDescription(item); } - + @Override public AbstractSuggestBoxFilter getSuggestBoxFilter( SelectionCallback selectionCallback) { - return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, - StringMessages.INSTANCE.add(StringMessages.INSTANCE.competitor())) { + return new AbstractSuggestedMultiSelectionFilter(dataProvider, + selectionCallback, StringMessages.INSTANCE.add(StringMessages.INSTANCE.competitor())) { @Override protected String createSuggestionKeyString(SimpleCompetitorWithIdDTO value) { return value.getSailID(); } - + @Override protected String createSuggestionAdditionalDisplayString(SimpleCompetitorWithIdDTO value) { return value.getName(); @@ -165,13 +177,13 @@ public final class SuggestedMultiSelection extends Composite { } public static SuggestedMultiSelection forBoatClasses( - final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { + final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { @Override public IsWidget getItemDescriptionWidget(BoatClassMasterdata item) { return new SuggestedMultiSelectionBoatClassItemDescription(item); } - + @Override public AbstractSuggestBoxFilter getSuggestBoxFilter( SelectionCallback selectionCallback) { @@ -181,7 +193,7 @@ public final class SuggestedMultiSelection extends Composite { protected String createSuggestionKeyString(BoatClassMasterdata value) { return value.getDisplayName(); } - + @Override protected String createSuggestionAdditionalDisplayString(BoatClassMasterdata value) { return null; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml index 07003f640ba..d0546c07acc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml @@ -17,7 +17,7 @@
        - +
        diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java index f4b41312d38..cd2f51aa8ec 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java @@ -3,8 +3,9 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; import java.util.Collection; import com.google.gwt.view.client.ProvidesKey; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.Display; -public interface SuggestedMultiSelectionDataProvider extends ProvidesKey { +public interface SuggestedMultiSelectionDataProvider> extends ProvidesKey { void addSelection(T item); @@ -12,14 +13,19 @@ public interface SuggestedMultiSelectionDataProvider extends ProvidesKey { void clearSelection(); - void setNotifications(boolean enabled); - void getSuggestionItems(Iterable queryTokens, int limit, final SuggestionItemsCallback callback); - void persist(Collection selectedItems); + void setDisplay(D display); + + void persist(); + + void initSelectedItems(Collection selectedItems); interface SuggestionItemsCallback { void setSuggestionItems(Collection suggestionItems); } + interface Display { + void setSelectedItems(Collection selectedItems); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java index 9a849eb71cf..b7b836836fa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java @@ -8,8 +8,10 @@ import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasEnabled; +import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.common.client.SharedResources; +import com.sap.sailing.gwt.ui.client.StringMessages; class SuggestedMultiSelectionNotificationToggle extends Composite implements HasEnabled { @@ -19,12 +21,13 @@ class SuggestedMultiSelectionNotificationToggle extends Composite implements Has } @UiField SharedResources res; + @UiField Label labelUi; @UiField Button toggleButtonUi; private boolean enabled = false; - SuggestedMultiSelectionNotificationToggle() { + SuggestedMultiSelectionNotificationToggle(String label) { initWidget(uiBinder.createAndBindUi(this)); - this.updateUiState(); // TODO remove + labelUi.setText(label); } @UiHandler("toggleButtonUi") @@ -45,7 +48,7 @@ class SuggestedMultiSelectionNotificationToggle extends Composite implements Has private void updateUiState() { toggleButtonUi.setStyleName(res.mainCss().buttonred(), !enabled); - toggleButtonUi.setText(enabled ? "!Enabled!" : "!Disabled!"); + toggleButtonUi.setText(enabled ? StringMessages.INSTANCE.enabled() : StringMessages.INSTANCE.disabled()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml index 3edbcaa3b04..ddbb0cc52b5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml @@ -4,7 +4,7 @@ - TODO Email notification for this category + \ No newline at end of file From 3212ed03dbd60b1bcf5f90686795c810cb2de669 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 08:41:35 +0200 Subject: [PATCH 123/259] Prepared NotificationSets for BoatClass and Competitor Notifications --- .../AbstractBoatClassNotificationSet.java | 33 +++++++++++++++++++ .../AbstractCompetitorNotificationSet.java | 33 +++++++++++++++++++ .../BoatClassResultsNotificationSet.java | 16 +++++++++ .../BoatClassUpcomingRaceNotificationSet.java | 16 +++++++++ .../CompetitorResultsNotificationSet.java | 17 ++++++++++ 5 files changed, 115 insertions(+) create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java new file mode 100644 index 00000000000..e85e54e7d16 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java @@ -0,0 +1,33 @@ +package com.sap.sailing.server.impl.preferences; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; +import com.sap.sailing.domain.common.preferences.NotificationPreferences; +import com.sap.sse.security.PreferenceObjectBasedNotificationSet; +import com.sap.sse.security.UserStore; + +public abstract class AbstractBoatClassNotificationSet + extends PreferenceObjectBasedNotificationSet { + + public AbstractBoatClassNotificationSet(UserStore store) { + super(NotificationPreferences.PREF_NAME, store); + } + + @Override + protected Collection calculateObjectsToNotify(NotificationPreferences preference) { + Set result = new HashSet<>(); + for (BoatClassNotificationPreference pref : preference.getBoatClassPreferences().getBoatClasses()) { + if (shouldNotifyFor(pref)) { + result.add(pref.getBoatClass()); + } + } + return result; + } + + protected abstract boolean shouldNotifyFor(BoatClassNotificationPreference pref); + +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java new file mode 100644 index 00000000000..3489f62d5a4 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java @@ -0,0 +1,33 @@ +package com.sap.sailing.server.impl.preferences; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; +import com.sap.sailing.domain.common.preferences.NotificationPreferences; +import com.sap.sse.security.PreferenceObjectBasedNotificationSet; +import com.sap.sse.security.UserStore; + +public abstract class AbstractCompetitorNotificationSet + extends PreferenceObjectBasedNotificationSet { + + public AbstractCompetitorNotificationSet(UserStore store) { + super(NotificationPreferences.PREF_NAME, store); + } + + @Override + protected Collection calculateObjectsToNotify(NotificationPreferences preference) { + Set result = new HashSet<>(); + for (CompetitorNotificationPreference pref : preference.getCompetitorPreferences().getCompetitors()) { + if (shouldNotifyFor(pref)) { + result.add(pref.getCompetitorId()); + } + } + return result; + } + + protected abstract boolean shouldNotifyFor(CompetitorNotificationPreference pref); + +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java new file mode 100644 index 00000000000..084f02c9845 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java @@ -0,0 +1,16 @@ +package com.sap.sailing.server.impl.preferences; + +import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; +import com.sap.sse.security.UserStore; + +public class BoatClassResultsNotificationSet extends AbstractBoatClassNotificationSet { + + public BoatClassResultsNotificationSet(UserStore store) { + super(store); + } + + @Override + protected boolean shouldNotifyFor(BoatClassNotificationPreference pref) { + return pref.isNotifyAboutResults(); + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java new file mode 100644 index 00000000000..379d67f55e7 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java @@ -0,0 +1,16 @@ +package com.sap.sailing.server.impl.preferences; + +import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; +import com.sap.sse.security.UserStore; + +public class BoatClassUpcomingRaceNotificationSet extends AbstractBoatClassNotificationSet { + + public BoatClassUpcomingRaceNotificationSet(UserStore store) { + super(store); + } + + @Override + protected boolean shouldNotifyFor(BoatClassNotificationPreference pref) { + return pref.isNotifyAboutUpcomingRaces(); + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java new file mode 100644 index 00000000000..766747a1d53 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java @@ -0,0 +1,17 @@ +package com.sap.sailing.server.impl.preferences; + +import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; +import com.sap.sse.security.UserStore; + +public class CompetitorResultsNotificationSet extends AbstractCompetitorNotificationSet { + + public CompetitorResultsNotificationSet(UserStore store) { + super(store); + } + + @Override + protected boolean shouldNotifyFor(CompetitorNotificationPreference pref) { + return pref.isNotifyAboutResults(); + } + +} From da43003a2cffd2810293b6af64738f66783a9164 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 09:09:03 +0200 Subject: [PATCH 124/259] Updated JavaDocs --- .../sse/security/PreferenceObjectBasedNotificationSet.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index a86844772c9..ceed6bfb22e 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -13,7 +13,10 @@ import java.util.logging.Logger; import com.sap.sse.common.Util; /** - * Holds an optimized association of who to notify about specific objects. + * Holds an optimized association of who to notify about specific objects. On preference changes for the given key in + * the given {@link UserStore}, the associations are being updated to make the model always reflect the current state of + * the associations. This makes it possible to search for associations for a specific object without the need of a model + * update on the fly. * * @param * The type of preference object on which the calculation of the objects to notify is based on. From fb39c0992cfe9e5ea8073753114b8481f8fd216a Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 7 Jul 2016 09:45:29 +0200 Subject: [PATCH 125/259] Refactored client-side user preferences saving and loading logic --- .../UserProfilePreferencesPresenter.java | 46 ++++++++++--------- .../UserProfilePreferencesView.java | 8 ++-- .../UserProfilePreferencesViewImpl.java | 16 +++---- ...dMultiSelectionBoatClassDataProvider.java} | 10 ++-- ...MultiSelectionCompetitorDataProvider.java} | 12 +++-- ...ctSuggestedMultiSelectionDataProvider.java | 12 +++-- ...dMultiSelectionBoatClassDataProvider.java} | 4 +- ...MultiSelectionCompetitorDataProvider.java} | 4 +- .../SuggestedMultiSelectionDataProvider.java | 2 +- 9 files changed, 61 insertions(+), 53 deletions(-) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/{AbstractBoatClassSuggestedMultiSelectionDataProvider.java => AbstractSuggestedMultiSelectionBoatClassDataProvider.java} (87%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/{AbstractCompetitorSuggestedMultiSelectionDataProvider.java => AbstractSuggestedMultiSelectionCompetitorDataProvider.java} (70%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/{BoatClassSuggestedMultiSelectionDataProvider.java => SuggestedMultiSelectionBoatClassDataProvider.java} (87%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/{CompetitorSuggestedMultiSelectionDataProvider.java => SuggestedMultiSelectionCompetitorDataProvider.java} (84%) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 3d684b97dc2..c82689f3b5e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; -import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sailing.domain.common.BoatClassMasterdata; @@ -18,22 +17,23 @@ import com.sap.sailing.gwt.home.communication.user.profile.CompetitorSuggestionR import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggestionAction; import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorsAction; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractBoatClassSuggestedMultiSelectionDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractCompetitorSuggestedMultiSelectionDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.BoatClassSuggestedMultiSelectionDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; +import com.sap.sse.security.ui.client.UserService; public class UserProfilePreferencesPresenter implements UserProfilePreferencesView.Presenter { private final UserProfilePreferencesView view; private final UserProfileView.Presenter userProfilePresenter; private NotificationPreferences notificationPreferences; - private final CompetitorSuggestedMultiSelectionDataProvider competitorDataProvider = - new CompetitorSuggestedMultiSelectionDataProviderImpl(); - private final BoatClassSuggestedMultiSelectionDataProvider boatClassDataProvider = - new BoatClassSuggestedMultiSelectionDataProviderImpl(); + private final SuggestedMultiSelectionCompetitorDataProvider competitorDataProvider = + new SuggestedMultiSelectionCompetitorDataProviderImpl(); + private final SuggestedMultiSelectionBoatClassDataProvider boatClassDataProvider = + new SuggestedMultiSelectionBoatClassDataProviderImpl(); public UserProfilePreferencesPresenter(final UserProfilePreferencesView view, final UserProfileView.Presenter userProfilePresenter) { @@ -96,6 +96,11 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi boatClassDataProvider.initNotifications(initialNotifyAboutUpcomingRaces, initialNotifyAboutResults); } + private void persistNotificationPreferences() { + UserService userService = userProfilePresenter.getClientFactory().getUserService(); + userService.setPreference(NotificationPreferences.PREF_NAME, notificationPreferences); + } + @Override public void setAuthenticationContext(AuthenticationContext authenticationContext) { view.getDecorator().setAuthenticationContext(authenticationContext); @@ -107,33 +112,31 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public BoatClassSuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider() { + public SuggestedMultiSelectionBoatClassDataProvider getFavoriteBoatClassesDataProvider() { return boatClassDataProvider; } @Override - public CompetitorSuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider() { + public SuggestedMultiSelectionCompetitorDataProvider getFavoriteCompetitorsDataProvider() { return competitorDataProvider; } - private class BoatClassSuggestedMultiSelectionDataProviderImpl - extends AbstractBoatClassSuggestedMultiSelectionDataProvider { + private class SuggestedMultiSelectionBoatClassDataProviderImpl + extends AbstractSuggestedMultiSelectionBoatClassDataProvider { @Override public void persist(Collection selectedItems) { - GWT.debugger(); List preferences = new ArrayList<>(); for (BoatClassMasterdata boatClass : selectedItems) { preferences.add(new BoatClassNotificationPreference(boatClass, isNotifyAboutUpcomingRaces(), isNotifyAboutResults())); } notificationPreferences.getBoatClassPreferences().setBoatClasses(preferences); - userProfilePresenter.getClientFactory().getUserService().setPreference( - NotificationPreferences.PREF_NAME, notificationPreferences); + UserProfilePreferencesPresenter.this.persistNotificationPreferences(); } } - private class CompetitorSuggestedMultiSelectionDataProviderImpl - extends AbstractCompetitorSuggestedMultiSelectionDataProvider { + private class SuggestedMultiSelectionCompetitorDataProviderImpl + extends AbstractSuggestedMultiSelectionCompetitorDataProvider { @Override protected void getSuggestions(Iterable queryTokens, int limit, @@ -155,14 +158,13 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi @Override public void persist(Collection selectedItems) { - GWT.debugger(); List preferences = new ArrayList<>(); for (SimpleCompetitorWithIdDTO competitor : selectedItems) { - preferences.add(new CompetitorNotificationPreference(competitor.getIdAsString(), isNotifyAboutResults())); + preferences.add(new CompetitorNotificationPreference( + competitor.getIdAsString(), isNotifyAboutResults())); } notificationPreferences.getCompetitorPreferences().setCompetitors(preferences); - userProfilePresenter.getClientFactory().getUserService().setPreference( - NotificationPreferences.PREF_NAME, notificationPreferences); + UserProfilePreferencesPresenter.this.persistNotificationPreferences(); } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index 5a19d431691..6c592e89f26 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -1,8 +1,8 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; import com.google.gwt.user.client.ui.IsWidget; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.BoatClassSuggestedMultiSelectionDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; @@ -13,8 +13,8 @@ public interface UserProfilePreferencesView extends IsWidget { NeedsAuthenticationContext getDecorator(); public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext { - BoatClassSuggestedMultiSelectionDataProvider getFavoriteBoatClassesDataProvider(); - CompetitorSuggestedMultiSelectionDataProvider getFavoriteCompetitorsDataProvider(); + SuggestedMultiSelectionBoatClassDataProvider getFavoriteBoatClassesDataProvider(); + SuggestedMultiSelectionCompetitorDataProvider getFavoriteCompetitorsDataProvider(); void start(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index af5f03db628..fb0e8c197a7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -11,10 +11,10 @@ import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.BoatClassSuggestedMultiSelectionDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection.NotificationCallback; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; @@ -46,11 +46,11 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro return decoratorUi; } - private class CompetitorDisplayImpl implements CompetitorSuggestedMultiSelectionDataProvider.Display { + private class CompetitorDisplayImpl implements SuggestedMultiSelectionCompetitorDataProvider.Display { private final SuggestedMultiSelection selectionUi; private final HasEnabled notifyAboutResultsUi; - private CompetitorDisplayImpl(final CompetitorSuggestedMultiSelectionDataProvider dataProvider) { + private CompetitorDisplayImpl(final SuggestedMultiSelectionCompetitorDataProvider dataProvider) { selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, "TODO Favourite competitors"); notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override @@ -58,7 +58,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro dataProvider.setNotifyAboutResults(enabled); } }, "TODO Email notification about new results"); - dataProvider.setDisplay(this); + dataProvider.addDisplay(this); } @Override @@ -72,12 +72,12 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro } } - private class BoatClassDisplayImpl implements BoatClassSuggestedMultiSelectionDataProvider.Display { + private class BoatClassDisplayImpl implements SuggestedMultiSelectionBoatClassDataProvider.Display { private final SuggestedMultiSelection selectionUi; private final HasEnabled notifyAboutUpcomingRacesUi; private final HasEnabled notifyAboutResultsUi; - private BoatClassDisplayImpl(final BoatClassSuggestedMultiSelectionDataProvider dataProvider) { + private BoatClassDisplayImpl(final SuggestedMultiSelectionBoatClassDataProvider dataProvider) { selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, "TODO Favourite boat classes"); notifyAboutUpcomingRacesUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override @@ -91,7 +91,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro dataProvider.setNotifyAboutResults(enabled); } }, "TODO Email notification about new results"); - dataProvider.setDisplay(this); + dataProvider.addDisplay(this); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractBoatClassSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java similarity index 87% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractBoatClassSuggestedMultiSelectionDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java index c2a3b1fc0d8..160b74bf8ab 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractBoatClassSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java @@ -8,9 +8,9 @@ import com.sap.sailing.domain.common.BoatClassMasterdata; import com.sap.sse.common.Util; import com.sap.sse.common.filter.AbstractListFilter; -public abstract class AbstractBoatClassSuggestedMultiSelectionDataProvider extends - AbstractSuggestedMultiSelectionDataProvider - implements BoatClassSuggestedMultiSelectionDataProvider { +public abstract class AbstractSuggestedMultiSelectionBoatClassDataProvider extends + AbstractSuggestedMultiSelectionDataProvider + implements SuggestedMultiSelectionBoatClassDataProvider { private boolean notifyAboutUpcomingRaces; private boolean notifyAboutResults; @@ -22,7 +22,7 @@ public abstract class AbstractBoatClassSuggestedMultiSelectionDataProvider exten } }; - protected AbstractBoatClassSuggestedMultiSelectionDataProvider() { + protected AbstractSuggestedMultiSelectionBoatClassDataProvider() { super(new ProvidesKey() { @Override public Object getKey(BoatClassMasterdata item) { @@ -42,7 +42,7 @@ public abstract class AbstractBoatClassSuggestedMultiSelectionDataProvider exten public void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults) { this.notifyAboutUpcomingRaces = notifyAboutUpcomingRaces; this.notifyAboutResults = notifyAboutResults; - if (display != null) { + for (SuggestedMultiSelectionBoatClassDataProvider.Display display : displays) { display.setNotifyAboutUpcomingRaces(notifyAboutUpcomingRaces); display.setNotifyAboutResults(notifyAboutResults); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractCompetitorSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java similarity index 70% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractCompetitorSuggestedMultiSelectionDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java index 735d3b6c332..d470a82a7a3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractCompetitorSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java @@ -3,13 +3,13 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -public abstract class AbstractCompetitorSuggestedMultiSelectionDataProvider extends - AbstractSuggestedMultiSelectionDataProvider - implements CompetitorSuggestedMultiSelectionDataProvider { +public abstract class AbstractSuggestedMultiSelectionCompetitorDataProvider extends + AbstractSuggestedMultiSelectionDataProvider + implements SuggestedMultiSelectionCompetitorDataProvider { private boolean notifyAboutResults; - protected AbstractCompetitorSuggestedMultiSelectionDataProvider() { + protected AbstractSuggestedMultiSelectionCompetitorDataProvider() { super(new ProvidesKey() { @Override public Object getKey(SimpleCompetitorWithIdDTO item) { @@ -21,7 +21,9 @@ public abstract class AbstractCompetitorSuggestedMultiSelectionDataProvider exte @Override public void initNotifications(boolean notifyAboutResults) { this.notifyAboutResults = notifyAboutResults; - if (display != null) display.setNotifyAboutResults(notifyAboutResults); + for (SuggestedMultiSelectionCompetitorDataProvider.Display display : displays) { + display.setNotifyAboutResults(notifyAboutResults); + } } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java index f669c6ed934..d98bda887f3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java @@ -3,8 +3,10 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.Display; @@ -14,15 +16,15 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider keyProvider; private final Map selectedItemsMap = new HashMap<>(); - protected D display; + protected Set displays = new HashSet<>(); protected AbstractSuggestedMultiSelectionDataProvider(ProvidesKey keyProvider) { this.keyProvider = keyProvider; } @Override - public void setDisplay(D display) { - this.display = display; + public void addDisplay(D display) { + this.displays.add(display); } @Override @@ -55,7 +57,9 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider { boolean isNotifyAboutUpcomingRaces(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/CompetitorSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java similarity index 84% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/CompetitorSuggestedMultiSelectionDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java index 5cd99e6c422..dc332e26322 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/CompetitorSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java @@ -1,9 +1,9 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.CompetitorSuggestedMultiSelectionDataProvider.Display; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider.Display; -public interface CompetitorSuggestedMultiSelectionDataProvider +public interface SuggestedMultiSelectionCompetitorDataProvider extends SuggestedMultiSelectionDataProvider { boolean isNotifyAboutResults(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java index cd2f51aa8ec..8cb1972713f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java @@ -15,7 +15,7 @@ public interface SuggestedMultiSelectionDataProvider> ex void getSuggestionItems(Iterable queryTokens, int limit, final SuggestionItemsCallback callback); - void setDisplay(D display); + void addDisplay(D display); void persist(); From 13467a2eee2d65cd937b0831b33f312d1aa40f2c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 10:37:43 +0200 Subject: [PATCH 126/259] Added tests to check that UserStore and MongoDB persistence is in sync --- .../test/UserStoreWithPersistenceTest.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java new file mode 100644 index 00000000000..b081c04ee30 --- /dev/null +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java @@ -0,0 +1,76 @@ +package com.sap.sse.security.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.net.UnknownHostException; + +import org.junit.Before; +import org.junit.Test; + +import com.mongodb.DB; +import com.mongodb.MongoException; +import com.sap.sse.mongodb.MongoDBConfiguration; +import com.sap.sse.mongodb.MongoDBService; +import com.sap.sse.security.shared.UserManagementException; +import com.sap.sse.security.userstore.mongodb.UserStoreImpl; +import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; + +/** + * Tests that the MongoDB persistence is always in sync with the {@link UserStore}. + */ +public class UserStoreWithPersistenceTest { + private final String username = "abc"; + private final String email = "anonymous@sapsailing.com"; + private final String prefKey = "pk"; + private final String prefValue = "pv"; + + private UserStoreImpl store; + + @Before + public void setUp() throws UnknownHostException, MongoException { + final MongoDBConfiguration dbConfiguration = MongoDBConfiguration.getDefaultTestConfiguration(); + final MongoDBService service = dbConfiguration.getService(); + DB db = service.getDB(); + db.getCollection(CollectionNames.USERS.name()).drop(); + db.getCollection(CollectionNames.SETTINGS.name()).drop(); + db.getCollection(CollectionNames.PREFERENCES.name()).drop(); + db.getCollection(CollectionNames.PREFERENCES.name()).drop(); + newStore(); + } + + private void newStore() { + store = new UserStoreImpl(); + } + + @Test + public void testCreateUser() throws UserManagementException { + store.createUser(username, email); + assertNotNull(store.getUserByName(username)); + assertNotNull(store.getUserByEmail(email)); + + newStore(); + assertNotNull(store.getUserByName(username)); + assertNotNull(store.getUserByEmail(email)); + } + + @Test + public void testSetPreferences() throws UserManagementException { + store.createUser(username, email); + store.setPreference(username, prefKey, prefValue); + assertEquals(prefValue, store.getPreference(username, prefKey)); + newStore(); + assertEquals(prefValue, store.getPreference(username, prefKey)); + } + + @Test + public void testUnsetPreferences() throws UserManagementException { + store.createUser(username, email); + store.setPreference(username, prefKey, prefValue); + store.unsetPreference(username, prefKey); + assertNull(store.getPreference(username, prefKey)); + newStore(); + assertNull(store.getPreference(username, prefKey)); + } +} From 7ecc533f8e74819ecdf6850ad3a33ee1662cd418 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 10:38:53 +0200 Subject: [PATCH 127/259] Added a failing test to verify that getUserByEmail currently throws a NullPointerException if there is no user for a given email address --- .../test/UserStoreWithPersistenceTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java index b081c04ee30..a155bfcef03 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java @@ -55,6 +55,22 @@ public class UserStoreWithPersistenceTest { assertNotNull(store.getUserByEmail(email)); } + /** + * There was a {@link NullPointerException} thrown if calling getUserByEmail for an email address for which there + * wasn't an associated user. + */ + @Test + public void testDeleteUser() throws UserManagementException { + store.createUser(username, email); + store.deleteUser(username); + assertNull(store.getUserByName(username)); + assertNull(store.getUserByEmail(email)); + + newStore(); + assertNull(store.getUserByName(username)); + assertNull(store.getUserByEmail(email)); + } + @Test public void testSetPreferences() throws UserManagementException { store.createUser(username, email); From 5004b250f04c7b20e22b92de75672809ebf98348 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 10:40:34 +0200 Subject: [PATCH 128/259] Added a null check to prevent a NullPointerException to be thrown in getUserByEmail if there is no user for a given email address --- .../com/sap/sse/security/userstore/mongodb/UserStoreImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 6cfb672df8d..a050f28645a 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -320,7 +320,7 @@ public class UserStoreImpl implements UserStore { result = null; } else { Set set = usersByEmail.get(email); - if (set.isEmpty()) { + if (set == null || set.isEmpty()) { result = null; } else { result = set.iterator().next(); From aaa04bb2fb662d9a1fc94b1f58e3846f40257b67 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 10:41:28 +0200 Subject: [PATCH 129/259] Added failing tests to verify that preferences are currently not correctly removed when a user is being deleted --- ...PreferenceObjectBasedNotificationSetTest.java | 15 +++++++++++++++ .../UserPreferenceObjectAndConverterTest.java | 16 +++++++++++++++- .../test/UserStoreWithPersistenceTest.java | 14 ++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 9a74a1c896d..ab11ec7d336 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -212,6 +212,21 @@ public class PreferenceObjectBasedNotificationSetTest { Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); } + /** + * There was a bug that caused the preferences not to be removed when a user was deleted. + */ + @Test + public void deleteUserWithMappingTest() throws UserManagementException { + store.createUser(user1, mail); + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + store.deleteUser(user1); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); + } + private static HashSet values(String... values) { return new HashSet<>(Arrays.asList(values)); } diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java index 0bf83a0560f..01a30f1be44 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java @@ -10,6 +10,7 @@ import com.mongodb.DB; import com.mongodb.MongoException; import com.sap.sse.mongodb.MongoDBConfiguration; import com.sap.sse.mongodb.MongoDBService; +import com.sap.sse.security.shared.UserManagementException; import com.sap.sse.security.userstore.mongodb.UserStoreImpl; import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; @@ -18,7 +19,8 @@ import junit.framework.Assert; public class UserPreferenceObjectAndConverterTest { private UserStoreImpl store; - + + private final String email = "anonymous@sapsailing.com"; private String user1 = "me"; private String user2 = "somebody_else"; @@ -104,6 +106,18 @@ public class UserPreferenceObjectAndConverterTest { store.setPreferenceObject(user1, prefKey1, null); Assert.assertEquals(null, store.getPreferenceObject(user1, prefKey1)); } + + /** + * There was a bug that caused the preferences not to be removed when a user was deleted. + */ + @Test + public void deleteUserWithPreferenceObjectTest() throws UserManagementException { + store.createUser(user1, email); + store.registerPreferenceConverter(prefKey1, prefConverter); + store.setPreferenceObject(user1, prefKey1, pref1); + store.deleteUser(user1); + Assert.assertNull(store.getPreferenceObject(user1, prefKey1)); + } public static class SimplePreferenceForSerialization implements Serializable { private static final long serialVersionUID = -580569932709860895L; diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java index a155bfcef03..d5d9d77c397 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java @@ -13,6 +13,7 @@ import com.mongodb.DB; import com.mongodb.MongoException; import com.sap.sse.mongodb.MongoDBConfiguration; import com.sap.sse.mongodb.MongoDBService; +import com.sap.sse.security.UserStore; import com.sap.sse.security.shared.UserManagementException; import com.sap.sse.security.userstore.mongodb.UserStoreImpl; import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; @@ -89,4 +90,17 @@ public class UserStoreWithPersistenceTest { newStore(); assertNull(store.getPreference(username, prefKey)); } + + /** + * There was a bug that caused the preferences not to be removed when a user was deleted. + */ + @Test + public void testDeleteUserWithPreferences() throws UserManagementException { + store.createUser(username, email); + store.setPreference(username, prefKey, prefValue); + store.deleteUser(username); + assertNull(store.getPreference(username, prefKey)); + newStore(); + assertNull(store.getPreference(username, prefKey)); + } } From e876d456a46d243c2f0345a7e049b6c605f0285c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 10:41:57 +0200 Subject: [PATCH 130/259] Preferences are now removed if a user is deleted --- .../userstore/mongodb/UserStoreImpl.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index a050f28645a..11062a4304d 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -401,6 +401,7 @@ public class UserStoreImpl implements UserStore { mongoObjectFactory.deleteUser(users.get(name)); } removeFromUsersByEmail(users.remove(name)); + removeAllPreferencesForUser(name); } @Override @@ -499,6 +500,25 @@ public class UserStoreImpl implements UserStore { return result; } + private void removeAllPreferencesForUser(String username) { + // TODO should we keep the preferences anonymized (e.g. use a UUID as username) to enable better statistics? + synchronized (preferences) { + preferences.remove(username); + } + if (mongoObjectFactory != null) { + mongoObjectFactory.storePreferences(username, Collections.emptyMap()); + } + Map preferenceObjectsToRemove; + synchronized (preferenceObjects) { + preferenceObjectsToRemove = preferenceObjects.remove(username); + } + if(preferenceObjectsToRemove != null) { + for(Map.Entry entry: preferenceObjectsToRemove.entrySet()) { + notifyListenersOnPreferenceObjectChange(username, entry.getKey(), entry.getValue(), null); + } + } + } + @Override public Map getAllSettings() { return settings; @@ -564,7 +584,9 @@ public class UserStoreImpl implements UserStore { Map userObjectMap = preferenceObjects.get(username); if (userObjectMap != null) { Object oldPreference = userObjectMap.remove(key); - notifyListenersOnPreferenceObjectChange(username, key, oldPreference, null); + if(oldPreference != null) { + notifyListenersOnPreferenceObjectChange(username, key, oldPreference, null); + } } } From 9475d30ef28e2367e220eb1375d32d61f6d111d2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 10:43:53 +0200 Subject: [PATCH 131/259] Added new test case regarding correct removal of preferences on user deletion --- .../src/com/sap/sse/security/test/UserStoreTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java index 2b4c91673e4..48d3cc91552 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java @@ -41,4 +41,10 @@ public class UserStoreTest { assertEquals(prefValue, newUserStore.getPreference(username, prefKey)); assertEquals(username, newUserStore.getUserByAccessToken(accessToken).getName()); } + + @Test + public void testDeleteUserWithPreference() throws UserManagementException { + userStore.unsetPreference(username, prefKey); + assertNull(prefValue, userStore.getPreference(username, prefKey)); + } } From d9ac7d5ab8ad73fbd424c74ae5a187ab225f6b86 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 10:48:36 +0200 Subject: [PATCH 132/259] Code quality improvements for several tests --- ...ferenceObjectBasedNotificationSetTest.java | 18 +++++++-------- .../UserPreferenceObjectAndConverterTest.java | 22 +++++++++---------- .../sap/sse/security/test/UserStoreTest.java | 3 +++ 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index ab11ec7d336..20e8b8647de 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -31,16 +31,16 @@ public class PreferenceObjectBasedNotificationSetTest { private UserStoreImpl store; - private String user1 = "me"; - private String user2 = "somebody_else"; - private String mail = "anonymous@sapsailing.com"; + private static final String user1 = "me"; + private static final String user2 = "somebody_else"; + private static final String mail = "anonymous@sapsailing.com"; - private JavaIoSerializablePreferenceConverter> prefConverter = new JavaIoSerializablePreferenceConverter<>(); - private String prefKey = "prefKey"; - private String otherPrefKey = "otherPrefKey"; - private HashSet values1 = values(A, B); - private HashSet values2 = values(B, C); - private HashSet allValues = values(A, B, C); + private static final JavaIoSerializablePreferenceConverter> prefConverter = new JavaIoSerializablePreferenceConverter<>(); + private static final String prefKey = "prefKey"; + private static final String otherPrefKey = "otherPrefKey"; + private static final HashSet values1 = values(A, B); + private static final HashSet values2 = values(B, C); + private static final HashSet allValues = values(A, B, C); @Before public void setUp() throws UnknownHostException, MongoException { diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java index 01a30f1be44..e07beeba608 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java @@ -21,16 +21,16 @@ public class UserPreferenceObjectAndConverterTest { private UserStoreImpl store; private final String email = "anonymous@sapsailing.com"; - private String user1 = "me"; - private String user2 = "somebody_else"; + private static final String user1 = "me"; + private static final String user2 = "somebody_else"; - private JavaIoSerializablePreferenceConverter prefConverter = new JavaIoSerializablePreferenceConverter<>(); - private String prefKey1 = "prefKey1"; - private SimplePreferenceForSerialization pref1 = new SimplePreferenceForSerialization("test12345", false, 432.567); - private String serializedPref1 = prefConverter.toPreferenceString(pref1); - private String prefKey2 = "prefKey2"; - private SimplePreferenceForSerialization pref2 = new SimplePreferenceForSerialization("some sailing value", true, 9.87654321); - private String serializedPref2 = prefConverter.toPreferenceString(pref2); + private static final JavaIoSerializablePreferenceConverter prefConverter = new JavaIoSerializablePreferenceConverter<>(); + private static final String prefKey1 = "prefKey1"; + private static final SimplePreferenceForSerialization pref1 = new SimplePreferenceForSerialization("test12345", false, 432.567); + private static final String serializedPref1 = prefConverter.toPreferenceString(pref1); + private static final String prefKey2 = "prefKey2"; + private static final SimplePreferenceForSerialization pref2 = new SimplePreferenceForSerialization("some sailing value", true, 9.87654321); + private static final String serializedPref2 = prefConverter.toPreferenceString(pref2); @Before public void setUp() throws UnknownHostException, MongoException { @@ -96,7 +96,7 @@ public class UserPreferenceObjectAndConverterTest { store.registerPreferenceConverter(prefKey1, prefConverter); store.setPreferenceObject(user1, prefKey1, pref1); store.unsetPreference(user1, prefKey1); - Assert.assertEquals(null, store.getPreferenceObject(user1, prefKey1)); + Assert.assertNull(store.getPreferenceObject(user1, prefKey1)); } @Test @@ -104,7 +104,7 @@ public class UserPreferenceObjectAndConverterTest { store.registerPreferenceConverter(prefKey1, prefConverter); store.setPreferenceObject(user1, prefKey1, pref1); store.setPreferenceObject(user1, prefKey1, null); - Assert.assertEquals(null, store.getPreferenceObject(user1, prefKey1)); + Assert.assertNull(store.getPreferenceObject(user1, prefKey1)); } /** diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java index 48d3cc91552..0f6b1531b99 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java @@ -42,6 +42,9 @@ public class UserStoreTest { assertEquals(username, newUserStore.getUserByAccessToken(accessToken).getName()); } + /** + * There was a bug that caused the preferences not to be removed when a user was deleted. + */ @Test public void testDeleteUserWithPreference() throws UserManagementException { userStore.unsetPreference(username, prefKey); From d72221ab28af4ef863b36921a5a8e9d109220202 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 7 Jul 2016 11:36:13 +0200 Subject: [PATCH 133/259] Moved mobile user profile details classes into their own package --- .../mobile/places/user/profile/UserProfileActivityProxy.java | 1 + .../user/profile/{ => details}/UserProfileDetailsActivity.java | 2 +- .../user/profile/{ => details}/UserProfileDetailsView.java | 2 +- .../user/profile/{ => details}/UserProfileDetailsViewImpl.java | 2 +- .../profile/{ => details}/UserProfileDetailsViewImpl.ui.xml | 0 5 files changed, 4 insertions(+), 3 deletions(-) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/{ => details}/UserProfileDetailsActivity.java (96%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/{ => details}/UserProfileDetailsView.java (87%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/{ => details}/UserProfileDetailsViewImpl.java (96%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/{ => details}/UserProfileDetailsViewImpl.ui.xml (100%) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java index 714c480ecce..1a00d8b37ac 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java @@ -2,6 +2,7 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile; import com.google.gwt.core.client.GWT; import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; +import com.sap.sailing.gwt.home.mobile.places.user.profile.details.UserProfileDetailsActivity; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sse.gwt.client.mvp.AbstractActivityProxy; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsActivity.java similarity index 96% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsActivity.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsActivity.java index c723488bbb0..e23e4a1dd79 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsActivity.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.mobile.places.user.profile; +package com.sap.sailing.gwt.home.mobile.places.user.profile.details; import com.google.gwt.activity.shared.AbstractActivity; import com.google.gwt.event.shared.EventBus; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsView.java similarity index 87% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsView.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsView.java index c7bce74050d..09b818447c7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsView.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.mobile.places.user.profile; +package com.sap.sailing.gwt.home.mobile.places.user.profile.details; import com.google.gwt.user.client.ui.IsWidget; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.java similarity index 96% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsViewImpl.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.java index 7e8dea11d35..61554825f04 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.mobile.places.user.profile; +package com.sap.sailing.gwt.home.mobile.places.user.profile.details; import com.google.gwt.core.client.GWT; import com.google.gwt.uibinder.client.UiBinder; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.ui.xml similarity index 100% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileDetailsViewImpl.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.ui.xml From 5142bfe64992e7b3f113f70887a34ef2702d084c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 7 Jul 2016 15:05:50 +0200 Subject: [PATCH 134/259] I18n for user profile preferences --- .../UserProfilePreferencesViewImpl.java | 11 ++++++----- .../com/sap/sailing/gwt/ui/client/StringMessages.java | 4 ++++ .../sailing/gwt/ui/client/StringMessages.properties | 6 +++++- .../gwt/ui/client/StringMessages_de.properties | 4 ++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index fb0e8c197a7..8d5303fd9d4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -16,6 +16,7 @@ import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedM import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop; +import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; public class UserProfilePreferencesViewImpl extends Composite implements UserProfilePreferencesView { @@ -51,13 +52,13 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro private final HasEnabled notifyAboutResultsUi; private CompetitorDisplayImpl(final SuggestedMultiSelectionCompetitorDataProvider dataProvider) { - selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, "TODO Favourite competitors"); + selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, StringMessages.INSTANCE.favouriteCompetitors()); notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override public void onNotificationToggled(boolean enabled) { dataProvider.setNotifyAboutResults(enabled); } - }, "TODO Email notification about new results"); + }, StringMessages.INSTANCE.notificationAboutNewResults()); dataProvider.addDisplay(this); } @@ -78,19 +79,19 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro private final HasEnabled notifyAboutResultsUi; private BoatClassDisplayImpl(final SuggestedMultiSelectionBoatClassDataProvider dataProvider) { - selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, "TODO Favourite boat classes"); + selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, StringMessages.INSTANCE.favouriteBoatClasses()); notifyAboutUpcomingRacesUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override public void onNotificationToggled(boolean enabled) { dataProvider.setNotifyAboutUpcomingRaces(enabled); } - }, "TODO Email notification about upcoming races"); + }, StringMessages.INSTANCE.notificationAboutUpcomingRaces()); notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override public void onNotificationToggled(boolean enabled) { dataProvider.setNotifyAboutResults(enabled); } - }, "TODO Email notification about new results"); + }, StringMessages.INSTANCE.notificationAboutNewResults()); dataProvider.addDisplay(this); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index dd5ee23e706..d4a09d5b7e3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1614,4 +1614,8 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String enabled(); String disabled(); String favouritesAndNotifications(); + String favouriteCompetitors(); + String favouriteBoatClasses(); + String notificationAboutNewResults(); + String notificationAboutUpcomingRaces(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 2382419671f..60293bd4e8c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1586,4 +1586,8 @@ showWindChart=Show wind chart userNotificationsOnlyIfMailAddressIsVerified=Due to privacy reasons, mail notifications require that you enter your mail address on the user profile page and verify this mail address. enabled=Enabled disabled=Disabled -favouritesAndNotifications=Favourites/Notifications \ No newline at end of file +favouritesAndNotifications=Favourites/Notifications +favouriteCompetitors=Favourite competitors +favouriteBoatClasses=Favourite boat classes +notificationAboutNewResults=Send notifications about new results +notificationAboutUpcomingRaces=Send notifications about upcoming races diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index d0b902f927d..67a20255c3b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1572,3 +1572,7 @@ userNotificationsOnlyIfMailAddressIsVerified=Aus Gründen des Datenschutzes kön enabled=Aktiviert disabled=Deaktiviert favouritesAndNotifications=Favoriten/Benachrichtigungen +favouriteCompetitors=Favorisierte Teilnehmer +favouriteBoatClasses=Favorisierte Bootsklassen +notificationAboutNewResults=Über neue Ergebnisse informieren +notificationAboutUpcomingRaces=Über demnächst stattfindende Rennen informieren From adf898a73b0003c90d23d44956ece5213eb18455 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Fri, 8 Jul 2016 09:59:25 +0200 Subject: [PATCH 135/259] First version of user profile preferences page for mobile devices --- .../profile/UserProfileActivityProxy.java | 9 +- .../UserProfilePreferencesActivity.java | 174 ++++++++++++++++++ .../UserProfilePreferencesView.java | 16 ++ .../UserProfilePreferencesViewImpl.java | 116 ++++++++++++ .../UserProfilePreferencesViewImpl.ui.xml | 34 ++++ 5 files changed, 348 insertions(+), 1 deletion(-) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java index 1a00d8b37ac..f1ec14b8b7d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java @@ -3,7 +3,9 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile; import com.google.gwt.core.client.GWT; import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; import com.sap.sailing.gwt.home.mobile.places.user.profile.details.UserProfileDetailsActivity; +import com.sap.sailing.gwt.home.mobile.places.user.profile.preferences.UserProfilePreferencesActivity; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; +import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; import com.sap.sse.gwt.client.mvp.AbstractActivityProxy; public class UserProfileActivityProxy extends AbstractActivityProxy { @@ -21,7 +23,12 @@ public class UserProfileActivityProxy extends AbstractActivityProxy { GWT.runAsync(new AbstractRunAsyncCallback() { @Override public void onSuccess() { - super.onSuccess(new UserProfileDetailsActivity(currentPlace, clientFactory)); + if (currentPlace instanceof UserProfilePreferencesPlace) { + UserProfilePreferencesPlace userProfilePrefsPlace = (UserProfilePreferencesPlace) currentPlace; + super.onSuccess(new UserProfilePreferencesActivity(userProfilePrefsPlace, clientFactory)); + } else { + super.onSuccess(new UserProfileDetailsActivity(currentPlace, clientFactory)); + } } }); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java new file mode 100644 index 00000000000..44497d091a8 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java @@ -0,0 +1,174 @@ +package com.sap.sailing.gwt.home.mobile.places.user.profile.preferences; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.google.gwt.activity.shared.AbstractActivity; +import com.google.gwt.event.shared.EventBus; +import com.google.gwt.user.client.Window; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.AcceptsOneWidget; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; +import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreferences; +import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; +import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreferences; +import com.sap.sailing.domain.common.preferences.NotificationPreferences; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sailing.gwt.home.communication.user.profile.CompetitorSuggestionResult; +import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggestionAction; +import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorsAction; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; +import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; +import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; +import com.sap.sse.security.ui.authentication.AuthenticationContextEvent; +import com.sap.sse.security.ui.client.UserService; + +public class UserProfilePreferencesActivity extends AbstractActivity implements UserProfilePreferencesView.Presenter { + + private final MobileApplicationClientFactory clientFactory; + private final UserProfilePreferencesView currentView;; + private final SuggestedMultiSelectionCompetitorDataProvider competitorDataProvider = + new SuggestedMultiSelectionCompetitorDataProviderImpl(); + private final SuggestedMultiSelectionBoatClassDataProvider boatClassDataProvider = + new SuggestedMultiSelectionBoatClassDataProviderImpl(); + + private NotificationPreferences notificationPreferences; + + public UserProfilePreferencesActivity(UserProfilePreferencesPlace place, MobileApplicationClientFactory clientFactory) { + this.clientFactory = clientFactory; + this.currentView = new UserProfilePreferencesViewImpl(this); + } + + @Override + public void start(final AcceptsOneWidget panel, final EventBus eventBus) { + panel.setWidget(currentView); + currentView.setAuthenticationContext(clientFactory.getAuthenticationManager().getAuthenticationContext()); + eventBus.addHandler(AuthenticationContextEvent.TYPE, new AuthenticationContextEvent.Handler() { + @Override + public void onUserChangeEvent(AuthenticationContextEvent event) { + currentView.setAuthenticationContext(event.getCtx()); + } + }); + + clientFactory.getUserService().getPreference(NotificationPreferences.PREF_NAME, + new NotificationPreferences(), new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + clientFactory.createErrorView("Error while loading notification preferences!", caught); + } + + @Override + public void onSuccess(NotificationPreferences result) { + notificationPreferences = result; + initFavoriteCompetitors(result.getCompetitorPreferences()); + initFavoriteBoatClasses(result.getBoatClassPreferences()); + } + }); + } + + private void initFavoriteCompetitors(CompetitorNotificationPreferences preferences) { + boolean initialNotifyAboutResults = false; + List favoriteCompetitorIds = new ArrayList<>(); + for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { + favoriteCompetitorIds.add(pref.getCompetitorId()); + initialNotifyAboutResults |= pref.isNotifyAboutResults(); + } + competitorDataProvider.initNotifications(initialNotifyAboutResults); + clientFactory.getDispatch().execute(new GetCompetitorsAction(favoriteCompetitorIds), + new AsyncCallback>() { + @Override + public void onFailure(Throwable caught) { + clientFactory.createErrorView("Error while loading notification preferences!", caught); + } + + @Override + public void onSuccess(SortedSetResult result) { + competitorDataProvider.initSelectedItems(result.getValues()); + } + }); + } + + private void initFavoriteBoatClasses(BoatClassNotificationPreferences preferences) { + boolean initialNotifyAboutResults = false, initialNotifyAboutUpcomingRaces = false; + List favoriteBoatClasses = new ArrayList<>(); + for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { + favoriteBoatClasses.add(pref.getBoatClass()); + initialNotifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); + initialNotifyAboutResults |= pref.isNotifyAboutResults(); + } + boatClassDataProvider.initSelectedItems(favoriteBoatClasses); + boatClassDataProvider.initNotifications(initialNotifyAboutUpcomingRaces, initialNotifyAboutResults); + } + + private void persistNotificationPreferences() { + UserService userService = clientFactory.getUserService(); + userService.setPreference(NotificationPreferences.PREF_NAME, notificationPreferences); + } + + @Override + public void doTriggerLoginForm() { + clientFactory.getNavigator().getSignInNavigation().goToPlace(); + } + + @Override + public SuggestedMultiSelectionBoatClassDataProvider getFavoriteBoatClassesDataProvider() { + return boatClassDataProvider; + } + + @Override + public SuggestedMultiSelectionCompetitorDataProvider getFavoriteCompetitorsDataProvider() { + return competitorDataProvider; + } + + private class SuggestedMultiSelectionBoatClassDataProviderImpl + extends AbstractSuggestedMultiSelectionBoatClassDataProvider { + @Override + public void persist(Collection selectedItems) { + List preferences = new ArrayList<>(); + for (BoatClassMasterdata boatClass : selectedItems) { + preferences.add(new BoatClassNotificationPreference(boatClass, + isNotifyAboutUpcomingRaces(), isNotifyAboutResults())); + } + notificationPreferences.getBoatClassPreferences().setBoatClasses(preferences); + UserProfilePreferencesActivity.this.persistNotificationPreferences(); + } + } + + private class SuggestedMultiSelectionCompetitorDataProviderImpl + extends AbstractSuggestedMultiSelectionCompetitorDataProvider { + + @Override + protected void getSuggestions(Iterable queryTokens, int limit, + final SuggestionItemsCallback callback) { + clientFactory.getDispatch().execute(new GetCompetitorSuggestionAction(queryTokens, limit), + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Window.alert("Error while loading competitor suggestion"); + } + + @Override + public void onSuccess(CompetitorSuggestionResult result) { + callback.setSuggestionItems(result.getValues()); + } + }); + } + + @Override + public void persist(Collection selectedItems) { + List preferences = new ArrayList<>(); + for (SimpleCompetitorWithIdDTO competitor : selectedItems) { + preferences.add(new CompetitorNotificationPreference( + competitor.getIdAsString(), isNotifyAboutResults())); + } + notificationPreferences.getCompetitorPreferences().setCompetitors(preferences); + UserProfilePreferencesActivity.this.persistNotificationPreferences(); + } + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java new file mode 100644 index 00000000000..7597ea3ec17 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java @@ -0,0 +1,16 @@ +package com.sap.sailing.gwt.home.mobile.places.user.profile.preferences; + +import com.google.gwt.user.client.ui.IsWidget; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; +import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; + +public interface UserProfilePreferencesView extends IsWidget, NeedsAuthenticationContext { + + public interface Presenter extends NotLoggedInPresenter { + SuggestedMultiSelectionBoatClassDataProvider getFavoriteBoatClassesDataProvider(); + SuggestedMultiSelectionCompetitorDataProvider getFavoriteCompetitorsDataProvider(); + } +} + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java new file mode 100644 index 00000000000..b5bbb36b4d3 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java @@ -0,0 +1,116 @@ +package com.sap.sailing.gwt.home.mobile.places.user.profile.preferences; + +import java.util.Collection; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.DivElement; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HasEnabled; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.gwt.common.client.SharedResources; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection.NotificationCallback; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorMobile; +import com.sap.sailing.gwt.ui.client.StringMessages; +import com.sap.sse.security.ui.authentication.app.AuthenticationContext; +import com.sap.sse.security.ui.userprofile.mobile.userheader.UserHeader; + +public class UserProfilePreferencesViewImpl extends Composite implements UserProfilePreferencesView { + private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); + + interface MyUiBinder extends UiBinder { + } + + private final StringMessages i18n = StringMessages.INSTANCE; + @UiField(provided = true) final UserHeader userHeaderUi; + @UiField(provided = true) final AuthorizedContentDecoratorMobile decoratorUi; + @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; + @UiField DivElement notificationsTextUi; + + public UserProfilePreferencesViewImpl(Presenter presenter) { + userHeaderUi = new UserHeader(SharedResources.INSTANCE); + decoratorUi = new AuthorizedContentDecoratorMobile(presenter); + favoriteCompetitorsSelctionUi = new CompetitorDisplayImpl( + presenter.getFavoriteCompetitorsDataProvider()).selectionUi; + favoriteBoatClassesSelctionUi = new BoatClassDisplayImpl( + presenter.getFavoriteBoatClassesDataProvider()).selectionUi; + initWidget(uiBinder.createAndBindUi(this)); + } + + @Override + public void setAuthenticationContext(AuthenticationContext authenticationContext) { + userHeaderUi.setAuthenticationContext(authenticationContext); + decoratorUi.setAuthenticationContext(authenticationContext); + } + + private class CompetitorDisplayImpl implements SuggestedMultiSelectionCompetitorDataProvider.Display { + private final SuggestedMultiSelection selectionUi; + private final HasEnabled notifyAboutResultsUi; + + private CompetitorDisplayImpl(final SuggestedMultiSelectionCompetitorDataProvider dataProvider) { + selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, i18n.favouriteCompetitors()); + notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { + @Override + public void onNotificationToggled(boolean enabled) { + dataProvider.setNotifyAboutResults(enabled); + } + }, i18n.notificationAboutNewResults()); + dataProvider.addDisplay(this); + } + + @Override + public void setSelectedItems(Collection selectedItems) { + selectionUi.setSelectedItems(selectedItems); + } + + @Override + public void setNotifyAboutResults(boolean notifyAboutResults) { + notifyAboutResultsUi.setEnabled(notifyAboutResults); + } + } + + private class BoatClassDisplayImpl implements SuggestedMultiSelectionBoatClassDataProvider.Display { + private final SuggestedMultiSelection selectionUi; + private final HasEnabled notifyAboutUpcomingRacesUi; + private final HasEnabled notifyAboutResultsUi; + + private BoatClassDisplayImpl(final SuggestedMultiSelectionBoatClassDataProvider dataProvider) { + selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, i18n.favouriteBoatClasses()); + notifyAboutUpcomingRacesUi = selectionUi.addNotificationToggle(new NotificationCallback() { + @Override + public void onNotificationToggled(boolean enabled) { + dataProvider.setNotifyAboutUpcomingRaces(enabled); + } + }, i18n.notificationAboutUpcomingRaces()); + notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { + @Override + public void onNotificationToggled(boolean enabled) { + dataProvider.setNotifyAboutResults(enabled); + } + }, i18n.notificationAboutNewResults()); + dataProvider.addDisplay(this); + } + + @Override + public void setSelectedItems(Collection selectedItems) { + selectionUi.setSelectedItems(selectedItems); + } + + @Override + public void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces) { + notifyAboutUpcomingRacesUi.setEnabled(notifyAboutUpcomingRaces); + } + + @Override + public void setNotifyAboutResults(boolean notifyAboutResults) { + notifyAboutResultsUi.setEnabled(notifyAboutResults); + } + } +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml new file mode 100644 index 00000000000..f12a62fdf6f --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml @@ -0,0 +1,34 @@ + + + + + + .edgeToEdge { + border-radius: 0; + border-left: none; + border-right: none; + } + + + + + + +
        + +
        +
        + +
        +
        + +
        +
        +
        +
        +
        +
        From b5524aefde891e8054c355d58a4f0ed8f41f2093 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 09:38:17 +0200 Subject: [PATCH 136/259] JavaDoc / Code quality improvements --- .../common/preferences/NotificationPreferences.java | 6 +++--- .../sap/sse/security/userstore/mongodb/UserStoreImpl.java | 8 ++++---- .../src/com/sap/sse/security/UserStore.java | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java index f4939589b1a..d70311a18bb 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java @@ -6,9 +6,9 @@ import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; * Preferences for Sailing users that define for which Objects a user wants to receive specific notifications. * This currently includes: *
          - *
        • Results for a favourite Competitor
        • - *
        • Results for a favourite BoatClass
        • - *
        • Upcoming races for a favourite BoatClass
        • + *
        • Results for a favorite Competitor
        • + *
        • Results for a favorite BoatClass
        • + *
        • Upcoming races for a favorite BoatClass
        • *
        */ public class NotificationPreferences extends AbstractGenericSerializableSettings { diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 11062a4304d..7d5dae1602b 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -68,7 +68,7 @@ public class UserStoreImpl implements UserStore { */ private final ConcurrentHashMap> preferenceObjects; - private transient Map>> listeners; + private transient Map>> listeners; /** * Won't be serialized and remains null on the de-serializing end. @@ -532,8 +532,8 @@ public class UserStoreImpl implements UserStore { @Override public void registerPreferenceConverter(String preferenceKey, PreferenceConverter converter) { PreferenceConverter alreadyAssociatedConverter = preferenceConverters.putIfAbsent(preferenceKey, converter); - - if(alreadyAssociatedConverter == null) { + + if (alreadyAssociatedConverter == null) { final Set usersToProcess = new HashSet<>(preferences.keySet()); for (String user : usersToProcess) { loadPreferenceWithConverter(user, preferenceKey, converter); @@ -605,7 +605,7 @@ public class UserStoreImpl implements UserStore { } @Override - public void setPreferenceObject(String username, String key, Object preferenceObject) + public void setPreferenceObject(String username, String key, Object preferenceObject) throws IllegalArgumentException { @SuppressWarnings("unchecked") PreferenceConverter preferenceConverter = (PreferenceConverter) preferenceConverters.get(key); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index b47c7227075..672fa71ef0e 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -76,7 +76,7 @@ public interface UserStore extends Named { * * @throws IllegalArgumentException if there is no {@link PreferenceConverter} registered with the given key. */ - void setPreferenceObject(String username, String key, Object preferenceObject) throws IllegalArgumentException; + void setPreferenceObject(String username, String key, Object preferenceObject) throws IllegalArgumentException; /** * Sets a value for a key if that key was previously added to this store using {@link #addSetting(String, Class)}. From d85ab8b4709bdf9cfe1278c95e31a28968dfad31 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 10:50:19 +0200 Subject: [PATCH 137/259] The NotificationPreferences are now backend specific by using lookup mechanisms for BoatClasses and Competitors. With this the NotificationPreferences can't be used in the GWT UI anymore. Currently the UI doesn't compile -> this needs to be fixed in a subsequent commit --- .../META-INF/MANIFEST.MF | 1 - .../BoatClassNotificationPreferences.java | 36 ----------- .../common/preferences/BoatClassSetting.java | 58 ------------------ .../CompetitorNotificationPreference.java | 34 ----------- .../CompetitorNotificationPreferences.java | 36 ----------- .../sap/sailing/server/impl/Activator.java | 5 +- .../AbstractBoatClassNotificationSet.java | 12 ++-- .../AbstractCompetitorNotificationSet.java | 14 ++--- .../BoatClassResultsNotificationSet.java | 2 +- .../BoatClassUpcomingRaceNotificationSet.java | 2 +- .../CompetitorResultsNotificationSet.java | 2 +- .../BoatClassNotificationPreference.java | 38 +++++++----- .../BoatClassNotificationPreferences.java | 35 +++++++++++ .../preferences/model/BoatClassSetting.java | 59 ++++++++++++++++++ .../CompetitorNotificationPreference.java | 42 +++++++++++++ .../CompetitorNotificationPreferences.java | 35 +++++++++++ .../preferences/model/CompetitorSetting.java | 60 +++++++++++++++++++ .../model}/NotificationPreferences.java | 14 +++-- 18 files changed, 283 insertions(+), 202 deletions(-) delete mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java delete mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java delete mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java delete mode 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java rename java/{com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences => com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model}/BoatClassNotificationPreference.java (52%) create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassSetting.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorSetting.java rename java/{com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences => com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model}/NotificationPreferences.java (59%) diff --git a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF index 66913ee2003..c058553927b 100644 --- a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF @@ -14,7 +14,6 @@ Export-Package: com.sap.sailing.domain.common, com.sap.sailing.domain.common.i18n, com.sap.sailing.domain.common.impl, com.sap.sailing.domain.common.media, - com.sap.sailing.domain.common.preferences, com.sap.sailing.domain.common.quadtree, com.sap.sailing.domain.common.quadtree.impl;x-friends:="com.sap.sailing.domain.test", com.sap.sailing.domain.common.racelog, diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java deleted file mode 100644 index e2c0b05a1a6..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreferences.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.sap.sailing.domain.common.preferences; - -import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; -import com.sap.sse.common.settings.generic.SettingsFactory; -import com.sap.sse.common.settings.generic.SettingsList; - -public class BoatClassNotificationPreferences extends AbstractGenericSerializableSettings { - private static final long serialVersionUID = -3682996540081614053L; - - private transient SettingsList boatClasses; - - public BoatClassNotificationPreferences() { - } - - public BoatClassNotificationPreferences(String name, AbstractGenericSerializableSettings settings) { - super(name, settings); - } - - @Override - protected void addChildSettings() { - boatClasses = new SettingsList<>("boatClasses", this, new SettingsFactory() { - @Override - public BoatClassNotificationPreference newInstance() { - return new BoatClassNotificationPreference(); - } - }); - } - - public Iterable getBoatClasses() { - return boatClasses.getValues(); - } - - public void setBoatClasses(Iterable boatClasses) { - this.boatClasses.setValues(boatClasses); - } -} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java deleted file mode 100644 index 4967a995888..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassSetting.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.sap.sailing.domain.common.preferences; - -import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; -import com.sap.sse.common.settings.generic.EnumSetting; -import com.sap.sse.common.settings.generic.ValueConverter; -import com.sap.sse.common.settings.generic.base.AbstractValueSetting; -import com.sap.sse.common.settings.value.StringValue; -import com.sap.sse.common.settings.value.Value; - -/** - * We could use {@link EnumSetting} but this woul lead to problems if a enum constant in {@link BoatClassMasterdata} is - * renamed. This Setting instead used the display name that is also used in the backend to store which boat class is - * meant. {@link BoatClassMasterdata} can resolve the enum values from the display named which also works with some - * alternative names so that we don'T rely on the exact display name but that the display name will at least be - * available as alternative name. - */ -public class BoatClassSetting extends AbstractValueSetting { - - protected BoatClassSetting(String name, AbstractGenericSerializableSettings settings) { - super(name, settings, null, Converter.INSTANCE); - } - - public static class Converter implements ValueConverter { - - public static final Converter INSTANCE = new Converter(); - - @Override - public Object toJSONValue(BoatClassMasterdata value) { - return value == null ? null : value.getDisplayName(); - } - - @Override - public BoatClassMasterdata fromJSONValue(Object jsonValue) { - return fromStringValue((String) jsonValue); - } - - @Override - public String toStringValue(BoatClassMasterdata value) { - return value == null ? null : value.getDisplayName(); - } - - @Override - public BoatClassMasterdata fromStringValue(String stringValue) { - return stringValue == null ? null : BoatClassMasterdata.resolveBoatClass(stringValue); - } - - @Override - public BoatClassMasterdata fromValue(Value value) { - return fromStringValue(((StringValue) value).getValue()); - } - - @Override - public Value toValue(BoatClassMasterdata value) { - return new StringValue(toStringValue(value)); - } - } -} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java deleted file mode 100644 index a146fbdcdd1..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreference.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.sap.sailing.domain.common.preferences; - -import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; -import com.sap.sse.common.settings.generic.BooleanSetting; -import com.sap.sse.common.settings.generic.StringSetting; - -public class CompetitorNotificationPreference extends AbstractGenericSerializableSettings { - private static final long serialVersionUID = -6510535362114348707L; - - private transient StringSetting competitorId; - private transient BooleanSetting notifyAboutResults; - - public CompetitorNotificationPreference() { - } - - public CompetitorNotificationPreference(String competitorId, boolean notifyAboutResults) { - this.competitorId.setValue(competitorId); - this.notifyAboutResults.setValue(notifyAboutResults); - } - - @Override - protected void addChildSettings() { - competitorId = new StringSetting("competitorId", this); - notifyAboutResults = new BooleanSetting("notifyAboutResults", this, false); - } - - public String getCompetitorId() { - return competitorId.getValue(); - } - - public boolean isNotifyAboutResults() { - return Boolean.TRUE.equals(notifyAboutResults.getValue()); - } -} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java deleted file mode 100644 index e0ed4c50003..00000000000 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/CompetitorNotificationPreferences.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.sap.sailing.domain.common.preferences; - -import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; -import com.sap.sse.common.settings.generic.SettingsFactory; -import com.sap.sse.common.settings.generic.SettingsList; - -public class CompetitorNotificationPreferences extends AbstractGenericSerializableSettings { - private static final long serialVersionUID = -3682996540081614053L; - - private transient SettingsList competitors; - - public CompetitorNotificationPreferences() { - } - - public CompetitorNotificationPreferences(String name, AbstractGenericSerializableSettings settings) { - super(name, settings); - } - - @Override - protected void addChildSettings() { - competitors = new SettingsList<>("competitors", this, new SettingsFactory() { - @Override - public CompetitorNotificationPreference newInstance() { - return new CompetitorNotificationPreference(); - } - }); - } - - public Iterable getCompetitors() { - return competitors.getValues(); - } - - public void setCompetitors(Iterable boatClasses) { - this.competitors.setValues(boatClasses); - } -} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index c476d258cc0..61cf7fca73c 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -21,7 +21,6 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; -import com.sap.sailing.domain.common.preferences.NotificationPreferences; import com.sap.sailing.domain.common.tracking.impl.GPSFixImpl; import com.sap.sailing.domain.common.tracking.impl.GPSFixMovingImpl; import com.sap.sailing.domain.persistence.racelog.tracking.GPSFixMongoHandler; @@ -31,6 +30,7 @@ import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.server.MasterDataImportClassLoaderService; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceMXBean; +import com.sap.sailing.server.impl.preferences.model.NotificationPreferences; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.Util; import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; @@ -143,7 +143,8 @@ public class Activator implements BundleActivator { protected void registerPreferenceConvertersForUserStore(UserStore userStore) { userStore.registerPreferenceConverter(NotificationPreferences.PREF_NAME, - new GenericJSONPreferenceConverter(NotificationPreferences::new)); + new GenericJSONPreferenceConverter( + () -> new NotificationPreferences(racingEventService))); } public void stop(BundleContext context) throws Exception { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java index e85e54e7d16..28ebafe27ec 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java @@ -4,22 +4,22 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; -import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; -import com.sap.sailing.domain.common.preferences.NotificationPreferences; +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.NotificationPreferences; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; import com.sap.sse.security.UserStore; public abstract class AbstractBoatClassNotificationSet - extends PreferenceObjectBasedNotificationSet { + extends PreferenceObjectBasedNotificationSet { public AbstractBoatClassNotificationSet(UserStore store) { super(NotificationPreferences.PREF_NAME, store); } @Override - protected Collection calculateObjectsToNotify(NotificationPreferences preference) { - Set result = new HashSet<>(); + protected Collection calculateObjectsToNotify(NotificationPreferences preference) { + Set result = new HashSet<>(); for (BoatClassNotificationPreference pref : preference.getBoatClassPreferences().getBoatClasses()) { if (shouldNotifyFor(pref)) { result.add(pref.getBoatClass()); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java index 3489f62d5a4..4bbf0ad5500 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java @@ -1,28 +1,28 @@ package com.sap.sailing.server.impl.preferences; -import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.Set; -import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; -import com.sap.sailing.domain.common.preferences.NotificationPreferences; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.NotificationPreferences; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; import com.sap.sse.security.UserStore; public abstract class AbstractCompetitorNotificationSet - extends PreferenceObjectBasedNotificationSet { + extends PreferenceObjectBasedNotificationSet { public AbstractCompetitorNotificationSet(UserStore store) { super(NotificationPreferences.PREF_NAME, store); } @Override - protected Collection calculateObjectsToNotify(NotificationPreferences preference) { - Set result = new HashSet<>(); + protected Collection calculateObjectsToNotify(NotificationPreferences preference) { + Set result = new HashSet<>(); for (CompetitorNotificationPreference pref : preference.getCompetitorPreferences().getCompetitors()) { if (shouldNotifyFor(pref)) { - result.add(pref.getCompetitorId()); + result.add(pref.getCompetitor()); } } return result; diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java index 084f02c9845..abe666cfb68 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java @@ -1,6 +1,6 @@ package com.sap.sailing.server.impl.preferences; -import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; import com.sap.sse.security.UserStore; public class BoatClassResultsNotificationSet extends AbstractBoatClassNotificationSet { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java index 379d67f55e7..61ca3fc7de0 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java @@ -1,6 +1,6 @@ package com.sap.sailing.server.impl.preferences; -import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; import com.sap.sse.security.UserStore; public class BoatClassUpcomingRaceNotificationSet extends AbstractBoatClassNotificationSet { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java index 766747a1d53..da035ca17a7 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java @@ -1,6 +1,6 @@ package com.sap.sailing.server.impl.preferences; -import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; import com.sap.sse.security.UserStore; public class CompetitorResultsNotificationSet extends AbstractCompetitorNotificationSet { diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreference.java similarity index 52% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java rename to java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreference.java index 43919f4e7ff..c4898abe1d9 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/BoatClassNotificationPreference.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreference.java @@ -1,40 +1,48 @@ -package com.sap.sailing.domain.common.preferences; +package com.sap.sailing.server.impl.preferences.model; -import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.DomainFactory; import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; import com.sap.sse.common.settings.generic.BooleanSetting; public class BoatClassNotificationPreference extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -6510535362114348707L; - + private transient BoatClassSetting boatClass; private transient BooleanSetting notifyAboutUpcomingRaces; private transient BooleanSetting notifyAboutResults; - - public BoatClassNotificationPreference() { + + public BoatClassNotificationPreference(DomainFactory domainFactory) { + boatClass = new BoatClassSetting("boatClass", this, domainFactory); + notifyAboutUpcomingRaces = new BooleanSetting("notifyAboutUpcomingRaces", this, false); + notifyAboutResults = new BooleanSetting("notifyAboutResults", this, false); } - - public BoatClassNotificationPreference(BoatClassMasterdata boatClass, boolean notifyAboutRaces, boolean notifyAboutResults) { + + public BoatClassNotificationPreference(DomainFactory domainFactory, BoatClass boatClass, boolean notifyAboutRaces, + boolean notifyAboutResults) { + this(domainFactory); this.boatClass.setValue(boatClass); this.notifyAboutUpcomingRaces.setValue(notifyAboutRaces); this.notifyAboutResults.setValue(notifyAboutResults); } - + @Override protected void addChildSettings() { - boatClass = new BoatClassSetting("boatClass", this); - notifyAboutUpcomingRaces = new BooleanSetting("notifyAboutUpcomingRaces", this, false); - notifyAboutResults = new BooleanSetting("notifyAboutResults", this, false); + // We do not create the Setting instances here, because access to the RacingEventService would not be given. + // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON + // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and + // Competitor domain objects, it wouldn't be GWT compatible anyway. + // The usage of Java Serialization isn't planned by now too. } - - public BoatClassMasterdata getBoatClass() { + + public BoatClass getBoatClass() { return boatClass.getValue(); } - + public boolean isNotifyAboutUpcomingRaces() { return Boolean.TRUE.equals(notifyAboutUpcomingRaces.getValue()); } - + public boolean isNotifyAboutResults() { return Boolean.TRUE.equals(notifyAboutResults.getValue()); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java new file mode 100644 index 00000000000..12042a25f1a --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java @@ -0,0 +1,35 @@ +package com.sap.sailing.server.impl.preferences.model; + +import com.sap.sailing.server.RacingEventService; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.SettingsList; + +public class BoatClassNotificationPreferences extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -3682996540081614053L; + + private transient SettingsList boatClasses; + + public BoatClassNotificationPreferences(String name, AbstractGenericSerializableSettings settings, + RacingEventService racingEventService) { + super(name, settings); + boatClasses = new SettingsList<>("boatClasses", this, + () -> new BoatClassNotificationPreference(racingEventService.getBaseDomainFactory())); + } + + @Override + protected void addChildSettings() { + // We do not create the Setting instances here, because access to the RacingEventService would not be given. + // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON + // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and + // Competitor domain objects, it wouldn't be GWT compatible anyway. + // The usage of Java Serialization isn't planned by now too. + } + + public Iterable getBoatClasses() { + return boatClasses.getValues(); + } + + public void setBoatClasses(Iterable boatClasses) { + this.boatClasses.setValues(boatClasses); + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassSetting.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassSetting.java new file mode 100644 index 00000000000..b34a8d6f163 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassSetting.java @@ -0,0 +1,59 @@ +package com.sap.sailing.server.impl.preferences.model; + +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.DomainFactory; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.ValueConverter; +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.value.StringValue; +import com.sap.sse.common.settings.value.Value; + +/** + * Specific setting to hold a {@link BoatClass} instance. The competitor is being serialized using the boat classes' + * name and deserialized using the given {@link DomainFactory}. + */ +public class BoatClassSetting extends AbstractValueSetting { + + protected BoatClassSetting(String name, AbstractGenericSerializableSettings settings, DomainFactory domainFactory) { + super(name, settings, null, new Converter(domainFactory)); + } + + public static class Converter implements ValueConverter { + + private final DomainFactory domainFactory; + + public Converter(DomainFactory domainFactory) { + this.domainFactory = domainFactory; + } + + @Override + public Object toJSONValue(BoatClass value) { + return toStringValue(value); + } + + @Override + public BoatClass fromJSONValue(Object jsonValue) { + return fromStringValue((String) jsonValue); + } + + @Override + public String toStringValue(BoatClass value) { + return value == null ? null : value.getDisplayName(); + } + + @Override + public BoatClass fromStringValue(String stringValue) { + return stringValue == null ? null : domainFactory.getOrCreateBoatClass(stringValue); + } + + @Override + public BoatClass fromValue(Value value) { + return fromStringValue(((StringValue) value).getValue()); + } + + @Override + public Value toValue(BoatClass value) { + return new StringValue(toStringValue(value)); + } + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java new file mode 100644 index 00000000000..9888e8f0058 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java @@ -0,0 +1,42 @@ +package com.sap.sailing.server.impl.preferences.model; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.CompetitorStore; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.BooleanSetting; + +public class CompetitorNotificationPreference extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -6510535362114348707L; + + private transient CompetitorSetting competitor; + private transient BooleanSetting notifyAboutResults; + + public CompetitorNotificationPreference(CompetitorStore competitorStore) { + competitor = new CompetitorSetting("competitor", this, competitorStore); + notifyAboutResults = new BooleanSetting("notifyAboutResults", this, false); + } + + public CompetitorNotificationPreference(CompetitorStore competitorStore, Competitor competitor, + boolean notifyAboutResults) { + this(competitorStore); + this.competitor.setValue(competitor); + this.notifyAboutResults.setValue(notifyAboutResults); + } + + @Override + protected void addChildSettings() { + // We do not create the Setting instances here, because access to the RacingEventService would not be given. + // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON + // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and + // Competitor domain objects, it wouldn't be GWT compatible anyway. + // The usage of Java Serialization isn't planned by now too. + } + + public Competitor getCompetitor() { + return competitor.getValue(); + } + + public boolean isNotifyAboutResults() { + return Boolean.TRUE.equals(notifyAboutResults.getValue()); + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java new file mode 100644 index 00000000000..1f94f3274bf --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java @@ -0,0 +1,35 @@ +package com.sap.sailing.server.impl.preferences.model; + +import com.sap.sailing.server.RacingEventService; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.SettingsList; + +public class CompetitorNotificationPreferences extends AbstractGenericSerializableSettings { + private static final long serialVersionUID = -3682996540081614053L; + + private transient SettingsList competitors; + + public CompetitorNotificationPreferences(String name, AbstractGenericSerializableSettings settings, + RacingEventService racingEventService) { + super(name, settings); + competitors = new SettingsList<>("competitors", this, + () -> new CompetitorNotificationPreference(racingEventService.getCompetitorStore())); + } + + @Override + protected void addChildSettings() { + // We do not create the Setting instances here, because access to the RacingEventService would not be given. + // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON + // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and + // Competitor domain objects, it wouldn't be GWT compatible anyway. + // The usage of Java Serialization isn't planned by now too. + } + + public Iterable getCompetitors() { + return competitors.getValues(); + } + + public void setCompetitors(Iterable boatClasses) { + this.competitors.setValues(boatClasses); + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorSetting.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorSetting.java new file mode 100644 index 00000000000..0133116b9ef --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorSetting.java @@ -0,0 +1,60 @@ +package com.sap.sailing.server.impl.preferences.model; + +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.CompetitorStore; +import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; +import com.sap.sse.common.settings.generic.ValueConverter; +import com.sap.sse.common.settings.generic.base.AbstractValueSetting; +import com.sap.sse.common.settings.value.StringValue; +import com.sap.sse.common.settings.value.Value; + +/** + * Specific setting to hold a {@link Competitor} instance. The competitor is being serialized as ID and deserialized + * doing as lookup in the given {@link CompetitorStore}. + */ +public class CompetitorSetting extends AbstractValueSetting { + + protected CompetitorSetting(String name, AbstractGenericSerializableSettings settings, + CompetitorStore competitorStore) { + super(name, settings, null, new Converter(competitorStore)); + } + + public static class Converter implements ValueConverter { + + private final CompetitorStore competitorStore; + + public Converter(CompetitorStore competitorStore) { + this.competitorStore = competitorStore; + } + + @Override + public Object toJSONValue(Competitor value) { + return toStringValue(value); + } + + @Override + public Competitor fromJSONValue(Object jsonValue) { + return fromStringValue((String) jsonValue); + } + + @Override + public String toStringValue(Competitor value) { + return value == null ? null : value.getId().toString(); + } + + @Override + public Competitor fromStringValue(String stringValue) { + return stringValue == null ? null : competitorStore.getExistingCompetitorByIdAsString(stringValue); + } + + @Override + public Competitor fromValue(Value value) { + return fromStringValue(((StringValue) value).getValue()); + } + + @Override + public Value toValue(Competitor value) { + return new StringValue(toStringValue(value)); + } + } +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/NotificationPreferences.java similarity index 59% rename from java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java rename to java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/NotificationPreferences.java index d70311a18bb..dbec5991529 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/preferences/NotificationPreferences.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/NotificationPreferences.java @@ -1,5 +1,6 @@ -package com.sap.sailing.domain.common.preferences; +package com.sap.sailing.server.impl.preferences.model; +import com.sap.sailing.server.RacingEventService; import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; /** @@ -19,13 +20,18 @@ public class NotificationPreferences extends AbstractGenericSerializableSettings private transient BoatClassNotificationPreferences boatClassPreferences; private transient CompetitorNotificationPreferences competitorPreferences; - public NotificationPreferences() { + public NotificationPreferences(RacingEventService racingEventService) { + boatClassPreferences = new BoatClassNotificationPreferences("boatClassPreferences", this, racingEventService); + competitorPreferences = new CompetitorNotificationPreferences("competitorPreferences", this, racingEventService); } @Override protected void addChildSettings() { - boatClassPreferences = new BoatClassNotificationPreferences("boatClassPreferences", this); - competitorPreferences = new CompetitorNotificationPreferences("competitorPreferences", this); + // We do not create the Setting instances here, because access to the RacingEventService would not be given. + // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON + // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and + // Competitor domain objects, it wouldn't be GWT compatible anyway. + // The usage of Java Serialization isn't planned by now too. } public BoatClassNotificationPreferences getBoatClassPreferences() { From b230d93aa22514b677c114ea21757571141738af Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 11:12:01 +0200 Subject: [PATCH 138/259] Extended SailingDispatchContext to give access to preference objects --- .../communication/SailingDispatchContext.java | 3 +++ .../server/SailingDispatchContextImpl.java | 27 ++++++++++++++++++- .../servlets/SailingDispatchServlet.java | 12 ++++++--- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchContext.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchContext.java index f17c2ba6bb3..9be312e0c4d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchContext.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/SailingDispatchContext.java @@ -28,4 +28,7 @@ public interface SailingDispatchContext extends DispatchContext { @GwtIncompatible Date getCurrentClientTime(); + T getPreferenceForCurrentUser(String preferenceKey); + + void setPreferenceForCurrentUser(String preferenceKey, Object preference); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java index 2473ee39832..da641bf8ff0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java @@ -12,6 +12,9 @@ import com.sap.sailing.gwt.server.HomeServiceUtil; import com.sap.sailing.news.EventNewsService; import com.sap.sailing.server.RacingEventService; import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; +import com.sap.sse.security.SecurityService; +import com.sap.sse.security.User; +import com.sap.sse.security.UserStore; @GwtIncompatible public class SailingDispatchContextImpl implements SailingDispatchContext { @@ -21,11 +24,17 @@ public class SailingDispatchContextImpl implements SailingDispatchContext { // private final Date currentServerTime = new Date(); private String clientLocaleName; private final HttpServletRequest request; + private final SecurityService securityService; + private final UserStore userStore; - public SailingDispatchContextImpl(Date currentClientTime, RacingEventService racingEventService, EventNewsService eventNewsService, String clientLocaleName, HttpServletRequest request) { + public SailingDispatchContextImpl(Date currentClientTime, RacingEventService racingEventService, + EventNewsService eventNewsService, SecurityService securityService, UserStore userStore, + String clientLocaleName, HttpServletRequest request) { this.currentClientTime = currentClientTime; this.racingEventService = racingEventService; this.eventNewsService = eventNewsService; + this.securityService = securityService; + this.userStore = userStore; this.clientLocaleName = clientLocaleName; this.request = request; } @@ -68,4 +77,20 @@ public class SailingDispatchContextImpl implements SailingDispatchContext { return HomeServiceUtil.getRequestBaseURL(request); } + @Override + public T getPreferenceForCurrentUser(String preferenceKey) { + User currentUser = securityService.getCurrentUser(); + if(currentUser != null) { + userStore.getPreferenceObject(currentUser.getName(), preferenceKey); + } + return null; + } + + @Override + public void setPreferenceForCurrentUser(String preferenceKey, Object preference) { + User currentUser = securityService.getCurrentUser(); + if(currentUser != null) { + userStore.setPreferenceObject(currentUser.getName(), preferenceKey, preference); + } + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/SailingDispatchServlet.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/SailingDispatchServlet.java index 1186ed03aeb..b9618268f34 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/SailingDispatchServlet.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/servlets/SailingDispatchServlet.java @@ -12,6 +12,8 @@ import com.sap.sse.gwt.dispatch.client.transport.gwtrpc.RequestWrapper; import com.sap.sse.gwt.dispatch.servlets.AbstractDispatchServlet; import com.sap.sse.gwt.dispatch.shared.commands.Action; import com.sap.sse.gwt.dispatch.shared.commands.Result; +import com.sap.sse.security.SecurityService; +import com.sap.sse.security.UserStore; import com.sap.sse.util.ServiceTrackerFactory; public class SailingDispatchServlet extends AbstractDispatchServlet { @@ -19,18 +21,22 @@ public class SailingDispatchServlet extends AbstractDispatchServlet racingEventServiceTracker; private final ServiceTracker eventNewsServiceTracker; + private final ServiceTracker securityServiceTracker; + private final ServiceTracker userStoreTracker; public SailingDispatchServlet() { final BundleContext context = Activator.getDefault(); racingEventServiceTracker = ServiceTrackerFactory.createAndOpen(context, RacingEventService.class); eventNewsServiceTracker = ServiceTrackerFactory.createAndOpen(context, EventNewsService.class); + securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class); + userStoreTracker = ServiceTrackerFactory.createAndOpen(context, UserStore.class); } @Override protected > SailingDispatchContext createDispatchContextFor( RequestWrapper request) { - return new SailingDispatchContextImpl(request.getCurrentClientTime(), - racingEventServiceTracker.getService(), eventNewsServiceTracker.getService(), request - .getClientLocaleName(), getThreadLocalRequest()); + return new SailingDispatchContextImpl(request.getCurrentClientTime(), racingEventServiceTracker.getService(), + eventNewsServiceTracker.getService(), securityServiceTracker.getService(), + userStoreTracker.getService(), request.getClientLocaleName(), getThreadLocalRequest()); } } From 72aed5a00c6e3a9128ba0abcee5c2711b4da7085 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 11:25:53 +0200 Subject: [PATCH 139/259] Notification preferences are now saved to different keys --- .../sap/sailing/server/impl/Activator.java | 10 +++-- .../AbstractBoatClassNotificationSet.java | 10 ++--- .../AbstractCompetitorNotificationSet.java | 10 ++--- .../BoatClassNotificationPreferences.java | 6 +-- .../CompetitorNotificationPreferences.java | 6 +-- .../model/NotificationPreferences.java | 44 ------------------- .../preferences/model/SailingPreferences.java | 5 +++ 7 files changed, 27 insertions(+), 64 deletions(-) delete mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/NotificationPreferences.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 565c7d64205..7ec39138b80 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -32,7 +32,8 @@ import com.sap.sailing.domain.polars.PolarDataService; import com.sap.sailing.server.MasterDataImportClassLoaderService; import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceMXBean; -import com.sap.sailing.server.impl.preferences.model.NotificationPreferences; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.Util; import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; @@ -152,9 +153,10 @@ public class Activator implements BundleActivator { } protected void registerPreferenceConvertersForUserStore(UserStore userStore) { - userStore.registerPreferenceConverter(NotificationPreferences.PREF_NAME, - new GenericJSONPreferenceConverter( - () -> new NotificationPreferences(racingEventService))); + userStore.registerPreferenceConverter(CompetitorNotificationPreferences.PREF_NAME, + new GenericJSONPreferenceConverter<>(() -> new CompetitorNotificationPreferences(racingEventService))); + userStore.registerPreferenceConverter(BoatClassNotificationPreferences.PREF_NAME, + new GenericJSONPreferenceConverter<>(() -> new BoatClassNotificationPreferences(racingEventService))); } public void stop(BundleContext context) throws Exception { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java index 28ebafe27ec..33e2ee6da80 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java @@ -6,21 +6,21 @@ import java.util.Set; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; -import com.sap.sailing.server.impl.preferences.model.NotificationPreferences; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; import com.sap.sse.security.UserStore; public abstract class AbstractBoatClassNotificationSet - extends PreferenceObjectBasedNotificationSet { + extends PreferenceObjectBasedNotificationSet { public AbstractBoatClassNotificationSet(UserStore store) { - super(NotificationPreferences.PREF_NAME, store); + super(BoatClassNotificationPreferences.PREF_NAME, store); } @Override - protected Collection calculateObjectsToNotify(NotificationPreferences preference) { + protected Collection calculateObjectsToNotify(BoatClassNotificationPreferences preference) { Set result = new HashSet<>(); - for (BoatClassNotificationPreference pref : preference.getBoatClassPreferences().getBoatClasses()) { + for (BoatClassNotificationPreference pref : preference.getBoatClasses()) { if (shouldNotifyFor(pref)) { result.add(pref.getBoatClass()); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java index 4bbf0ad5500..71c26ed67d5 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java @@ -6,21 +6,21 @@ import java.util.Set; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; -import com.sap.sailing.server.impl.preferences.model.NotificationPreferences; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; import com.sap.sse.security.UserStore; public abstract class AbstractCompetitorNotificationSet - extends PreferenceObjectBasedNotificationSet { + extends PreferenceObjectBasedNotificationSet { public AbstractCompetitorNotificationSet(UserStore store) { - super(NotificationPreferences.PREF_NAME, store); + super(CompetitorNotificationPreferences.PREF_NAME, store); } @Override - protected Collection calculateObjectsToNotify(NotificationPreferences preference) { + protected Collection calculateObjectsToNotify(CompetitorNotificationPreferences preference) { Set result = new HashSet<>(); - for (CompetitorNotificationPreference pref : preference.getCompetitorPreferences().getCompetitors()) { + for (CompetitorNotificationPreference pref : preference.getCompetitors()) { if (shouldNotifyFor(pref)) { result.add(pref.getCompetitor()); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java index 12042a25f1a..c2a069c3252 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java @@ -7,11 +7,11 @@ import com.sap.sse.common.settings.generic.SettingsList; public class BoatClassNotificationPreferences extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -3682996540081614053L; + public static final String PREF_NAME = SailingPreferences.NOTIFICATION_PREFERENCES_PREFIX + "boatclasses"; + private transient SettingsList boatClasses; - public BoatClassNotificationPreferences(String name, AbstractGenericSerializableSettings settings, - RacingEventService racingEventService) { - super(name, settings); + public BoatClassNotificationPreferences(RacingEventService racingEventService) { boatClasses = new SettingsList<>("boatClasses", this, () -> new BoatClassNotificationPreference(racingEventService.getBaseDomainFactory())); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java index 1f94f3274bf..8804204f72e 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java @@ -6,12 +6,12 @@ import com.sap.sse.common.settings.generic.SettingsList; public class CompetitorNotificationPreferences extends AbstractGenericSerializableSettings { private static final long serialVersionUID = -3682996540081614053L; + + public static final String PREF_NAME = SailingPreferences.NOTIFICATION_PREFERENCES_PREFIX + "competitors"; private transient SettingsList competitors; - public CompetitorNotificationPreferences(String name, AbstractGenericSerializableSettings settings, - RacingEventService racingEventService) { - super(name, settings); + public CompetitorNotificationPreferences(RacingEventService racingEventService) { competitors = new SettingsList<>("competitors", this, () -> new CompetitorNotificationPreference(racingEventService.getCompetitorStore())); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/NotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/NotificationPreferences.java deleted file mode 100644 index dbec5991529..00000000000 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/NotificationPreferences.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.sap.sailing.server.impl.preferences.model; - -import com.sap.sailing.server.RacingEventService; -import com.sap.sse.common.settings.generic.AbstractGenericSerializableSettings; - -/** - * Preferences for Sailing users that define for which Objects a user wants to receive specific notifications. - * This currently includes: - *
          - *
        • Results for a favorite Competitor
        • - *
        • Results for a favorite BoatClass
        • - *
        • Upcoming races for a favorite BoatClass
        • - *
        - */ -public class NotificationPreferences extends AbstractGenericSerializableSettings { - private static final long serialVersionUID = 8865010526321472376L; - - public static final String PREF_NAME = "sailing.notifications"; - - private transient BoatClassNotificationPreferences boatClassPreferences; - private transient CompetitorNotificationPreferences competitorPreferences; - - public NotificationPreferences(RacingEventService racingEventService) { - boatClassPreferences = new BoatClassNotificationPreferences("boatClassPreferences", this, racingEventService); - competitorPreferences = new CompetitorNotificationPreferences("competitorPreferences", this, racingEventService); - } - - @Override - protected void addChildSettings() { - // We do not create the Setting instances here, because access to the RacingEventService would not be given. - // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON - // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and - // Competitor domain objects, it wouldn't be GWT compatible anyway. - // The usage of Java Serialization isn't planned by now too. - } - - public BoatClassNotificationPreferences getBoatClassPreferences() { - return boatClassPreferences; - } - - public CompetitorNotificationPreferences getCompetitorPreferences() { - return competitorPreferences; - } -} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java new file mode 100644 index 00000000000..44451d9c539 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java @@ -0,0 +1,5 @@ +package com.sap.sailing.server.impl.preferences.model; + +public interface SailingPreferences { + public static final String NOTIFICATION_PREFERENCES_PREFIX = "sailing.notifications."; +} From b1a7a05006a50afaba46cd3888bcc589da16c5dd Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 11:31:55 +0200 Subject: [PATCH 140/259] Exporting package in OSGi to access the preferences model in gwt.ui --- java/com.sap.sailing.server/META-INF/MANIFEST.MF | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.server/META-INF/MANIFEST.MF b/java/com.sap.sailing.server/META-INF/MANIFEST.MF index ca1e4920472..a3fd190d9b7 100644 --- a/java/com.sap.sailing.server/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server/META-INF/MANIFEST.MF @@ -45,6 +45,7 @@ Export-Package: com.sap.sailing.server, com.sap.sailing.server.replication.test, com.sap.sailing.domain.racelogtrackingadapter.test, com.sap.sailing.server.testsupport", + com.sap.sailing.server.impl.preferences.model, com.sap.sailing.server.masterdata, com.sap.sailing.server.operationaltransformation, com.sap.sailing.server.operationaltransformation.racelog, From 7b0f3c9cbdf3351ac85c27b9e474cf836895c5fa Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 11:38:53 +0200 Subject: [PATCH 141/259] Added more JavaDocs to PreferenceObjectBasedNotificationSet --- .../PreferenceObjectBasedNotificationSet.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index ceed6bfb22e..9092876428a 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -13,10 +13,25 @@ import java.util.logging.Logger; import com.sap.sse.common.Util; /** - * Holds an optimized association of who to notify about specific objects. On preference changes for the given key in - * the given {@link UserStore}, the associations are being updated to make the model always reflect the current state of - * the associations. This makes it possible to search for associations for a specific object without the need of a model - * update on the fly. + *

        + * Preferences available in the {@link UserStore} are held by the user as key. The preferences are stored as complex + * objects that are being serialized to String to be saved in the DB. For convenience, the {@link UserStore} allows to + * register {@link PreferenceConverter}s to also hold a deserialized version of the preferences in memory to speed up + * the access without the need of a deserialization on demand. + *

        + * + *

        + * When coming from the notification perspective, we have a domain object (e.g. competitor) and would like to know the + * users to notify about this domain object. To calculate this Set of users we would need to loop over the specific + * notification preferences for all users. + *

        + * + *

        + * To speed up this part, the PreferenceObjectBasedNotificationSet holds an optimized association of who to notify about + * specific objects. On preference changes for the given key in the given {@link UserStore}, the associations are being + * updated to make the model always reflect the current state of the associations. Due to this the calculation of the + * users to notify is a simple lookup. + *

        * * @param * The type of preference object on which the calculation of the objects to notify is based on. From b931a4efaa3a568d62ecfeb95cf73649444aa247 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 11:53:33 +0200 Subject: [PATCH 142/259] Added data transfer object for favorite boat class preferences --- .../user/profile/FavoriteBoatClassesDTO.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteBoatClassesDTO.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteBoatClassesDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteBoatClassesDTO.java new file mode 100644 index 00000000000..4cff5cfe15b --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteBoatClassesDTO.java @@ -0,0 +1,39 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.ArrayList; +import java.util.Collection; + +import com.sap.sailing.domain.common.dto.BoatClassDTO; +import com.sap.sse.gwt.dispatch.shared.commands.DTO; + +/** + * {@link DTO} implementation representing the favorite boat class preferences. + */ +public class FavoriteBoatClassesDTO implements DTO { + + private ArrayList selectedBoatClasses = new ArrayList<>(); + private boolean notifyAboutUpcomingRaces; + private boolean notifyAboutResults; + + protected FavoriteBoatClassesDTO() {} + + public FavoriteBoatClassesDTO(Collection selectedBoatClasses, boolean notifyAboutUpcomingRaces, + boolean notifyAboutResults) { + this.selectedBoatClasses.addAll(selectedBoatClasses); + this.notifyAboutUpcomingRaces = notifyAboutUpcomingRaces; + this.notifyAboutResults = notifyAboutResults; + } + + public Collection getSelectedBoatClasses() { + return selectedBoatClasses; + } + + public boolean isNotifyAboutUpcomingRaces() { + return notifyAboutUpcomingRaces; + } + + public boolean isNotifyAboutResults() { + return notifyAboutResults; + } + +} From 651f73c6a46bae1a42930914443f20b9f951aff1 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 11:53:46 +0200 Subject: [PATCH 143/259] Added data transfer object for favorite competitor preferences --- .../user/profile/FavoriteCompetitorsDTO.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteCompetitorsDTO.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteCompetitorsDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteCompetitorsDTO.java new file mode 100644 index 00000000000..e53932552ba --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoriteCompetitorsDTO.java @@ -0,0 +1,33 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.ArrayList; +import java.util.Collection; + +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sse.gwt.dispatch.shared.commands.DTO; + +/** + * {@link DTO} implementation representing the favorite competitor preferences. + */ +public class FavoriteCompetitorsDTO implements DTO { + + private ArrayList selectedCompetitors = new ArrayList<>(); + private boolean notifyAboutResults; + + protected FavoriteCompetitorsDTO() {} + + public FavoriteCompetitorsDTO(Collection selectedCompetitors, + boolean notifyAboutResults) { + this.selectedCompetitors.addAll(selectedCompetitors); + this.notifyAboutResults = notifyAboutResults; + } + + public Collection getSelectedCompetitors() { + return selectedCompetitors; + } + + public boolean isNotifyAboutResults() { + return notifyAboutResults; + } + +} From 0fd78b5c35fba423987b8fc4425d294cfc49d4ae Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 11:54:23 +0200 Subject: [PATCH 144/259] Added dispatch action and result to load user favorite preferences --- .../user/profile/FavoritesResult.java | 25 +++++++++ .../user/profile/GetFavoritesAction.java | 54 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoritesResult.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoritesResult.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoritesResult.java new file mode 100644 index 00000000000..81e84f99d55 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/FavoritesResult.java @@ -0,0 +1,25 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import com.sap.sse.gwt.dispatch.shared.commands.Result; + +public class FavoritesResult implements Result { + + private FavoriteBoatClassesDTO favoriteBoatClasses; + private FavoriteCompetitorsDTO favoriteCompetitors; + + protected FavoritesResult() {} + + public FavoritesResult(FavoriteBoatClassesDTO favoriteBoatClasses, FavoriteCompetitorsDTO favoriteCompetitors) { + this.favoriteBoatClasses = favoriteBoatClasses; + this.favoriteCompetitors = favoriteCompetitors; + } + + public FavoriteBoatClassesDTO getFavoriteBoatClasses() { + return favoriteBoatClasses; + } + + public FavoriteCompetitorsDTO getFavoriteCompetitors() { + return favoriteCompetitors; + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java new file mode 100644 index 00000000000..55a488d79be --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java @@ -0,0 +1,54 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.TreeSet; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.common.dto.BoatClassDTO; +import com.sap.sailing.gwt.home.communication.SailingAction; +import com.sap.sailing.gwt.home.communication.SailingDispatchContext; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences; +import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; + +/** + * {@link SailingAction} implementation to load favorites for the currently logged in user to bee shown on the + * preferences page, preparing the appropriate data structure. + */ +public class GetFavoritesAction implements SailingAction { + + @Override + @GwtIncompatible + public FavoritesResult execute(SailingDispatchContext ctx) throws DispatchException { + return new FavoritesResult(getFavoriteBoatClasses(ctx), getFavoriteCompetitors(ctx)); + } + + private FavoriteBoatClassesDTO getFavoriteBoatClasses(SailingDispatchContext ctx) { + BoatClassNotificationPreferences preferences = ctx + .getPreferenceForCurrentUser(BoatClassNotificationPreferences.PREF_NAME); + TreeSet selected = new TreeSet<>(); + boolean notifyAboutUpcomingRaces = false, notifyAboutResults = false; + for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { + String name = pref.getBoatClass().getName(), displayName = pref.getBoatClass().getDisplayName(); + selected.add(new BoatClassDTO(name, displayName, pref.getBoatClass().getHullLength().getMeters())); + notifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); + notifyAboutResults |= pref.isNotifyAboutResults(); + } + return new FavoriteBoatClassesDTO(selected, notifyAboutUpcomingRaces, notifyAboutResults); + } + + private FavoriteCompetitorsDTO getFavoriteCompetitors(SailingDispatchContext ctx) { + CompetitorNotificationPreferences preferences = ctx + .getPreferenceForCurrentUser(CompetitorNotificationPreferences.PREF_NAME); + TreeSet selected = new TreeSet<>(); + boolean notifyAboutResults = false; + for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { + selected.add(new SimpleCompetitorWithIdDTO(pref.getCompetitor())); + notifyAboutResults |= pref.isNotifyAboutResults(); + } + return new FavoriteCompetitorsDTO(selected, notifyAboutResults); + } + +} From 54ebaf6e8bcf72b12838fc70038c1af0ca676fca Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 12:30:54 +0200 Subject: [PATCH 145/259] Added dispatch VoidResult for convenience purposes --- .../sap/sse/gwt/dispatch/shared/commands/VoidResult.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/shared/commands/VoidResult.java diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/shared/commands/VoidResult.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/shared/commands/VoidResult.java new file mode 100644 index 00000000000..694becc1c94 --- /dev/null +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/dispatch/shared/commands/VoidResult.java @@ -0,0 +1,7 @@ +package com.sap.sse.gwt.dispatch.shared.commands; + +/** + * Empty {@link Result} implementation, which can be reused for {@link Action}s with a void result. + */ +public class VoidResult implements Result { +} From 4bed3d20fd4604b08289852cca771340f0c0ba87 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 12:31:23 +0200 Subject: [PATCH 146/259] Added dispatch action to save favorite boat class preferences --- .../SaveFavoriteBoatClassesAction.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java new file mode 100644 index 00000000000..40238b92231 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java @@ -0,0 +1,47 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.DomainFactory; +import com.sap.sailing.domain.common.dto.BoatClassDTO; +import com.sap.sailing.gwt.home.communication.SailingAction; +import com.sap.sailing.gwt.home.communication.SailingDispatchContext; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; +import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; +import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; + +/** + * {@link SailingAction} implementation to save favorite boat classes for the currently logged in user as selected on + * the preferences page. + */ +public class SaveFavoriteBoatClassesAction implements SailingAction { + + private FavoriteBoatClassesDTO favorites; + + protected SaveFavoriteBoatClassesAction() {} + + public SaveFavoriteBoatClassesAction(FavoriteBoatClassesDTO favorites) { + this.favorites = favorites; + } + + @Override + @GwtIncompatible + public VoidResult execute(SailingDispatchContext ctx) throws DispatchException { + BoatClassNotificationPreferences prefs = new BoatClassNotificationPreferences(ctx.getRacingEventService()); + List boatClassPreferences = new ArrayList<>(); + for (BoatClassDTO boatClassDTO : favorites.getSelectedBoatClasses()) { + DomainFactory domainFactory = ctx.getRacingEventService().getBaseDomainFactory(); + BoatClass boatClass = domainFactory.getOrCreateBoatClass(boatClassDTO.getName()); + boatClassPreferences.add(new BoatClassNotificationPreference(domainFactory, boatClass, + favorites.isNotifyAboutUpcomingRaces(), favorites.isNotifyAboutResults())); + } + prefs.setBoatClasses(boatClassPreferences); + ctx.setPreferenceForCurrentUser(BoatClassNotificationPreferences.PREF_NAME, prefs); + return new VoidResult(); + } + +} From 1c0ca145d21b4c5e20f44dfdeda2f6aabe4e6c2a Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 12:31:37 +0200 Subject: [PATCH 147/259] Added dispatch action to save favorite competitor preferences --- .../SaveFavoriteCompetitorsAction.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java new file mode 100644 index 00000000000..3eacf7ec1ba --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java @@ -0,0 +1,47 @@ +package com.sap.sailing.gwt.home.communication.user.profile; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gwt.core.shared.GwtIncompatible; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.CompetitorStore; +import com.sap.sailing.gwt.home.communication.SailingAction; +import com.sap.sailing.gwt.home.communication.SailingDispatchContext; +import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; +import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences; +import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; +import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; + +/** + * {@link SailingAction} implementation to save favorite competitors for the currently logged in user as selected on + * the preferences page. + */ +public class SaveFavoriteCompetitorsAction implements SailingAction { + + private FavoriteCompetitorsDTO favorites; + + protected SaveFavoriteCompetitorsAction() {} + + public SaveFavoriteCompetitorsAction(FavoriteCompetitorsDTO favorites) { + this.favorites = favorites; + } + + @Override + @GwtIncompatible + public VoidResult execute(SailingDispatchContext ctx) throws DispatchException { + CompetitorNotificationPreferences prefs = new CompetitorNotificationPreferences(ctx.getRacingEventService()); + List competitorPreferences = new ArrayList<>(); + for (SimpleCompetitorWithIdDTO competitorDTO : favorites.getSelectedCompetitors()) { + CompetitorStore competitorStore = ctx.getRacingEventService().getCompetitorStore(); + Competitor competitor = competitorStore.getExistingCompetitorByIdAsString(competitorDTO.getIdAsString()); + competitorPreferences.add(new CompetitorNotificationPreference(competitorStore, competitor, + favorites.isNotifyAboutResults())); + } + prefs.setCompetitors(competitorPreferences); + ctx.setPreferenceForCurrentUser(CompetitorNotificationPreferences.PREF_NAME, prefs); + return new VoidResult(); + } + +} From 516a889c0263760b5e5bbaf27e405ba25081667c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 12:35:28 +0200 Subject: [PATCH 148/259] Added the possibility to remove PreferenceConverters from the UserStore --- .../security/userstore/mongodb/UserStoreImpl.java | 15 +++++++++++++++ .../src/com/sap/sse/security/UserStore.java | 2 ++ 2 files changed, 17 insertions(+) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 7d5dae1602b..5491267e292 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -543,6 +543,21 @@ public class UserStoreImpl implements UserStore { + " is already registered. Converter " + converter + " will not be registered"); } } + + @Override + public void removePreferenceConverter(String preferenceKey) { + PreferenceConverter preferenceConverterToRemove = preferenceConverters.remove(preferenceKey); + if (preferenceConverterToRemove != null) { + final Set usersToProcess = new HashSet<>(preferences.keySet()); + for (String username : usersToProcess) { + unsetPreferenceObject(username, preferenceKey); + } + } else { + logger.log(Level.WARNING, "PreferenceConverter for key " + preferenceKey + + " should be removed but wasn't registered"); + } + + } private void loadPreferenceIfConverterIsAvailable(String username, String key) { PreferenceConverter preferenceConverter = preferenceConverters.get(key); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index 672fa71ef0e..5900cfebc50 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -63,6 +63,8 @@ public interface UserStore extends Named { */ void registerPreferenceConverter(String key, PreferenceConverter converter); + void removePreferenceConverter(String key); + /** * Gets a preference object. Always returns null if there is no converter associated with the given key -> see * {@link #registerPreferenceConverter(String, PreferenceConverter)}. From 3695b9cc10d93251971195fb0400ac5402dfd97a Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 12:36:26 +0200 Subject: [PATCH 149/259] Renamed some internal methods in UserStoreImpl to make more clear what's happening --- .../sse/security/userstore/mongodb/UserStoreImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 5491267e292..7540d1337f3 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -443,7 +443,7 @@ public class UserStoreImpl implements UserStore { @Override public void setPreference(String username, String key, String value) { setPreferenceInternal(username, key, value); - loadPreferenceIfConverterIsAvailable(username, key); + updatePreferenceObjectIfConverterIsAvailable(username, key); } private void setPreferenceInternal(String username, String key, String value) { @@ -536,7 +536,7 @@ public class UserStoreImpl implements UserStore { if (alreadyAssociatedConverter == null) { final Set usersToProcess = new HashSet<>(preferences.keySet()); for (String user : usersToProcess) { - loadPreferenceWithConverter(user, preferenceKey, converter); + updatePreferenceObjectWithConverter(user, preferenceKey, converter); } } else { logger.log(Level.SEVERE, "PreferenceConverter " + alreadyAssociatedConverter + " for key " + preferenceKey @@ -559,14 +559,14 @@ public class UserStoreImpl implements UserStore { } - private void loadPreferenceIfConverterIsAvailable(String username, String key) { + private void updatePreferenceObjectIfConverterIsAvailable(String username, String key) { PreferenceConverter preferenceConverter = preferenceConverters.get(key); if (preferenceConverter != null) { - loadPreferenceWithConverter(username, key, preferenceConverter); + updatePreferenceObjectWithConverter(username, key, preferenceConverter); } } - private void loadPreferenceWithConverter(String username, String key, PreferenceConverter preferenceConverter) { + private void updatePreferenceObjectWithConverter(String username, String key, PreferenceConverter preferenceConverter) { final String preferenceString = getPreference(username, key); if (preferenceString != null) { try { From f5c359b64e1ca7b7aa0c80621aeb4bcc847a4356 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 12:37:32 +0200 Subject: [PATCH 150/259] Added tests to verify the PreferenceConverter removal in UserStore --- .../PreferenceObjectBasedNotificationSetTest.java | 12 ++++++++++++ .../test/UserPreferenceObjectAndConverterTest.java | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 20e8b8647de..9706cafb15c 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -227,6 +227,18 @@ public class PreferenceObjectBasedNotificationSetTest { Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); } + @Test + public void removePreferenceConverterTest() throws UserManagementException { + store.createUser(user1, mail); + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + store.removePreferenceConverter(prefKey); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(A), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(B), values())); + Assert.assertTrue(Util.equals(notificationSet.getUsersnamesToNotifyFor(C), values())); + } + private static HashSet values(String... values) { return new HashSet<>(Arrays.asList(values)); } diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java index e07beeba608..31d53f9ee5c 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java @@ -118,6 +118,15 @@ public class UserPreferenceObjectAndConverterTest { store.deleteUser(user1); Assert.assertNull(store.getPreferenceObject(user1, prefKey1)); } + + @Test + public void removeConverterTest() throws UserManagementException { + store.createUser(user1, email); + store.registerPreferenceConverter(prefKey1, prefConverter); + store.setPreference(user1, prefKey1, serializedPref1); + store.removePreferenceConverter(prefKey1); + Assert.assertNull(store.getPreferenceObject(user1, prefKey1)); + } public static class SimplePreferenceForSerialization implements Serializable { private static final long serialVersionUID = -580569932709860895L; From e89c05bf01d7525b863803f203a61d04ce7af693 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 12:38:14 +0200 Subject: [PATCH 151/259] PreferenceConverters can now be registered through OSGi service registry --- .../userstore/mongodb/UserStoreImpl.java | 8 +- .../userstore/mongodb/impl/Activator.java | 7 +- .../sap/sse/security/PreferenceConverter.java | 2 + ...referenceConverterRegistrationManager.java | 77 +++++++++++++++++++ .../src/com/sap/sse/security/UserStore.java | 28 ++++++- 5 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 7540d1337f3..c752334a0f3 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -591,8 +591,12 @@ public class UserStoreImpl implements UserStore { } } } - Object oldPreference = userMap.put(key, convertedObject); - notifyListenersOnPreferenceObjectChange(username, key, oldPreference, convertedObject); + // if the new preference object is simply null, we remove the entry instead of putting null + Object oldPreference = convertedObject == null ? userMap.remove(key) : userMap.put(key, convertedObject); + if(oldPreference != null || convertedObject != null) { + // preference hasn't changed if it was null and is now null + notifyListenersOnPreferenceObjectChange(username, key, oldPreference, convertedObject); + } } private void unsetPreferenceObject(String username, String key) { diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/Activator.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/Activator.java index 1bf1b5eca8e..9226a1b243c 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/Activator.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/Activator.java @@ -7,6 +7,7 @@ import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import com.sap.sse.mongodb.MongoDBService; +import com.sap.sse.security.PreferenceConverterRegistrationManager; import com.sap.sse.security.UserStore; import com.sap.sse.security.userstore.mongodb.UserStoreImpl; @@ -14,6 +15,7 @@ public class Activator implements BundleActivator { private static BundleContext context; private ServiceRegistration registration; + private PreferenceConverterRegistrationManager preferenceConverterRegistrationManager; static BundleContext getContext() { return context; @@ -26,8 +28,10 @@ public class Activator implements BundleActivator { */ public void start(BundleContext bundleContext) throws Exception { Activator.context = bundleContext; + UserStoreImpl userStore = new UserStoreImpl(); registration = context.registerService(UserStore.class.getName(), - new UserStoreImpl(), null); + userStore, null); + preferenceConverterRegistrationManager = new PreferenceConverterRegistrationManager(bundleContext, userStore); Logger.getLogger(Activator.class.getName()).info("User store registered."); for (CollectionNames name : CollectionNames.values()) { MongoDBService.INSTANCE.registerExclusively(CollectionNames.class, name.name()); @@ -40,6 +44,7 @@ public class Activator implements BundleActivator { * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext bundleContext) throws Exception { + preferenceConverterRegistrationManager.stop(); registration.unregister(); Activator.context = null; } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java index 7fb62123211..2ce5fba4e5c 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java @@ -7,6 +7,8 @@ package com.sap.sse.security; * @param The type of preference object, this converter handles. */ public interface PreferenceConverter { + public final String KEY_PARAMETER_NAME = "key"; + String toPreferenceString(PREF preference); PREF toPreferenceObject(String stringPreference); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java new file mode 100644 index 00000000000..ec813f73ee1 --- /dev/null +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java @@ -0,0 +1,77 @@ +package com.sap.sse.security; + +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +/** + * Automatically registers/removes {@link PreferenceConverter} instances found in the OSGi service registry on the given + * {@link UserStore}. + * + * {@link PreferenceConverter} found are required to have a property with the key + * {@link PreferenceConverter#KEY_PARAMETER_NAME} defining the preference key the converter should be registered with. + */ +public class PreferenceConverterRegistrationManager { + private static final Logger logger = Logger.getLogger(PreferenceConverterRegistrationManager.class.getName()); + + private final BundleContext context; + private final UserStore userStore; + + private final ServiceTracker, PreferenceConverter> tracker; + + public PreferenceConverterRegistrationManager(BundleContext bundleContext, UserStore userStore) { + this.context = bundleContext; + this.userStore = userStore; + tracker = createTracker(bundleContext); + tracker.open(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private ServiceTracker, PreferenceConverter> createTracker(BundleContext bundleContext) { + return new ServiceTracker, PreferenceConverter>(bundleContext, + (Class) PreferenceConverter.class, new Cutomizer()); + } + + public void stop() { + tracker.close(); + } + + private class Cutomizer implements ServiceTrackerCustomizer, PreferenceConverter> { + + @Override + public PreferenceConverter addingService(ServiceReference> reference) { + String preferenceKey = (String) reference.getProperty(PreferenceConverter.KEY_PARAMETER_NAME); + PreferenceConverter converter = context.getService(reference); + if (preferenceKey == null) { + logger.log(Level.SEVERE, + "Found PreferenceConverter \"" + converter + "\" in OSGi registry without property " + + PreferenceConverter.KEY_PARAMETER_NAME + " defining the preference key"); + } else { + logger.log(Level.FINE, "Registering PreferenceConverter \"" + converter + + "\" found as OSGi service with key \"" + preferenceKey + "\""); + userStore.registerPreferenceConverter(preferenceKey, converter); + } + return converter; + } + + @Override + public void modifiedService(ServiceReference> reference, + PreferenceConverter service) { + // Should we do anything here? + } + + @Override + public void removedService(ServiceReference> reference, PreferenceConverter service) { + String preferenceKey = (String) reference.getProperty(PreferenceConverter.KEY_PARAMETER_NAME); + if (preferenceKey != null) { + logger.log(Level.FINE, + "Removing PreferenceConverter \"" + service + "\" with key \"" + preferenceKey + "\""); + userStore.removePreferenceConverter(preferenceKey); + } + } + } +} diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index 5900cfebc50..74583ff2954 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -55,14 +55,38 @@ public interface UserStore extends Named { String getPreference(String username, String key); /** + *

        + * In an OSGi environment, this shouldn't be called manually, but instead automatically managed by setting a + * {@link PreferenceConverterRegistrationManager} up. {@link PreferenceConverter}s should be registered in the OSGi + * service registry with {@link PreferenceConverter#KEY_PARAMETER_NAME} containing the associated preference key + * added as property of the service registration. + *

        + * + *

        * Registers a converter objects for a preference key that is used to convert preference Strings to Objects. This * makes it possible to access deserialized settings without the need to do the deserialization over and over again. + *

        * - * @param key the key to associate the converter with - * @param converter the converter to use for (de)serialization + * @param key + * the key to associate the converter with + * @param converter + * the converter to use for (de)serialization */ void registerPreferenceConverter(String key, PreferenceConverter converter); + /** + *

        + * In an OSGi environment, this shouldn't be called manually, but instead automatically managed by setting a + * {@link PreferenceConverterRegistrationManager} up. + *

        + * + *

        + * Removes a registered {@link PreferenceConverter} with the given key. + *

        + * + * @param key + * the key of the {@link PreferenceConverter} to remove + */ void removePreferenceConverter(String key); /** From c555a39d4390370ea2c89dd9339e3375b0809716 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 12:42:59 +0200 Subject: [PATCH 152/259] PreferenceConverter registrations in com.sap.sailing.server are now done through OSGi --- .../sap/sailing/server/impl/Activator.java | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 7ec39138b80..e9a2790b809 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -38,9 +38,8 @@ import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.Util; import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; import com.sap.sse.replication.Replicable; -import com.sap.sse.security.UserStore; +import com.sap.sse.security.PreferenceConverter; import com.sap.sse.util.ClearStateTestSupport; -import com.sap.sse.util.ServiceTrackerFactory; public class Activator implements BundleActivator { @@ -123,7 +122,7 @@ public class Activator implements BundleActivator { racingEventService.getDomainObjectFactory()), properties)); - registerPreferenceConvertersWhenUserStoreIsAvailable(context); + registerPreferenceConvertersForUserStore(context); // Add an MBean for the service to the JMX bean server: RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService); @@ -134,29 +133,16 @@ public class Activator implements BundleActivator { Charset.defaultCharset()); } - private void registerPreferenceConvertersWhenUserStoreIsAvailable(BundleContext bundleContext) { - ServiceTracker userStoreTracker = ServiceTrackerFactory.createAndOpen(bundleContext, - UserStore.class); - new Thread("ServiceTracker waiting for UserStore service") { - @Override - public void run() { - try { - logger.info("Waiting for UserStore service..."); - UserStore userStore = userStoreTracker.waitForService(0); - logger.info("Obtained UserStore service " + userStore); - registerPreferenceConvertersForUserStore(userStore); - } catch (InterruptedException e) { - logger.log(Level.SEVERE, "Interrupted while waiting for UserStore service", e); - } - } - }.start(); - } - - protected void registerPreferenceConvertersForUserStore(UserStore userStore) { - userStore.registerPreferenceConverter(CompetitorNotificationPreferences.PREF_NAME, - new GenericJSONPreferenceConverter<>(() -> new CompetitorNotificationPreferences(racingEventService))); - userStore.registerPreferenceConverter(BoatClassNotificationPreferences.PREF_NAME, - new GenericJSONPreferenceConverter<>(() -> new BoatClassNotificationPreferences(racingEventService))); + protected void registerPreferenceConvertersForUserStore(BundleContext context) { + Dictionary properties = new Hashtable(); + properties.put(PreferenceConverter.KEY_PARAMETER_NAME, CompetitorNotificationPreferences.PREF_NAME); + registrations.add(context.registerService(PreferenceConverter.class, + new GenericJSONPreferenceConverter<>(() -> new CompetitorNotificationPreferences(racingEventService)), + properties)); + properties.put(PreferenceConverter.KEY_PARAMETER_NAME, BoatClassNotificationPreferences.PREF_NAME); + registrations.add(context.registerService(PreferenceConverter.class, + new GenericJSONPreferenceConverter<>(() -> new BoatClassNotificationPreferences(racingEventService)), + properties)); } public void stop(BundleContext context) throws Exception { From 033ec41a606a4ad32ae8eaeacff6c87c195369bd Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 13:49:56 +0200 Subject: [PATCH 153/259] Added a common interface Stoppable with a declared stop method to make it possible to cleanup several objects in an Activator --- .../src/com/sap/sse/common/Stoppable.java | 11 +++++++++++ .../PreferenceConverterRegistrationManager.java | 5 ++++- .../PreferenceObjectBasedNotificationSet.java | 4 +++- 3 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 java/com.sap.sse.common/src/com/sap/sse/common/Stoppable.java diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Stoppable.java b/java/com.sap.sse.common/src/com/sap/sse/common/Stoppable.java new file mode 100644 index 00000000000..5b798071abe --- /dev/null +++ b/java/com.sap.sse.common/src/com/sap/sse/common/Stoppable.java @@ -0,0 +1,11 @@ +package com.sap.sse.common; + +/** + * Common definition for classes that hold resources that must be explicitly cleaned up. + * + * This can be used to e.g. recognize all {@link Stoppable} instance in a {@link org.osgi.framework.BundleActivator}. + * This makes it possible to cleanup all {@link Stoppable} instances in a loop to make the code much shorter. + */ +public interface Stoppable { + void stop(); +} diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java index ec813f73ee1..55dfc05d8c0 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java @@ -8,6 +8,8 @@ import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; +import com.sap.sse.common.Stoppable; + /** * Automatically registers/removes {@link PreferenceConverter} instances found in the OSGi service registry on the given * {@link UserStore}. @@ -15,7 +17,7 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; * {@link PreferenceConverter} found are required to have a property with the key * {@link PreferenceConverter#KEY_PARAMETER_NAME} defining the preference key the converter should be registered with. */ -public class PreferenceConverterRegistrationManager { +public class PreferenceConverterRegistrationManager implements Stoppable { private static final Logger logger = Logger.getLogger(PreferenceConverterRegistrationManager.class.getName()); private final BundleContext context; @@ -36,6 +38,7 @@ public class PreferenceConverterRegistrationManager { (Class) PreferenceConverter.class, new Cutomizer()); } + @Override public void stop() { tracker.close(); } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 9092876428a..bb54d9e8c75 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -10,6 +10,7 @@ import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import com.sap.sse.common.Stoppable; import com.sap.sse.common.Util; /** @@ -38,7 +39,7 @@ import com.sap.sse.common.Util; * @param * The type of object for which the users to notify is managed. */ -public abstract class PreferenceObjectBasedNotificationSet { +public abstract class PreferenceObjectBasedNotificationSet implements Stoppable { private static final Logger logger = Logger.getLogger(PreferenceObjectBasedNotificationSet.class.getName()); private final UserStore store; @@ -54,6 +55,7 @@ public abstract class PreferenceObjectBasedNotificationSet { store.addPreferenceObjectListener(key, listener, true); } + @Override public void stop() { store.removePreferenceObjectListener(listener); } From 0f441038fc127afba371d060945bf94b9b89a36c Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 13:51:30 +0200 Subject: [PATCH 154/259] PreferenceObjectBasedNotificationSet can now work with a ServiceTracker instead of a fixed UserStore instance --- .../PreferenceObjectBasedNotificationSet.java | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index bb54d9e8c75..69baacd70ce 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -10,6 +10,11 @@ import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + import com.sap.sse.common.Stoppable; import com.sap.sse.common.Util; @@ -42,7 +47,7 @@ import com.sap.sse.common.Util; public abstract class PreferenceObjectBasedNotificationSet implements Stoppable { private static final Logger logger = Logger.getLogger(PreferenceObjectBasedNotificationSet.class.getName()); - private final UserStore store; + private UserStore store; private final PreferenceObjectListener listener = new PreferenceObjectListenerImpl(); /** @@ -50,14 +55,41 @@ public abstract class PreferenceObjectBasedNotificationSet implements */ private final Map> notifications = new HashMap<>(); + private final BundleContext context; + + private final String key; + + private final ServiceTracker tracker; + + /** + * Constructor used to automatically track {@link UserStore} as OSGi service. + */ + public PreferenceObjectBasedNotificationSet(String key, BundleContext context) { + this.key = key; + this.context = context; + tracker = new ServiceTracker(context, UserStore.class, new Cutomizer()); + } + + /** + * Constructor used to work with a given {@link UserStore}. + */ public PreferenceObjectBasedNotificationSet(String key, UserStore store) { + this.key = key; this.store = store; + context = null; + tracker = null; store.addPreferenceObjectListener(key, listener, true); } @Override public void stop() { - store.removePreferenceObjectListener(listener); + if(tracker != null) { + tracker.close(); + } + if(store!= null) { + store.removePreferenceObjectListener(listener); + store = null; + } } protected abstract Collection calculateObjectsToNotify(PrefT preference); @@ -110,4 +142,33 @@ public abstract class PreferenceObjectBasedNotificationSet implements } } } + + private class Cutomizer implements ServiceTrackerCustomizer { + @Override + public UserStore addingService(ServiceReference reference) { + UserStore store = context.getService(reference); + if (PreferenceObjectBasedNotificationSet.this.store != null + && PreferenceObjectBasedNotificationSet.this.store != store) { + logger.severe("Multiple " + UserStore.class.getSimpleName() + + " instances found. Only one instance is handled."); + } else { + PreferenceObjectBasedNotificationSet.this.store = store; + store.addPreferenceObjectListener(key, listener, true); + } + return store; + } + + @Override + public void modifiedService(ServiceReference reference, UserStore service) { + // Should we do anything here? + } + + @Override + public void removedService(ServiceReference reference, UserStore service) { + if(PreferenceObjectBasedNotificationSet.this.store == service) { + service.removePreferenceObjectListener(listener); + PreferenceObjectBasedNotificationSet.this.store = null; + } + } + } } From b44afb3d3545d9ea3db53ebb9762af648179672f Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 13:55:25 +0200 Subject: [PATCH 155/259] Removed duplicate code and improved the cleanup implementation --- .../PreferenceObjectBasedNotificationSet.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 69baacd70ce..b9279074c21 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -83,13 +83,21 @@ public abstract class PreferenceObjectBasedNotificationSet implements @Override public void stop() { - if(tracker != null) { + if (tracker != null) { tracker.close(); } - if(store!= null) { + removeStore(); + } + + private void removeStore() { + if (store != null) { store.removePreferenceObjectListener(listener); store = null; } + // TODO use write lock + synchronized (notifications) { + notifications.clear(); + } } protected abstract Collection calculateObjectsToNotify(PrefT preference); @@ -160,14 +168,13 @@ public abstract class PreferenceObjectBasedNotificationSet implements @Override public void modifiedService(ServiceReference reference, UserStore service) { - // Should we do anything here? + // Should we do anything here? the preference key could have changed, but does this make any sense? } @Override public void removedService(ServiceReference reference, UserStore service) { - if(PreferenceObjectBasedNotificationSet.this.store == service) { - service.removePreferenceObjectListener(listener); - PreferenceObjectBasedNotificationSet.this.store = null; + if (PreferenceObjectBasedNotificationSet.this.store == service) { + removeStore(); } } } From c4e4ef25359597336f60f65b6c36379bb7068ec0 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 15:22:40 +0200 Subject: [PATCH 156/259] Fixed missing return in SailingDispatchContextImpl --- .../sap/sailing/gwt/home/server/SailingDispatchContextImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java index da641bf8ff0..77ea7adc903 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java @@ -81,7 +81,7 @@ public class SailingDispatchContextImpl implements SailingDispatchContext { public T getPreferenceForCurrentUser(String preferenceKey) { User currentUser = securityService.getCurrentUser(); if(currentUser != null) { - userStore.getPreferenceObject(currentUser.getName(), preferenceKey); + return userStore.getPreferenceObject(currentUser.getName(), preferenceKey); } return null; } From 9990ddf8d6ddd13952f4c62ced151c173ee35821 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 15:25:06 +0200 Subject: [PATCH 157/259] Added Comparable interface to BoatClassDTO --- .../com/sap/sailing/domain/common/dto/BoatClassDTO.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) mode change 100755 => 100644 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java old mode 100755 new mode 100644 index a07c883e36f..4282ada013f --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/dto/BoatClassDTO.java @@ -2,7 +2,7 @@ package com.sap.sailing.domain.common.dto; import java.io.Serializable; -public class BoatClassDTO extends NamedDTO implements Serializable { +public class BoatClassDTO extends NamedDTO implements Serializable, Comparable { private static final long serialVersionUID = 1981789833769906676L; /** @@ -34,4 +34,9 @@ public class BoatClassDTO extends NamedDTO implements Serializable { public String getDisplayName() { return displayName; } + + @Override + public int compareTo(BoatClassDTO o) { + return getName().compareToIgnoreCase(o.getName()); + } } From 16bfd3af2b372c1fe5e0be47f8a8b1bf93b9975d Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 15:25:48 +0200 Subject: [PATCH 158/259] Adjusted dispatch actions for saving favorite preferences --- .../user/profile/SaveFavoriteBoatClassesAction.java | 2 +- .../user/profile/SaveFavoriteCompetitorsAction.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java index 40238b92231..3f7bec7905e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteBoatClassesAction.java @@ -33,8 +33,8 @@ public class SaveFavoriteBoatClassesAction implements SailingAction public VoidResult execute(SailingDispatchContext ctx) throws DispatchException { BoatClassNotificationPreferences prefs = new BoatClassNotificationPreferences(ctx.getRacingEventService()); List boatClassPreferences = new ArrayList<>(); + DomainFactory domainFactory = ctx.getRacingEventService().getBaseDomainFactory(); for (BoatClassDTO boatClassDTO : favorites.getSelectedBoatClasses()) { - DomainFactory domainFactory = ctx.getRacingEventService().getBaseDomainFactory(); BoatClass boatClass = domainFactory.getOrCreateBoatClass(boatClassDTO.getName()); boatClassPreferences.add(new BoatClassNotificationPreference(domainFactory, boatClass, favorites.isNotifyAboutUpcomingRaces(), favorites.isNotifyAboutResults())); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java index 3eacf7ec1ba..1a7a3a8380b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/SaveFavoriteCompetitorsAction.java @@ -33,8 +33,8 @@ public class SaveFavoriteCompetitorsAction implements SailingAction public VoidResult execute(SailingDispatchContext ctx) throws DispatchException { CompetitorNotificationPreferences prefs = new CompetitorNotificationPreferences(ctx.getRacingEventService()); List competitorPreferences = new ArrayList<>(); + CompetitorStore competitorStore = ctx.getRacingEventService().getCompetitorStore(); for (SimpleCompetitorWithIdDTO competitorDTO : favorites.getSelectedCompetitors()) { - CompetitorStore competitorStore = ctx.getRacingEventService().getCompetitorStore(); Competitor competitor = competitorStore.getExistingCompetitorByIdAsString(competitorDTO.getIdAsString()); competitorPreferences.add(new CompetitorNotificationPreference(competitorStore, competitor, favorites.isNotifyAboutResults())); From d00b432a3da433ee57526dc42bd029d564defcad Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 15:26:55 +0200 Subject: [PATCH 159/259] Adjusted GetFavoritesAction to handle not existing preferences --- .../user/profile/GetFavoritesAction.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java index 55a488d79be..880c5ea966d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/communication/user/profile/GetFavoritesAction.java @@ -25,28 +25,34 @@ public class GetFavoritesAction implements SailingAction { return new FavoritesResult(getFavoriteBoatClasses(ctx), getFavoriteCompetitors(ctx)); } + @GwtIncompatible private FavoriteBoatClassesDTO getFavoriteBoatClasses(SailingDispatchContext ctx) { BoatClassNotificationPreferences preferences = ctx .getPreferenceForCurrentUser(BoatClassNotificationPreferences.PREF_NAME); TreeSet selected = new TreeSet<>(); boolean notifyAboutUpcomingRaces = false, notifyAboutResults = false; - for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { - String name = pref.getBoatClass().getName(), displayName = pref.getBoatClass().getDisplayName(); - selected.add(new BoatClassDTO(name, displayName, pref.getBoatClass().getHullLength().getMeters())); - notifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); - notifyAboutResults |= pref.isNotifyAboutResults(); + if (preferences != null) { + for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { + String name = pref.getBoatClass().getName(), displayName = pref.getBoatClass().getDisplayName(); + selected.add(new BoatClassDTO(name, displayName, pref.getBoatClass().getHullLength().getMeters())); + notifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); + notifyAboutResults |= pref.isNotifyAboutResults(); + } } return new FavoriteBoatClassesDTO(selected, notifyAboutUpcomingRaces, notifyAboutResults); } + @GwtIncompatible private FavoriteCompetitorsDTO getFavoriteCompetitors(SailingDispatchContext ctx) { CompetitorNotificationPreferences preferences = ctx .getPreferenceForCurrentUser(CompetitorNotificationPreferences.PREF_NAME); TreeSet selected = new TreeSet<>(); boolean notifyAboutResults = false; - for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { - selected.add(new SimpleCompetitorWithIdDTO(pref.getCompetitor())); - notifyAboutResults |= pref.isNotifyAboutResults(); + if (preferences != null) { + for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { + selected.add(new SimpleCompetitorWithIdDTO(pref.getCompetitor())); + notifyAboutResults |= pref.isNotifyAboutResults(); + } } return new FavoriteCompetitorsDTO(selected, notifyAboutResults); } From 415c98720b4913c517d9a8ec0802714a2121c24f Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 15:41:02 +0200 Subject: [PATCH 160/259] Adjusted UI components to work with favorite data transfer objects --- .../UserProfilePreferencesPresenter.java | 109 ++++++----------- .../UserProfilePreferencesViewImpl.java | 8 +- ...edMultiSelectionBoatClassDataProvider.java | 38 +++--- ...dMultiSelectionCompetitorDataProvider.java | 9 +- ...ctSuggestedMultiSelectionDataProvider.java | 4 +- .../selection/SuggestedMultiSelection.java | 22 ++-- ...edMultiSelectionBoatClassDataProvider.java | 10 +- ...ultiSelectionBoatClassItemDescription.java | 8 +- ...dMultiSelectionCompetitorDataProvider.java | 2 - .../UserProfilePreferencesActivity.java | 113 ++++++------------ .../UserProfilePreferencesViewImpl.java | 8 +- 11 files changed, 130 insertions(+), 201 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index c82689f3b5e..5b56edd7b52 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -1,35 +1,28 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; -import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreferences; -import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; -import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreferences; -import com.sap.sailing.domain.common.preferences.NotificationPreferences; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.communication.user.profile.CompetitorSuggestionResult; +import com.sap.sailing.gwt.home.communication.user.profile.FavoriteBoatClassesDTO; +import com.sap.sailing.gwt.home.communication.user.profile.FavoriteCompetitorsDTO; +import com.sap.sailing.gwt.home.communication.user.profile.FavoritesResult; import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggestionAction; -import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorsAction; +import com.sap.sailing.gwt.home.communication.user.profile.GetFavoritesAction; +import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteBoatClassesAction; +import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteCompetitorsAction; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; -import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; +import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; -import com.sap.sse.security.ui.client.UserService; public class UserProfilePreferencesPresenter implements UserProfilePreferencesView.Presenter { private final UserProfilePreferencesView view; private final UserProfileView.Presenter userProfilePresenter; - private NotificationPreferences notificationPreferences; private final SuggestedMultiSelectionCompetitorDataProvider competitorDataProvider = new SuggestedMultiSelectionCompetitorDataProviderImpl(); private final SuggestedMultiSelectionBoatClassDataProvider boatClassDataProvider = @@ -44,33 +37,8 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi @Override public void start() { - userProfilePresenter.getClientFactory().getUserService().getPreference(NotificationPreferences.PREF_NAME, - new NotificationPreferences(), new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - userProfilePresenter.getClientFactory().createErrorView( - "Error while loading notification preferences!", caught); - } - - @Override - public void onSuccess(NotificationPreferences result) { - notificationPreferences = result; - initFavoriteCompetitors(result.getCompetitorPreferences()); - initFavoriteBoatClasses(result.getBoatClassPreferences()); - } - }); - } - - private void initFavoriteCompetitors(CompetitorNotificationPreferences preferences) { - boolean initialNotifyAboutResults = false; - List favoriteCompetitorIds = new ArrayList<>(); - for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { - favoriteCompetitorIds.add(pref.getCompetitorId()); - initialNotifyAboutResults |= pref.isNotifyAboutResults(); - } - competitorDataProvider.initNotifications(initialNotifyAboutResults); - userProfilePresenter.getClientFactory().getDispatch().execute(new GetCompetitorsAction(favoriteCompetitorIds), - new AsyncCallback>() { + userProfilePresenter.getClientFactory().getDispatch().execute(new GetFavoritesAction(), + new AsyncCallback() { @Override public void onFailure(Throwable caught) { userProfilePresenter.getClientFactory() @@ -78,27 +46,22 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public void onSuccess(SortedSetResult result) { - competitorDataProvider.initSelectedItems(result.getValues()); + public void onSuccess(FavoritesResult result) { + initFavoriteCompetitors(result.getFavoriteCompetitors()); + initFavoriteBoatClasses(result.getFavoriteBoatClasses()); } }); } - private void initFavoriteBoatClasses(BoatClassNotificationPreferences preferences) { - boolean initialNotifyAboutResults = false, initialNotifyAboutUpcomingRaces = false; - List favoriteBoatClasses = new ArrayList<>(); - for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { - favoriteBoatClasses.add(pref.getBoatClass()); - initialNotifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); - initialNotifyAboutResults |= pref.isNotifyAboutResults(); - } - boatClassDataProvider.initSelectedItems(favoriteBoatClasses); - boatClassDataProvider.initNotifications(initialNotifyAboutUpcomingRaces, initialNotifyAboutResults); + private void initFavoriteCompetitors(FavoriteCompetitorsDTO favoriteCompetitors) { + competitorDataProvider.initNotifications(favoriteCompetitors.isNotifyAboutResults()); + competitorDataProvider.initSelectedItems(favoriteCompetitors.getSelectedCompetitors()); } - private void persistNotificationPreferences() { - UserService userService = userProfilePresenter.getClientFactory().getUserService(); - userService.setPreference(NotificationPreferences.PREF_NAME, notificationPreferences); + private void initFavoriteBoatClasses(FavoriteBoatClassesDTO favoriteBoatClasses) { + boatClassDataProvider.initNotifications(favoriteBoatClasses.isNotifyAboutUpcomingRaces(), + favoriteBoatClasses.isNotifyAboutResults()); + boatClassDataProvider.initSelectedItems(favoriteBoatClasses.getSelectedBoatClasses()); } @Override @@ -124,14 +87,9 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi private class SuggestedMultiSelectionBoatClassDataProviderImpl extends AbstractSuggestedMultiSelectionBoatClassDataProvider { @Override - public void persist(Collection selectedItems) { - List preferences = new ArrayList<>(); - for (BoatClassMasterdata boatClass : selectedItems) { - preferences.add(new BoatClassNotificationPreference(boatClass, - isNotifyAboutUpcomingRaces(), isNotifyAboutResults())); - } - notificationPreferences.getBoatClassPreferences().setBoatClasses(preferences); - UserProfilePreferencesPresenter.this.persistNotificationPreferences(); + protected void persist(FavoriteBoatClassesDTO favorites) { + userProfilePresenter.getClientFactory().getDispatch().execute( + new SaveFavoriteBoatClassesAction(favorites), new SaveAsyncCallback()); } } @@ -157,14 +115,21 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public void persist(Collection selectedItems) { - List preferences = new ArrayList<>(); - for (SimpleCompetitorWithIdDTO competitor : selectedItems) { - preferences.add(new CompetitorNotificationPreference( - competitor.getIdAsString(), isNotifyAboutResults())); - } - notificationPreferences.getCompetitorPreferences().setCompetitors(preferences); - UserProfilePreferencesPresenter.this.persistNotificationPreferences(); + protected void persist(FavoriteCompetitorsDTO favorites) { + userProfilePresenter.getClientFactory().getDispatch().execute(new SaveFavoriteCompetitorsAction(favorites), + new SaveAsyncCallback()); + } + } + + private class SaveAsyncCallback implements AsyncCallback { + @Override + public void onFailure(Throwable caught) { + userProfilePresenter.getClientFactory().createErrorView( + "Error while saving notification preferences!", caught); + } + + @Override + public void onSuccess(VoidResult result) { } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 8d5303fd9d4..2af403e0f24 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -9,7 +9,7 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection.NotificationCallback; @@ -28,7 +28,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @UiField(provided = true) AuthorizedContentDecoratorDesktop decoratorUi; @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; - @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; @UiField DivElement notificationsTextUi; @Override @@ -74,7 +74,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro } private class BoatClassDisplayImpl implements SuggestedMultiSelectionBoatClassDataProvider.Display { - private final SuggestedMultiSelection selectionUi; + private final SuggestedMultiSelection selectionUi; private final HasEnabled notifyAboutUpcomingRacesUi; private final HasEnabled notifyAboutResultsUi; @@ -96,7 +96,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro } @Override - public void setSelectedItems(Collection selectedItems) { + public void setSelectedItems(Collection selectedItems) { selectionUi.setSelectedItems(selectedItems); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java index 160b74bf8ab..6fe84cf23d1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java @@ -1,15 +1,18 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sse.common.Util; +import com.sap.sailing.domain.common.dto.BoatClassDTO; +import com.sap.sailing.gwt.home.communication.user.profile.FavoriteBoatClassesDTO; import com.sap.sse.common.filter.AbstractListFilter; public abstract class AbstractSuggestedMultiSelectionBoatClassDataProvider extends - AbstractSuggestedMultiSelectionDataProvider + AbstractSuggestedMultiSelectionDataProvider implements SuggestedMultiSelectionBoatClassDataProvider { private boolean notifyAboutUpcomingRaces; @@ -23,19 +26,23 @@ public abstract class AbstractSuggestedMultiSelectionBoatClassDataProvider exten }; protected AbstractSuggestedMultiSelectionBoatClassDataProvider() { - super(new ProvidesKey() { + super(new ProvidesKey() { @Override - public Object getKey(BoatClassMasterdata item) { - return item.getDisplayName(); + public Object getKey(BoatClassDTO item) { + return item.getName(); } }); } @Override protected void getSuggestions(Iterable queryTokens, int limit, - SuggestionItemsCallback callback) { + SuggestionItemsCallback callback) { List boatClasses = Arrays.asList(BoatClassMasterdata.values()); - callback.setSuggestionItems(Util.asList(filter.applyFilter(queryTokens, boatClasses))); + List suggestionItems = new ArrayList<>(); + for (BoatClassMasterdata bcm : filter.applyFilter(queryTokens, boatClasses)) { + suggestionItems.add(new BoatClassDTO(bcm.getDisplayName(), bcm.getHullLength().getMeters())); + } + callback.setSuggestionItems(suggestionItems); } @Override @@ -48,26 +55,23 @@ public abstract class AbstractSuggestedMultiSelectionBoatClassDataProvider exten } } - @Override - public boolean isNotifyAboutUpcomingRaces() { - return notifyAboutUpcomingRaces; - } - @Override public void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces) { this.notifyAboutUpcomingRaces = notifyAboutUpcomingRaces; this.persist(); } - @Override - public boolean isNotifyAboutResults() { - return notifyAboutResults; - } - @Override public void setNotifyAboutResults(boolean notifyAboutResults) { this.notifyAboutResults = notifyAboutResults; this.persist(); } + @Override + protected final void persist(Collection selectedItem) { + this.persist(new FavoriteBoatClassesDTO(selectedItem, notifyAboutUpcomingRaces, notifyAboutResults)); + } + + protected abstract void persist(FavoriteBoatClassesDTO favorites); + } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java index d470a82a7a3..74bcf079df0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java @@ -1,7 +1,10 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +import java.util.Collection; + import com.google.gwt.view.client.ProvidesKey; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; +import com.sap.sailing.gwt.home.communication.user.profile.FavoriteCompetitorsDTO; public abstract class AbstractSuggestedMultiSelectionCompetitorDataProvider extends AbstractSuggestedMultiSelectionDataProvider @@ -33,8 +36,10 @@ public abstract class AbstractSuggestedMultiSelectionCompetitorDataProvider exte } @Override - public boolean isNotifyAboutResults() { - return notifyAboutResults; + protected final void persist(Collection selectedItem) { + this.persist(new FavoriteCompetitorsDTO(selectedItem, notifyAboutResults)); } + + protected abstract void persist(FavoriteCompetitorsDTO favorites); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java index d98bda887f3..3f3f64fe8be 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java @@ -23,7 +23,7 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider(selectedItemsMap.values())); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java index e8221f08c59..21b907c0a87 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java @@ -16,7 +16,7 @@ import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.SuggestOracle.Callback; import com.google.gwt.user.client.ui.SuggestOracle.Request; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.SuggestionItemsCallback; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractAsyncSuggestBoxFilter; @@ -176,26 +176,26 @@ public final class SuggestedMultiSelection extends Composite implements Sugge }, headerTitle); } - public static SuggestedMultiSelection forBoatClasses( - final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { - return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { + public static SuggestedMultiSelection forBoatClasses( + final SuggestedMultiSelectionDataProvider dataProvider, String headerTitle) { + return new SuggestedMultiSelection<>(dataProvider, new WidgetProvider() { @Override - public IsWidget getItemDescriptionWidget(BoatClassMasterdata item) { + public IsWidget getItemDescriptionWidget(BoatClassDTO item) { return new SuggestedMultiSelectionBoatClassItemDescription(item); } @Override - public AbstractSuggestBoxFilter getSuggestBoxFilter( - SelectionCallback selectionCallback) { - return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, + public AbstractSuggestBoxFilter getSuggestBoxFilter( + SelectionCallback selectionCallback) { + return new AbstractSuggestedMultiSelectionFilter(dataProvider, selectionCallback, StringMessages.INSTANCE.add(StringMessages.INSTANCE.boatClass())) { @Override - protected String createSuggestionKeyString(BoatClassMasterdata value) { - return value.getDisplayName(); + protected String createSuggestionKeyString(BoatClassDTO value) { + return value.getName(); } @Override - protected String createSuggestionAdditionalDisplayString(BoatClassMasterdata value) { + protected String createSuggestionAdditionalDisplayString(BoatClassDTO value) { return null; } }; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassDataProvider.java index d53beca14a4..627c44bce1a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassDataProvider.java @@ -1,22 +1,18 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; -import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider.Display; public interface SuggestedMultiSelectionBoatClassDataProvider - extends SuggestedMultiSelectionDataProvider { - - boolean isNotifyAboutUpcomingRaces(); + extends SuggestedMultiSelectionDataProvider { void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces); - boolean isNotifyAboutResults(); - void setNotifyAboutResults(boolean notifyAboutResults); void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults); - interface Display extends SuggestedMultiSelectionDataProvider.Display { + interface Display extends SuggestedMultiSelectionDataProvider.Display { void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java index 91429f69ea6..54b145abcfc 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java @@ -7,7 +7,7 @@ import com.google.gwt.dom.client.SpanElement; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.common.client.BoatClassImageResolver; class SuggestedMultiSelectionBoatClassItemDescription extends Widget { @@ -20,11 +20,11 @@ class SuggestedMultiSelectionBoatClassItemDescription extends Widget { @UiField DivElement imageUi; @UiField SpanElement nameUi; - SuggestedMultiSelectionBoatClassItemDescription(BoatClassMasterdata boatClass) { + SuggestedMultiSelectionBoatClassItemDescription(BoatClassDTO boatClass) { setElement(uiBinder.createAndBindUi(this)); imageUi.getStyle().setBackgroundImage("url('" + BoatClassImageResolver.getBoatClassIconResource( - boatClass.getDisplayName()).getSafeUri().asString() + "')"); - nameUi.setInnerText(boatClass.getDisplayName()); + boatClass.getName()).getSafeUri().asString() + "')"); + nameUi.setInnerText(boatClass.getName()); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java index dc332e26322..104a9bc8576 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java @@ -6,8 +6,6 @@ import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedM public interface SuggestedMultiSelectionCompetitorDataProvider extends SuggestedMultiSelectionDataProvider { - boolean isNotifyAboutResults(); - void setNotifyAboutResults(boolean notifyAboutResults); void initNotifications(boolean notifyAboutResults); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java index 44497d091a8..e12cee6ba52 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java @@ -1,33 +1,27 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile.preferences; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import com.google.gwt.activity.shared.AbstractActivity; import com.google.gwt.event.shared.EventBus; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.AcceptsOneWidget; -import com.sap.sailing.domain.common.BoatClassMasterdata; -import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreference; -import com.sap.sailing.domain.common.preferences.BoatClassNotificationPreferences; -import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreference; -import com.sap.sailing.domain.common.preferences.CompetitorNotificationPreferences; -import com.sap.sailing.domain.common.preferences.NotificationPreferences; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.communication.user.profile.CompetitorSuggestionResult; +import com.sap.sailing.gwt.home.communication.user.profile.FavoriteBoatClassesDTO; +import com.sap.sailing.gwt.home.communication.user.profile.FavoriteCompetitorsDTO; +import com.sap.sailing.gwt.home.communication.user.profile.FavoritesResult; import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggestionAction; -import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorsAction; +import com.sap.sailing.gwt.home.communication.user.profile.GetFavoritesAction; +import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteBoatClassesAction; +import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteCompetitorsAction; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; -import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; +import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; import com.sap.sse.security.ui.authentication.AuthenticationContextEvent; -import com.sap.sse.security.ui.client.UserService; public class UserProfilePreferencesActivity extends AbstractActivity implements UserProfilePreferencesView.Presenter { @@ -38,9 +32,8 @@ public class UserProfilePreferencesActivity extends AbstractActivity implements private final SuggestedMultiSelectionBoatClassDataProvider boatClassDataProvider = new SuggestedMultiSelectionBoatClassDataProviderImpl(); - private NotificationPreferences notificationPreferences; - - public UserProfilePreferencesActivity(UserProfilePreferencesPlace place, MobileApplicationClientFactory clientFactory) { + public UserProfilePreferencesActivity(UserProfilePreferencesPlace place, + MobileApplicationClientFactory clientFactory) { this.clientFactory = clientFactory; this.currentView = new UserProfilePreferencesViewImpl(this); } @@ -55,60 +48,29 @@ public class UserProfilePreferencesActivity extends AbstractActivity implements currentView.setAuthenticationContext(event.getCtx()); } }); - - clientFactory.getUserService().getPreference(NotificationPreferences.PREF_NAME, - new NotificationPreferences(), new AsyncCallback() { + clientFactory.getDispatch().execute(new GetFavoritesAction(), new AsyncCallback() { @Override public void onFailure(Throwable caught) { - clientFactory.createErrorView("Error while loading notification preferences!", caught); + clientFactory.createErrorView("Error while loading notification preferences!", caught); } - + @Override - public void onSuccess(NotificationPreferences result) { - notificationPreferences = result; - initFavoriteCompetitors(result.getCompetitorPreferences()); - initFavoriteBoatClasses(result.getBoatClassPreferences()); + public void onSuccess(FavoritesResult result) { + initFavoriteCompetitors(result.getFavoriteCompetitors()); + initFavoriteBoatClasses(result.getFavoriteBoatClasses()); } }); } - private void initFavoriteCompetitors(CompetitorNotificationPreferences preferences) { - boolean initialNotifyAboutResults = false; - List favoriteCompetitorIds = new ArrayList<>(); - for (CompetitorNotificationPreference pref : preferences.getCompetitors()) { - favoriteCompetitorIds.add(pref.getCompetitorId()); - initialNotifyAboutResults |= pref.isNotifyAboutResults(); - } - competitorDataProvider.initNotifications(initialNotifyAboutResults); - clientFactory.getDispatch().execute(new GetCompetitorsAction(favoriteCompetitorIds), - new AsyncCallback>() { - @Override - public void onFailure(Throwable caught) { - clientFactory.createErrorView("Error while loading notification preferences!", caught); - } - - @Override - public void onSuccess(SortedSetResult result) { - competitorDataProvider.initSelectedItems(result.getValues()); - } - }); + private void initFavoriteCompetitors(FavoriteCompetitorsDTO favoriteCompetitors) { + competitorDataProvider.initNotifications(favoriteCompetitors.isNotifyAboutResults()); + competitorDataProvider.initSelectedItems(favoriteCompetitors.getSelectedCompetitors()); } - private void initFavoriteBoatClasses(BoatClassNotificationPreferences preferences) { - boolean initialNotifyAboutResults = false, initialNotifyAboutUpcomingRaces = false; - List favoriteBoatClasses = new ArrayList<>(); - for (BoatClassNotificationPreference pref : preferences.getBoatClasses()) { - favoriteBoatClasses.add(pref.getBoatClass()); - initialNotifyAboutUpcomingRaces |= pref.isNotifyAboutUpcomingRaces(); - initialNotifyAboutResults |= pref.isNotifyAboutResults(); - } - boatClassDataProvider.initSelectedItems(favoriteBoatClasses); - boatClassDataProvider.initNotifications(initialNotifyAboutUpcomingRaces, initialNotifyAboutResults); - } - - private void persistNotificationPreferences() { - UserService userService = clientFactory.getUserService(); - userService.setPreference(NotificationPreferences.PREF_NAME, notificationPreferences); + private void initFavoriteBoatClasses(FavoriteBoatClassesDTO favoriteBoatClasses) { + boatClassDataProvider.initNotifications(favoriteBoatClasses.isNotifyAboutUpcomingRaces(), + favoriteBoatClasses.isNotifyAboutResults()); + boatClassDataProvider.initSelectedItems(favoriteBoatClasses.getSelectedBoatClasses()); } @Override @@ -129,14 +91,8 @@ public class UserProfilePreferencesActivity extends AbstractActivity implements private class SuggestedMultiSelectionBoatClassDataProviderImpl extends AbstractSuggestedMultiSelectionBoatClassDataProvider { @Override - public void persist(Collection selectedItems) { - List preferences = new ArrayList<>(); - for (BoatClassMasterdata boatClass : selectedItems) { - preferences.add(new BoatClassNotificationPreference(boatClass, - isNotifyAboutUpcomingRaces(), isNotifyAboutResults())); - } - notificationPreferences.getBoatClassPreferences().setBoatClasses(preferences); - UserProfilePreferencesActivity.this.persistNotificationPreferences(); + protected void persist(FavoriteBoatClassesDTO favorites) { + clientFactory.getDispatch().execute(new SaveFavoriteBoatClassesAction(favorites), new SaveAsyncCallback()); } } @@ -161,14 +117,19 @@ public class UserProfilePreferencesActivity extends AbstractActivity implements } @Override - public void persist(Collection selectedItems) { - List preferences = new ArrayList<>(); - for (SimpleCompetitorWithIdDTO competitor : selectedItems) { - preferences.add(new CompetitorNotificationPreference( - competitor.getIdAsString(), isNotifyAboutResults())); - } - notificationPreferences.getCompetitorPreferences().setCompetitors(preferences); - UserProfilePreferencesActivity.this.persistNotificationPreferences(); + protected void persist(FavoriteCompetitorsDTO favorites) { + clientFactory.getDispatch().execute(new SaveFavoriteCompetitorsAction(favorites), new SaveAsyncCallback()); + } + } + + private class SaveAsyncCallback implements AsyncCallback { + @Override + public void onFailure(Throwable caught) { + clientFactory.createErrorView("Error while saving notification preferences!", caught); + } + + @Override + public void onSuccess(VoidResult result) { } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java index b5bbb36b4d3..c3ec62149d3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java @@ -9,7 +9,7 @@ import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.domain.common.BoatClassMasterdata; +import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; @@ -31,7 +31,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro @UiField(provided = true) final UserHeader userHeaderUi; @UiField(provided = true) final AuthorizedContentDecoratorMobile decoratorUi; @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; - @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; + @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; @UiField DivElement notificationsTextUi; public UserProfilePreferencesViewImpl(Presenter presenter) { @@ -77,7 +77,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro } private class BoatClassDisplayImpl implements SuggestedMultiSelectionBoatClassDataProvider.Display { - private final SuggestedMultiSelection selectionUi; + private final SuggestedMultiSelection selectionUi; private final HasEnabled notifyAboutUpcomingRacesUi; private final HasEnabled notifyAboutResultsUi; @@ -99,7 +99,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro } @Override - public void setSelectedItems(Collection selectedItems) { + public void setSelectedItems(Collection selectedItems) { selectionUi.setSelectedItems(selectedItems); } From c4b29d4ec9c66a15d6a21d798b614bb8e36166e7 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Mon, 11 Jul 2016 15:43:14 +0200 Subject: [PATCH 161/259] Code format --- .../sailing/gwt/home/server/SailingDispatchContextImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java index 77ea7adc903..9ca7f1f0d22 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/server/SailingDispatchContextImpl.java @@ -80,7 +80,7 @@ public class SailingDispatchContextImpl implements SailingDispatchContext { @Override public T getPreferenceForCurrentUser(String preferenceKey) { User currentUser = securityService.getCurrentUser(); - if(currentUser != null) { + if (currentUser != null) { return userStore.getPreferenceObject(currentUser.getName(), preferenceKey); } return null; @@ -89,7 +89,7 @@ public class SailingDispatchContextImpl implements SailingDispatchContext { @Override public void setPreferenceForCurrentUser(String preferenceKey, Object preference) { User currentUser = securityService.getCurrentUser(); - if(currentUser != null) { + if (currentUser != null) { userStore.setPreferenceObject(currentUser.getName(), preferenceKey, preference); } } From f58cf732473d56f7d037b98211ee2b1fdc9c6eb3 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 16:03:03 +0200 Subject: [PATCH 162/259] Adjusted initialization of desktop preferences page --- .../UserProfilePreferencesPresenter.java | 36 +++++++++---------- .../UserProfilePreferencesTabView.java | 1 - .../UserProfilePreferencesView.java | 1 - 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 5b56edd7b52..9a08bb4f7b5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -36,21 +36,24 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi } @Override - public void start() { - userProfilePresenter.getClientFactory().getDispatch().execute(new GetFavoritesAction(), - new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - userProfilePresenter.getClientFactory() - .createErrorView("Error while loading notification preferences!", caught); - } + public void setAuthenticationContext(AuthenticationContext authenticationContext) { + view.getDecorator().setAuthenticationContext(authenticationContext); + if (authenticationContext.isLoggedIn()) { + userProfilePresenter.getClientFactory().getDispatch().execute(new GetFavoritesAction(), + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + userProfilePresenter.getClientFactory() + .createErrorView("Error while loading notification preferences!", caught); + } - @Override - public void onSuccess(FavoritesResult result) { - initFavoriteCompetitors(result.getFavoriteCompetitors()); - initFavoriteBoatClasses(result.getFavoriteBoatClasses()); - } - }); + @Override + public void onSuccess(FavoritesResult result) { + initFavoriteCompetitors(result.getFavoriteCompetitors()); + initFavoriteBoatClasses(result.getFavoriteBoatClasses()); + } + }); + } } private void initFavoriteCompetitors(FavoriteCompetitorsDTO favoriteCompetitors) { @@ -64,11 +67,6 @@ public class UserProfilePreferencesPresenter implements UserProfilePreferencesVi boatClassDataProvider.initSelectedItems(favoriteBoatClasses.getSelectedBoatClasses()); } - @Override - public void setAuthenticationContext(AuthenticationContext authenticationContext) { - view.getDecorator().setAuthenticationContext(authenticationContext); - } - @Override public void doTriggerLoginForm() { userProfilePresenter.doTriggerLoginForm(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java index c6d28ad1d07..5429da2ac33 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java @@ -26,7 +26,6 @@ public class UserProfilePreferencesTabView extends Composite implements UserProf @Override public void start(UserProfilePreferencesPlace myPlace, AcceptsOneWidget contentArea) { contentArea.setWidget(view); - currentPresenter.start(); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index 6c592e89f26..6caaf5a4f0c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -15,6 +15,5 @@ public interface UserProfilePreferencesView extends IsWidget { public interface Presenter extends NotLoggedInPresenter, NeedsAuthenticationContext { SuggestedMultiSelectionBoatClassDataProvider getFavoriteBoatClassesDataProvider(); SuggestedMultiSelectionCompetitorDataProvider getFavoriteCompetitorsDataProvider(); - void start(); } } \ No newline at end of file From 9a49d4ef191bf90f6618447b14dbc0654757d275 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 17:18:20 +0200 Subject: [PATCH 163/259] Introduced new interface for mobile user profile views --- .../places/user/profile/UserProfileViewBase.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java new file mode 100644 index 00000000000..22a23fbc063 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java @@ -0,0 +1,12 @@ +package com.sap.sailing.gwt.home.mobile.places.user.profile; + +import com.google.gwt.user.client.ui.IsWidget; +import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; +import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; + +public interface UserProfileViewBase extends IsWidget, NeedsAuthenticationContext { + + public interface Presenter extends NotLoggedInPresenter { + + } +} From 38e743bae4eb9811396a4470fc7d18dcfb742dbf Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 17:19:36 +0200 Subject: [PATCH 164/259] Introduced new abstract class for mobile user profile views --- .../user/profile/AbstractUserProfileView.java | 52 +++++++++++++++++++ .../profile/AbstractUserProfileView.ui.xml | 16 ++++++ 2 files changed, 68 insertions(+) create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java create mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java new file mode 100644 index 00000000000..59796fae232 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java @@ -0,0 +1,52 @@ +package com.sap.sailing.gwt.home.mobile.places.user.profile; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.IsWidget; +import com.google.gwt.user.client.ui.SimplePanel; +import com.google.gwt.user.client.ui.Widget; +import com.sap.sailing.gwt.common.client.SharedResources; +import com.sap.sailing.gwt.home.mobile.partials.quickfinder.Quickfinder; +import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorMobile; +import com.sap.sse.security.ui.authentication.app.AuthenticationContext; +import com.sap.sse.security.ui.userprofile.mobile.userheader.UserHeader; + +public class AbstractUserProfileView extends Composite implements UserProfileViewBase { + + private static AbstractUserProfileViewUiBinder uiBinder = GWT.create(AbstractUserProfileViewUiBinder.class); + + interface AbstractUserProfileViewUiBinder extends UiBinder { + } + + static class AbstractUserProfileViewLayout { + @UiField(provided = true) final AuthorizedContentDecoratorMobile decoratorUi; + @UiField(provided = true) final UserHeader userHeaderUi; + @UiField Quickfinder quickfinderUi; + @UiField SimplePanel contentContainerUi; + + private AbstractUserProfileViewLayout(UserProfileViewBase.Presenter presenter) { + this.decoratorUi = new AuthorizedContentDecoratorMobile(presenter); + this.userHeaderUi = new UserHeader(SharedResources.INSTANCE); + } + } + + private final AbstractUserProfileViewLayout layout; + + protected AbstractUserProfileView(UserProfileViewBase.Presenter presenter) { + this.layout = new AbstractUserProfileViewLayout(presenter); + initWidget(uiBinder.createAndBindUi(this.layout)); + } + + protected final void setViewContent(IsWidget content) { + this.layout.contentContainerUi.setWidget(content); + } + + @Override + public void setAuthenticationContext(AuthenticationContext authenticationContext) { + this.layout.decoratorUi.setAuthenticationContext(authenticationContext); + this.layout.userHeaderUi.setAuthenticationContext(authenticationContext); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml new file mode 100644 index 00000000000..244c63c8043 --- /dev/null +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + \ No newline at end of file From 0aace5d8e7fc2ffbd1d1acd4c938c9eecf4a24fc Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 17:24:20 +0200 Subject: [PATCH 165/259] Refactored mobile UserProfileDetailsView to use new abstraction --- .../details/UserProfileDetailsView.java | 8 ++--- .../details/UserProfileDetailsViewImpl.java | 32 ++++--------------- .../details/UserProfileDetailsViewImpl.ui.xml | 14 -------- 3 files changed, 9 insertions(+), 45 deletions(-) delete mode 100644 java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.ui.xml diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsView.java index 09b818447c7..2379450979d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsView.java @@ -1,15 +1,13 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile.details; -import com.google.gwt.user.client.ui.IsWidget; -import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; -import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; +import com.sap.sailing.gwt.home.mobile.places.user.profile.UserProfileViewBase; import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView; -public interface UserProfileDetailsView extends IsWidget, NeedsAuthenticationContext { +public interface UserProfileDetailsView extends UserProfileViewBase { UserDetailsView getUserDetailsView(); - public interface Presenter extends NotLoggedInPresenter { + public interface Presenter extends UserProfileViewBase.Presenter { } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.java index 61554825f04..a618bfa0aa7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.java @@ -1,32 +1,17 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile.details; -import com.google.gwt.core.client.GWT; -import com.google.gwt.uibinder.client.UiBinder; -import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.ui.Composite; -import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.common.client.SharedResources; -import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorMobile; -import com.sap.sse.security.ui.authentication.app.AuthenticationContext; +import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileView; import com.sap.sse.security.ui.userprofile.mobile.userdetails.UserDetails; -import com.sap.sse.security.ui.userprofile.mobile.userheader.UserHeader; import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsView; -public class UserProfileDetailsViewImpl extends Composite implements UserProfileDetailsView { - private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); +public class UserProfileDetailsViewImpl extends AbstractUserProfileView implements UserProfileDetailsView { - interface MyUiBinder extends UiBinder { - } - - @UiField(provided = true) final UserHeader userHeaderUi; - @UiField(provided = true) final AuthorizedContentDecoratorMobile decoratorUi; - @UiField(provided = true) final UserDetails userDetailsUi; + private final UserDetails userDetailsUi = new UserDetails(SharedResources.INSTANCE); - public UserProfileDetailsViewImpl(Presenter presenter) { - userHeaderUi = new UserHeader(SharedResources.INSTANCE); - decoratorUi = new AuthorizedContentDecoratorMobile(presenter); - userDetailsUi = new UserDetails(SharedResources.INSTANCE); - initWidget(uiBinder.createAndBindUi(this)); + public UserProfileDetailsViewImpl(UserProfileDetailsView.Presenter presenter) { + super(presenter); + setViewContent(userDetailsUi); } @Override @@ -34,9 +19,4 @@ public class UserProfileDetailsViewImpl extends Composite implements UserProfile return userDetailsUi; } - @Override - public void setAuthenticationContext(AuthenticationContext authenticationContext) { - userHeaderUi.setAuthenticationContext(authenticationContext); - decoratorUi.setAuthenticationContext(authenticationContext); - } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.ui.xml deleted file mode 100644 index e6d16a49d82..00000000000 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsViewImpl.ui.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - From 5ec8de53c03fb52964a57181703ca8b017d597c9 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 17:34:27 +0200 Subject: [PATCH 166/259] Refactored mobile UserProfilePreferencesView to use new abstraction --- .../UserProfilePreferencesView.java | 8 ++--- .../UserProfilePreferencesViewImpl.java | 23 ++++----------- .../UserProfilePreferencesViewImpl.ui.xml | 29 +++++++------------ 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java index 7597ea3ec17..ae82532f01e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java @@ -1,14 +1,12 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile.preferences; -import com.google.gwt.user.client.ui.IsWidget; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; -import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; -import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; +import com.sap.sailing.gwt.home.mobile.places.user.profile.UserProfileViewBase; -public interface UserProfilePreferencesView extends IsWidget, NeedsAuthenticationContext { +public interface UserProfilePreferencesView extends UserProfileViewBase { - public interface Presenter extends NotLoggedInPresenter { + public interface Presenter extends UserProfileViewBase.Presenter { SuggestedMultiSelectionBoatClassDataProvider getFavoriteBoatClassesDataProvider(); SuggestedMultiSelectionCompetitorDataProvider getFavoriteCompetitorsDataProvider(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java index c3ec62149d3..c2442b00598 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java @@ -6,48 +6,35 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; -import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.dto.BoatClassDTO; -import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection.NotificationCallback; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; -import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorMobile; +import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileView; import com.sap.sailing.gwt.ui.client.StringMessages; -import com.sap.sse.security.ui.authentication.app.AuthenticationContext; -import com.sap.sse.security.ui.userprofile.mobile.userheader.UserHeader; -public class UserProfilePreferencesViewImpl extends Composite implements UserProfilePreferencesView { +public class UserProfilePreferencesViewImpl extends AbstractUserProfileView implements UserProfilePreferencesView { private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); interface MyUiBinder extends UiBinder { } private final StringMessages i18n = StringMessages.INSTANCE; - @UiField(provided = true) final UserHeader userHeaderUi; - @UiField(provided = true) final AuthorizedContentDecoratorMobile decoratorUi; @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; @UiField DivElement notificationsTextUi; - public UserProfilePreferencesViewImpl(Presenter presenter) { - userHeaderUi = new UserHeader(SharedResources.INSTANCE); - decoratorUi = new AuthorizedContentDecoratorMobile(presenter); + public UserProfilePreferencesViewImpl(UserProfilePreferencesView.Presenter presenter) { + super(presenter); favoriteCompetitorsSelctionUi = new CompetitorDisplayImpl( presenter.getFavoriteCompetitorsDataProvider()).selectionUi; favoriteBoatClassesSelctionUi = new BoatClassDisplayImpl( presenter.getFavoriteBoatClassesDataProvider()).selectionUi; - initWidget(uiBinder.createAndBindUi(this)); - } - - @Override - public void setAuthenticationContext(AuthenticationContext authenticationContext) { - userHeaderUi.setAuthenticationContext(authenticationContext); - decoratorUi.setAuthenticationContext(authenticationContext); + setViewContent(uiBinder.createAndBindUi(this)); } private class CompetitorDisplayImpl implements SuggestedMultiSelectionCompetitorDataProvider.Display { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml index f12a62fdf6f..a83d729a98c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml @@ -13,22 +13,15 @@ border-right: none; } - - - - - -
        - -
        -
        - -
        -
        - -
        -
        -
        -
        -
        + +
        + +
        +
        + +
        +
        + +
        +
        From 0634818daa78879cea07b851cb1a221ce790c005 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 17:41:27 +0200 Subject: [PATCH 167/259] Added user preferences navigation to MobilePlacesNavigator --- .../sailing/gwt/home/mobile/app/MobilePlacesNavigator.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java index 3723e1ac40d..81b99f7806c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java @@ -28,6 +28,7 @@ import com.sap.sailing.gwt.home.shared.places.user.confirmation.ConfirmationPlac import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetPlace; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDefaultPlace; +import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; public class MobilePlacesNavigator extends AbstractPlaceNavigator { @@ -105,6 +106,10 @@ public class MobilePlacesNavigator extends AbstractPlaceNavigator { public PlaceNavigation getUserProfileNavigation() { return createLocalPlaceNavigation(new UserProfileDefaultPlace()); } + + public PlaceNavigation getUserPreferencesNavigation() { + return createLocalPlaceNavigation(new UserProfilePreferencesPlace()); + } public PlaceNavigation getMailVerifiedConfirmationNavigation() { return createLocalPlaceNavigation(new ConfirmationPlace(Action.MAIL_VERIFIED)); From 94a85e9332db849ddd87e622eb2d7b28a04c6366 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 18:12:31 +0200 Subject: [PATCH 168/259] Added and adjusted i18n StringMessages --- .../user/profile/TabletAndDesktopUserProfileView.ui.xml | 2 +- .../preferencestab/UserProfilePreferencesViewImpl.java | 4 ++-- .../preferences/UserProfilePreferencesViewImpl.java | 4 ++-- .../java/com/sap/sailing/gwt/ui/client/StringMessages.java | 7 ++++--- .../sap/sailing/gwt/ui/client/StringMessages.properties | 7 ++++--- .../sap/sailing/gwt/ui/client/StringMessages_de.properties | 7 ++++--- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml index 8a7b9e6c892..1cc220e8092 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/TabletAndDesktopUserProfileView.ui.xml @@ -45,7 +45,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 2af403e0f24..5ef849b1fb8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -52,7 +52,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro private final HasEnabled notifyAboutResultsUi; private CompetitorDisplayImpl(final SuggestedMultiSelectionCompetitorDataProvider dataProvider) { - selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, StringMessages.INSTANCE.favouriteCompetitors()); + selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, StringMessages.INSTANCE.favoriteCompetitors()); notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override public void onNotificationToggled(boolean enabled) { @@ -79,7 +79,7 @@ public class UserProfilePreferencesViewImpl extends Composite implements UserPro private final HasEnabled notifyAboutResultsUi; private BoatClassDisplayImpl(final SuggestedMultiSelectionBoatClassDataProvider dataProvider) { - selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, StringMessages.INSTANCE.favouriteBoatClasses()); + selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, StringMessages.INSTANCE.favoriteBoatClasses()); notifyAboutUpcomingRacesUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override public void onNotificationToggled(boolean enabled) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java index c2442b00598..8b3f7d5c306 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java @@ -42,7 +42,7 @@ public class UserProfilePreferencesViewImpl extends AbstractUserProfileView impl private final HasEnabled notifyAboutResultsUi; private CompetitorDisplayImpl(final SuggestedMultiSelectionCompetitorDataProvider dataProvider) { - selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, i18n.favouriteCompetitors()); + selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, i18n.favoriteCompetitors()); notifyAboutResultsUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override public void onNotificationToggled(boolean enabled) { @@ -69,7 +69,7 @@ public class UserProfilePreferencesViewImpl extends AbstractUserProfileView impl private final HasEnabled notifyAboutResultsUi; private BoatClassDisplayImpl(final SuggestedMultiSelectionBoatClassDataProvider dataProvider) { - selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, i18n.favouriteBoatClasses()); + selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, i18n.favoriteBoatClasses()); notifyAboutUpcomingRacesUi = selectionUi.addNotificationToggle(new NotificationCallback() { @Override public void onNotificationToggled(boolean enabled) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 8070e0a3075..31f3e439295 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1378,6 +1378,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String regattaQuickfinder(); String resultsQuickfinder(); String racesQuickfinder(); + String profileQuickfinder(); String statistics(); String impressions(); String notAvailableOnMobileMessage(); @@ -1619,9 +1620,9 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String userNotificationsOnlyIfMailAddressIsVerified(); String enabled(); String disabled(); - String favouritesAndNotifications(); - String favouriteCompetitors(); - String favouriteBoatClasses(); + String favoritesAndNotifications(); + String favoriteCompetitors(); + String favoriteBoatClasses(); String notificationAboutNewResults(); String notificationAboutUpcomingRaces(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index ee8bc8cbc69..0f1cbd99bbb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1346,6 +1346,7 @@ eventQuickfinder=Event Quickfinder regattaQuickfinder=Regatta Quickfinder resultsQuickfinder=Results Quickfinder racesQuickfinder=Races Quickfinder +profileQuickfinder=Profile Quickfinder statistics=Statistics impressions=Impressions notAvailableOnMobileMessage=This content is not available on mobile.\nSwitch to the desktop version? @@ -1586,9 +1587,9 @@ showWindChart=Show wind chart userNotificationsOnlyIfMailAddressIsVerified=Due to privacy reasons, mail notifications require that you enter your mail address on the user profile page and verify this mail address. enabled=Enabled disabled=Disabled -favouritesAndNotifications=Favourites/Notifications -favouriteCompetitors=Favourite competitors -favouriteBoatClasses=Favourite boat classes +favoritesAndNotifications=Favorites/Notifications +favoriteCompetitors=Favorite competitors +favoriteBoatClasses=Favorite boat classes notificationAboutNewResults=Send notifications about new results notificationAboutUpcomingRaces=Send notifications about upcoming races currentRideHeightInMeters=Ride Height diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index ef7adbc2a5f..1bd1b9375b9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1334,6 +1334,7 @@ eventQuickfinder=Veranstaltung-Schnellauswahl regattaQuickfinder=Regatta-Schnellauswahl resultsQuickfinder=Ergebnis-Schnellauswahl racesQuickfinder=Wettfahrt-Schnellauswahl +profileQuickfinder=Profil-Schnellauswahl statistics=Statistiken impressions=Eindrücke notAvailableOnMobileMessage=Diese Ansicht ist noch nicht für die Mobile bzw. Smartphone Ansicht umgesetzt.\nWollen Sie die Desktop Ansicht besuchen? @@ -1571,9 +1572,9 @@ showWindChart=Windiagramm zeigen userNotificationsOnlyIfMailAddressIsVerified=Aus Gründen des Datenschutzes können Benachrichtigungen nur verwendet werden, wenn im Benutzerprofil eine gültige Mail-Adresse angegeben und diese verfifiziert wurde. enabled=Aktiviert disabled=Deaktiviert -favouritesAndNotifications=Favoriten/Benachrichtigungen -favouriteCompetitors=Favorisierte Teilnehmer -favouriteBoatClasses=Favorisierte Bootsklassen +favoritesAndNotifications=Favoriten/Benachrichtigungen +favoriteCompetitors=Favorisierte Teilnehmer +favoriteBoatClasses=Favorisierte Bootsklassen notificationAboutNewResults=Über neue Ergebnisse informieren notificationAboutUpcomingRaces=Über demnächst stattfindende Rennen informieren currentRideHeightInMeters=Fahrhöhe From 96552195e2b7c4a64197cc2efe21a7cce520a5d4 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 11 Jul 2016 18:14:21 +0200 Subject: [PATCH 169/259] Added navigations to quickfinder on user profile pages --- .../user/profile/AbstractUserProfileView.java | 5 +++++ .../user/profile/AbstractUserProfileView.ui.xml | 14 +++++++++++--- .../places/user/profile/UserProfileViewBase.java | 7 +++++-- .../details/UserProfileDetailsActivity.java | 14 +++++++++++++- .../UserProfilePreferencesActivity.java | 12 ++++++++++++ .../UserProfilePreferencesViewImpl.java | 2 -- 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java index 59796fae232..f3e889d86b3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.java @@ -10,6 +10,7 @@ import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.home.mobile.partials.quickfinder.Quickfinder; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorMobile; +import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; import com.sap.sse.security.ui.userprofile.mobile.userheader.UserHeader; @@ -32,11 +33,15 @@ public class AbstractUserProfileView extends Composite implements UserProfileVie } } + protected final StringMessages i18n = StringMessages.INSTANCE; private final AbstractUserProfileViewLayout layout; protected AbstractUserProfileView(UserProfileViewBase.Presenter presenter) { this.layout = new AbstractUserProfileViewLayout(presenter); initWidget(uiBinder.createAndBindUi(this.layout)); + this.layout.quickfinderUi.addPlaceholderItem(i18n.profileQuickfinder()); + this.layout.quickfinderUi.addItem(i18n.details(), presenter.getUserProfileNavigation()); + this.layout.quickfinderUi.addItem(i18n.favoritesAndNotifications(), presenter.getUserPreferencesNavigation()); } protected final void setViewContent(IsWidget content) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml index 244c63c8043..7b4704e0597 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/AbstractUserProfileView.ui.xml @@ -4,13 +4,21 @@ xmlns:uh="urn:import:com.sap.sse.security.ui.userprofile.mobile.userheader" xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator"> + + .headerWrapper { + background-color: #f2f2f2; + padding-bottom: 10px; + } + - - + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java index 22a23fbc063..67fdac7ff66 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileViewBase.java @@ -1,12 +1,15 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile; import com.google.gwt.user.client.ui.IsWidget; +import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; +import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; public interface UserProfileViewBase extends IsWidget, NeedsAuthenticationContext { - + public interface Presenter extends NotLoggedInPresenter { - + PlaceNavigation getUserProfileNavigation(); + PlaceNavigation getUserPreferencesNavigation(); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsActivity.java index e23e4a1dd79..44fe0b4c229 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/details/UserProfileDetailsActivity.java @@ -4,6 +4,7 @@ import com.google.gwt.activity.shared.AbstractActivity; import com.google.gwt.event.shared.EventBus; import com.google.gwt.user.client.ui.AcceptsOneWidget; import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; +import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sse.security.ui.authentication.AuthenticationContextEvent; import com.sap.sse.security.ui.userprofile.shared.userdetails.UserDetailsPresenter; @@ -12,12 +13,13 @@ public class UserProfileDetailsActivity extends AbstractActivity implements User private final MobileApplicationClientFactory clientFactory; - private final UserProfileDetailsView currentView = new UserProfileDetailsViewImpl(this); + private final UserProfileDetailsView currentView; private UserDetailsPresenter userDetailsPresenter; public UserProfileDetailsActivity(AbstractUserProfilePlace place, MobileApplicationClientFactory clientFactory) { this.clientFactory = clientFactory; + this.currentView = new UserProfileDetailsViewImpl(this); } @Override @@ -42,4 +44,14 @@ public class UserProfileDetailsActivity extends AbstractActivity implements User public void doTriggerLoginForm() { clientFactory.getNavigator().getSignInNavigation().goToPlace(); } + + @Override + public PlaceNavigation getUserProfileNavigation() { + return clientFactory.getNavigator().getUserProfileNavigation(); + } + + @Override + public PlaceNavigation getUserPreferencesNavigation() { + return clientFactory.getNavigator().getUserPreferencesNavigation(); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java index e12cee6ba52..edec83cd21e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java @@ -19,6 +19,8 @@ import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSu import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; +import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; +import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; import com.sap.sse.security.ui.authentication.AuthenticationContextEvent; @@ -132,4 +134,14 @@ public class UserProfilePreferencesActivity extends AbstractActivity implements public void onSuccess(VoidResult result) { } } + + @Override + public PlaceNavigation getUserProfileNavigation() { + return clientFactory.getNavigator().getUserProfileNavigation(); + } + + @Override + public PlaceNavigation getUserPreferencesNavigation() { + return clientFactory.getNavigator().getUserPreferencesNavigation(); + } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java index 8b3f7d5c306..5329750927b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java @@ -15,7 +15,6 @@ import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedM import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileView; -import com.sap.sailing.gwt.ui.client.StringMessages; public class UserProfilePreferencesViewImpl extends AbstractUserProfileView implements UserProfilePreferencesView { private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); @@ -23,7 +22,6 @@ public class UserProfilePreferencesViewImpl extends AbstractUserProfileView impl interface MyUiBinder extends UiBinder { } - private final StringMessages i18n = StringMessages.INSTANCE; @UiField(provided = true) SuggestedMultiSelection favoriteCompetitorsSelctionUi; @UiField(provided = true) SuggestedMultiSelection favoriteBoatClassesSelctionUi; @UiField DivElement notificationsTextUi; From 3a8c053d1a0ea7a9ee614ff688deb1bf4e3c31d6 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 12 Jul 2016 09:36:29 +0200 Subject: [PATCH 170/259] use locking in PreferenceObjectBasedNotificationSet Change-Id: I911fb9e4c303e8ae828f109345ca04aaa0c0d2f3 --- .../userstore/mongodb/UserStoreImpl.java | 4 +- .../com.sap.sse.security/META-INF/MANIFEST.MF | 3 +- ...referenceConverterRegistrationManager.java | 2 +- .../PreferenceObjectBasedNotificationSet.java | 48 ++++++++++++++----- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index c752334a0f3..74538a910b6 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -593,7 +593,7 @@ public class UserStoreImpl implements UserStore { } // if the new preference object is simply null, we remove the entry instead of putting null Object oldPreference = convertedObject == null ? userMap.remove(key) : userMap.put(key, convertedObject); - if(oldPreference != null || convertedObject != null) { + if (oldPreference != null || convertedObject != null) { // preference hasn't changed if it was null and is now null notifyListenersOnPreferenceObjectChange(username, key, oldPreference, convertedObject); } @@ -631,7 +631,7 @@ public class UserStoreImpl implements UserStore { if (preferenceConverter == null) { throw new IllegalArgumentException("Setting preference for key "+key+" but there is no converter associated!"); } - if(preferenceObject == null) { + if (preferenceObject == null) { unsetPreference(username, key); } else { try { diff --git a/java/com.sap.sse.security/META-INF/MANIFEST.MF b/java/com.sap.sse.security/META-INF/MANIFEST.MF index d4b4e63e3d4..486da0880bc 100644 --- a/java/com.sap.sse.security/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.security/META-INF/MANIFEST.MF @@ -33,7 +33,8 @@ Require-Bundle: javax.servlet;bundle-version="2.5.0", com.sap.sse.operationaltransformation, com.sap.sse.security.common, com.sap.sse, - com.sap.sse.mail + com.sap.sse.mail, + com.sap.sse.shared.android Web-ContextPath: /security Export-Package: com.sap.sse.security, com.sap.sse.security.jaxrs diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java index 55dfc05d8c0..127e478abb6 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java @@ -12,7 +12,7 @@ import com.sap.sse.common.Stoppable; /** * Automatically registers/removes {@link PreferenceConverter} instances found in the OSGi service registry on the given - * {@link UserStore}. + * {@link UserStore}.

        * * {@link PreferenceConverter} found are required to have a property with the key * {@link PreferenceConverter#KEY_PARAMETER_NAME} defining the preference key the converter should be registered with. diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index b9279074c21..34075ef382b 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -17,6 +17,8 @@ import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.sap.sse.common.Stoppable; import com.sap.sse.common.Util; +import com.sap.sse.concurrent.LockUtil; +import com.sap.sse.concurrent.NamedReentrantReadWriteLock; /** *

        @@ -33,11 +35,16 @@ import com.sap.sse.common.Util; *

        * *

        - * To speed up this part, the PreferenceObjectBasedNotificationSet holds an optimized association of who to notify about + * To speed up this part, the {@link PreferenceObjectBasedNotificationSet} holds an optimized association of who to notify about * specific objects. On preference changes for the given key in the given {@link UserStore}, the associations are being * updated to make the model always reflect the current state of the associations. Due to this the calculation of the * users to notify is a simple lookup. *

        + * + *

        + * To use this, implement a subclass in which the {@link #calculateObjectsToNotify(Object)} method determines the domain + * objects from a preference object for which the user needs to be notified. + *

        * * @param * The type of preference object on which the calculation of the objects to notify is based on. @@ -60,6 +67,8 @@ public abstract class PreferenceObjectBasedNotificationSet implements private final String key; private final ServiceTracker tracker; + + private final NamedReentrantReadWriteLock lock; /** * Constructor used to automatically track {@link UserStore} as OSGi service. @@ -67,17 +76,20 @@ public abstract class PreferenceObjectBasedNotificationSet implements public PreferenceObjectBasedNotificationSet(String key, BundleContext context) { this.key = key; this.context = context; - tracker = new ServiceTracker(context, UserStore.class, new Cutomizer()); + if (context == null) { + this.tracker = null; + } else { + this.tracker = new ServiceTracker(context, UserStore.class, new Cutomizer()); + } + this.lock = new NamedReentrantReadWriteLock(getClass().getName()+" for "+key, /* fair */ false); } /** * Constructor used to work with a given {@link UserStore}. */ public PreferenceObjectBasedNotificationSet(String key, UserStore store) { - this.key = key; + this(key, /* context */ (BundleContext) null); this.store = store; - context = null; - tracker = null; store.addPreferenceObjectListener(key, listener, true); } @@ -94,18 +106,30 @@ public abstract class PreferenceObjectBasedNotificationSet implements store.removePreferenceObjectListener(listener); store = null; } - // TODO use write lock - synchronized (notifications) { + LockUtil.lockForWrite(lock); + try { notifications.clear(); + } finally { + LockUtil.unlockAfterWrite(lock); } } + /** + * Determines the domain objects for which the user needs to be notified. + * + * @param preference + * a notification preference of some sort which typically describes or contains a set of domain objects + * the user is "interested" in and for changes of which the user wants to be notified. + * @return the domain objects described by the {@code preference} object thta the user is "interested" in + */ protected abstract Collection calculateObjectsToNotify(PrefT preference); public Iterable getUsersnamesToNotifyFor(T object) { - // TODO use read lock - synchronized (notifications) { + LockUtil.lockForRead(lock); + try { return new HashSet<>(Util.get(notifications, object, Collections.emptySet())); + } finally { + LockUtil.unlockAfterRead(lock); } } @@ -139,14 +163,16 @@ public abstract class PreferenceObjectBasedNotificationSet implements Set objectsToAdd = new HashSet<>(newObjectsToNotify); objectsToAdd.removeAll(oldObjectsToNotify); - // TODO use write lock - synchronized (notifications) { + LockUtil.lockForWrite(lock); + try { for (T objectToRemove : objectsToRemove) { Util.removeFromValueSet(notifications, objectToRemove, username); } for (T objectToAdd : objectsToAdd) { Util.addToValueSet(notifications, objectToAdd, username); } + } finally { + LockUtil.unlockAfterWrite(lock); } } } From c49f01a3799d560c40bd17d1e0ee7b40320f8cbd Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 12 Jul 2016 09:54:48 +0200 Subject: [PATCH 171/259] comments and final declarations Change-Id: I260c40920b3a292ccf140b11c806465bdb40085c --- .../src/com/sap/sailing/server/impl/Activator.java | 3 +++ .../preferences/model/BoatClassNotificationPreferences.java | 2 +- .../sse/security/PreferenceConverterRegistrationManager.java | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index e9a2790b809..38e74655080 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -133,6 +133,9 @@ public class Activator implements BundleActivator { Charset.defaultCharset()); } + /** + * {@link #racingEventService} must already be initialized when calling this method + */ protected void registerPreferenceConvertersForUserStore(BundleContext context) { Dictionary properties = new Hashtable(); properties.put(PreferenceConverter.KEY_PARAMETER_NAME, CompetitorNotificationPreferences.PREF_NAME); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java index c2a069c3252..4114b9e7643 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreferences.java @@ -22,7 +22,7 @@ public class BoatClassNotificationPreferences extends AbstractGenericSerializabl // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and // Competitor domain objects, it wouldn't be GWT compatible anyway. - // The usage of Java Serialization isn't planned by now too. + // The usage of Java Serialization isn't planned by now, either. } public Iterable getBoatClasses() { diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java index 127e478abb6..b53e813675f 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java @@ -47,8 +47,8 @@ public class PreferenceConverterRegistrationManager implements Stoppable { @Override public PreferenceConverter addingService(ServiceReference> reference) { - String preferenceKey = (String) reference.getProperty(PreferenceConverter.KEY_PARAMETER_NAME); - PreferenceConverter converter = context.getService(reference); + final String preferenceKey = (String) reference.getProperty(PreferenceConverter.KEY_PARAMETER_NAME); + final PreferenceConverter converter = context.getService(reference); if (preferenceKey == null) { logger.log(Level.SEVERE, "Found PreferenceConverter \"" + converter + "\" in OSGi registry without property " From 8da490d09a71b4ec0f1963e9f3babafdc2bb627a Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 12 Jul 2016 10:08:35 +0200 Subject: [PATCH 172/259] Moved SuggestedMultiSelection to shared package --- .../UserProfilePreferencesPresenter.java | 8 +++---- .../UserProfilePreferencesView.java | 4 ++-- .../UserProfilePreferencesViewImpl.java | 8 +++---- .../UserProfilePreferencesViewImpl.ui.xml | 6 ++--- .../UserProfilePreferencesActivity.java | 8 +++---- .../UserProfilePreferencesView.java | 4 ++-- .../UserProfilePreferencesViewImpl.java | 8 +++---- .../UserProfilePreferencesViewImpl.ui.xml | 24 +++++++++---------- ...edMultiSelectionBoatClassDataProvider.java | 2 +- ...dMultiSelectionCompetitorDataProvider.java | 2 +- ...ctSuggestedMultiSelectionDataProvider.java | 4 ++-- .../SuggestedMultiSelection.gss | 0 .../SuggestedMultiSelection.java | 4 ++-- .../SuggestedMultiSelection.ui.xml | 2 +- ...edMultiSelectionBoatClassDataProvider.java | 4 ++-- ...ultiSelectionBoatClassItemDescription.java | 2 +- ...tiSelectionBoatClassItemDescription.ui.xml | 2 +- ...dMultiSelectionCompetitorDataProvider.java | 4 ++-- ...ltiSelectionCompetitorItemDescription.java | 2 +- ...iSelectionCompetitorItemDescription.ui.xml | 2 +- .../SuggestedMultiSelectionDataProvider.java | 4 ++-- .../SuggestedMultiSelectionItem.java | 2 +- .../SuggestedMultiSelectionItem.ui.xml | 2 +- ...estedMultiSelectionNotificationToggle.java | 2 +- ...tedMultiSelectionNotificationToggle.ui.xml | 2 +- .../SuggestedMultiSelectionResources.java | 2 +- 26 files changed, 57 insertions(+), 57 deletions(-) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/AbstractSuggestedMultiSelectionBoatClassDataProvider.java (97%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/AbstractSuggestedMultiSelectionCompetitorDataProvider.java (95%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/AbstractSuggestedMultiSelectionDataProvider.java (93%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelection.gss (100%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelection.java (97%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelection.ui.xml (92%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionBoatClassDataProvider.java (78%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionBoatClassItemDescription.java (94%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionBoatClassItemDescription.ui.xml (83%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionCompetitorDataProvider.java (73%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionCompetitorItemDescription.java (94%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionCompetitorItemDescription.ui.xml (85%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionDataProvider.java (79%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionItem.java (94%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionItem.ui.xml (84%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionNotificationToggle.java (96%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionNotificationToggle.ui.xml (83%) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/{desktop/places/user/profile/selection => shared/partials/multiselection}/SuggestedMultiSelectionResources.java (93%) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java index 9a08bb4f7b5..aae72f74651 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesPresenter.java @@ -12,10 +12,10 @@ import com.sap.sailing.gwt.home.communication.user.profile.GetFavoritesAction; import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteBoatClassesAction; import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteCompetitorsAction; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionCompetitorDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java index 6caaf5a4f0c..6d14177827a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesView.java @@ -1,8 +1,8 @@ package com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab; import com.google.gwt.user.client.ui.IsWidget; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java index 5ef849b1fb8..893a7054bde 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.java @@ -11,10 +11,10 @@ import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection.NotificationCallback; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelection; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelection.NotificationCallback; import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml index 4b5904e181b..827cd59c64c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesViewImpl.ui.xml @@ -1,7 +1,7 @@ + xmlns:ms="urn:import:com.sap.sailing.gwt.home.shared.partials.multiselection"> @@ -13,10 +13,10 @@
        - +
        - +
        diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java index edec83cd21e..ea3606b505e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java @@ -14,12 +14,12 @@ import com.sap.sailing.gwt.home.communication.user.profile.GetCompetitorSuggesti import com.sap.sailing.gwt.home.communication.user.profile.GetFavoritesAction; import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteBoatClassesAction; import com.sap.sailing.gwt.home.communication.user.profile.SaveFavoriteCompetitorsAction; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.AbstractSuggestedMultiSelectionCompetitorDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; +import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java index ae82532f01e..57e5a35639a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesView.java @@ -1,8 +1,8 @@ package com.sap.sailing.gwt.home.mobile.places.user.profile.preferences; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.mobile.places.user.profile.UserProfileViewBase; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; public interface UserProfilePreferencesView extends UserProfileViewBase { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java index 5329750927b..b537da0f85b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java @@ -10,11 +10,11 @@ import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelection.NotificationCallback; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileView; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelection; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelection.NotificationCallback; public class UserProfilePreferencesViewImpl extends AbstractUserProfileView implements UserProfilePreferencesView { private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml index a83d729a98c..d3a8b40a10b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml @@ -3,7 +3,7 @@ xmlns:ud="urn:import:com.sap.sse.security.ui.userprofile.mobile.userdetails" xmlns:uh="urn:import:com.sap.sse.security.ui.userprofile.mobile.userheader" xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator" - xmlns:s="urn:import:com.sap.sailing.gwt.home.desktop.places.user.profile.selection"> + xmlns:ms="urn:import:com.sap.sailing.gwt.home.shared.partials.multiselection"> @@ -14,14 +14,14 @@ } -
        - -
        -
        - -
        -
        - -
        -
        -
        +
        + +
        +
        + +
        +
        + +
        + + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java similarity index 97% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java index 6fe84cf23d1..abc20ea2fc5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionBoatClassDataProvider.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import java.util.ArrayList; import java.util.Arrays; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java similarity index 95% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java index 74bcf079df0..75419bf1113 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionCompetitorDataProvider.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import java.util.Collection; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionDataProvider.java similarity index 93% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionDataProvider.java index 3f3f64fe8be..fb7408df036 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionDataProvider.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import java.util.ArrayList; import java.util.Collection; @@ -9,7 +9,7 @@ import java.util.Map; import java.util.Set; import com.google.gwt.view.client.ProvidesKey; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.Display; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionDataProvider.Display; public abstract class AbstractSuggestedMultiSelectionDataProvider> implements SuggestedMultiSelectionDataProvider { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.gss similarity index 100% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.gss rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.gss diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.java similarity index 97% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.java index 21b907c0a87..453455596a1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import java.util.Collection; @@ -18,10 +18,10 @@ import com.google.gwt.user.client.ui.SuggestOracle.Request; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.SuggestionItemsCallback; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractAsyncSuggestBoxFilter; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractFilterWidget; import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionDataProvider.SuggestionItemsCallback; import com.sap.sailing.gwt.ui.client.StringMessages; public final class SuggestedMultiSelection extends Composite implements SuggestedMultiSelectionDataProvider.Display { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.ui.xml similarity index 92% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.ui.xml index d0546c07acc..c3128836cd7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelection.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.ui.xml @@ -4,7 +4,7 @@ xmlns:s="urn:import:com.sap.sailing.gwt.home.desktop.places.user.profile.selection"> - + .noResults { font-weight: bold; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassDataProvider.java similarity index 78% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassDataProvider.java index 627c44bce1a..e1b8d6d075c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassDataProvider.java @@ -1,7 +1,7 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import com.sap.sailing.domain.common.dto.BoatClassDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionBoatClassDataProvider.Display; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider.Display; public interface SuggestedMultiSelectionBoatClassDataProvider extends SuggestedMultiSelectionDataProvider { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassItemDescription.java similarity index 94% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassItemDescription.java index 54b145abcfc..ad7f61a03f8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassItemDescription.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml similarity index 83% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml index fdc0974942d..8c02a60ac3d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionBoatClassItemDescription.ui.xml @@ -2,7 +2,7 @@ - + .imageSize { width: 2.133333333333333em !important; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorDataProvider.java similarity index 73% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorDataProvider.java index 104a9bc8576..7c817e65861 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorDataProvider.java @@ -1,7 +1,7 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionCompetitorDataProvider.Display; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider.Display; public interface SuggestedMultiSelectionCompetitorDataProvider extends SuggestedMultiSelectionDataProvider { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorItemDescription.java similarity index 94% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorItemDescription.java index d10ff518508..62e73c79782 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorItemDescription.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.DivElement; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml similarity index 85% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml index b6a0b6541ff..d80d0ff1683 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionCompetitorItemDescription.ui.xml @@ -2,7 +2,7 @@ - + .imageSize { width: 1.666666666666667em !important; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionDataProvider.java similarity index 79% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionDataProvider.java index 8cb1972713f..7201772dac6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionDataProvider.java @@ -1,9 +1,9 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import java.util.Collection; import com.google.gwt.view.client.ProvidesKey; -import com.sap.sailing.gwt.home.desktop.places.user.profile.selection.SuggestedMultiSelectionDataProvider.Display; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionDataProvider.Display; public interface SuggestedMultiSelectionDataProvider> extends ProvidesKey { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionItem.java similarity index 94% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionItem.java index 7b36e0f1c0a..5865055785c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionItem.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionItem.ui.xml similarity index 84% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionItem.ui.xml index 4e3040acc3e..e3b722d1707 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionItem.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionItem.ui.xml @@ -2,7 +2,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionNotificationToggle.java similarity index 96% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionNotificationToggle.java index b7b836836fa..11a95ab4e6e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionNotificationToggle.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionNotificationToggle.ui.xml similarity index 83% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionNotificationToggle.ui.xml index ddbb0cc52b5..67cf57d9084 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionNotificationToggle.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionNotificationToggle.ui.xml @@ -2,7 +2,7 @@ - + diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionResources.java similarity index 93% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionResources.java index e7905df2270..190afbaffa2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/selection/SuggestedMultiSelectionResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionResources.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.home.desktop.places.user.profile.selection; +package com.sap.sailing.gwt.home.shared.partials.multiselection; import com.google.gwt.core.shared.GWT; import com.google.gwt.resources.client.ClientBundle; From a0cec5fb3776e566ae02fbb5ec160a5246e90426 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 10:12:22 +0200 Subject: [PATCH 173/259] Supporting additional constructor from superclass in NotificationSets to automatically track the UserStore via OSGi service registry --- .../preferences/AbstractBoatClassNotificationSet.java | 9 +++++++++ .../preferences/AbstractCompetitorNotificationSet.java | 9 +++++++++ .../preferences/BoatClassResultsNotificationSet.java | 9 +++++++++ .../BoatClassUpcomingRaceNotificationSet.java | 9 +++++++++ .../preferences/CompetitorResultsNotificationSet.java | 9 +++++++++ 5 files changed, 45 insertions(+) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java index 33e2ee6da80..9c5e1928515 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java @@ -4,6 +4,8 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; +import org.osgi.framework.BundleContext; + import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; @@ -16,6 +18,13 @@ public abstract class AbstractBoatClassNotificationSet public AbstractBoatClassNotificationSet(UserStore store) { super(BoatClassNotificationPreferences.PREF_NAME, store); } + + /** + * Constructor used to automatically track {@link UserStore} as OSGi service. + */ + public AbstractBoatClassNotificationSet(BundleContext bundleContext) { + super(BoatClassNotificationPreferences.PREF_NAME, bundleContext); + } @Override protected Collection calculateObjectsToNotify(BoatClassNotificationPreferences preference) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java index 71c26ed67d5..377f6782370 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java @@ -4,6 +4,8 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; +import org.osgi.framework.BundleContext; + import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences; @@ -16,6 +18,13 @@ public abstract class AbstractCompetitorNotificationSet public AbstractCompetitorNotificationSet(UserStore store) { super(CompetitorNotificationPreferences.PREF_NAME, store); } + + /** + * Constructor used to automatically track {@link UserStore} as OSGi service. + */ + public AbstractCompetitorNotificationSet(BundleContext bundleContext) { + super(CompetitorNotificationPreferences.PREF_NAME, bundleContext); + } @Override protected Collection calculateObjectsToNotify(CompetitorNotificationPreferences preference) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java index abe666cfb68..5a8a1e2067c 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java @@ -1,5 +1,7 @@ package com.sap.sailing.server.impl.preferences; +import org.osgi.framework.BundleContext; + import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; import com.sap.sse.security.UserStore; @@ -9,6 +11,13 @@ public class BoatClassResultsNotificationSet extends AbstractBoatClassNotificati super(store); } + /** + * Constructor used to automatically track {@link UserStore} as OSGi service. + */ + public BoatClassResultsNotificationSet(BundleContext bundleContext) { + super(bundleContext); + } + @Override protected boolean shouldNotifyFor(BoatClassNotificationPreference pref) { return pref.isNotifyAboutResults(); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java index 61ca3fc7de0..42c4f9c3d7d 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java @@ -1,5 +1,7 @@ package com.sap.sailing.server.impl.preferences; +import org.osgi.framework.BundleContext; + import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; import com.sap.sse.security.UserStore; @@ -9,6 +11,13 @@ public class BoatClassUpcomingRaceNotificationSet extends AbstractBoatClassNotif super(store); } + /** + * Constructor used to automatically track {@link UserStore} as OSGi service. + */ + public BoatClassUpcomingRaceNotificationSet(BundleContext bundleContext) { + super(bundleContext); + } + @Override protected boolean shouldNotifyFor(BoatClassNotificationPreference pref) { return pref.isNotifyAboutUpcomingRaces(); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java index da035ca17a7..fee4cab5224 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java @@ -1,5 +1,7 @@ package com.sap.sailing.server.impl.preferences; +import org.osgi.framework.BundleContext; + import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; import com.sap.sse.security.UserStore; @@ -9,6 +11,13 @@ public class CompetitorResultsNotificationSet extends AbstractCompetitorNotifica super(store); } + /** + * Constructor used to automatically track {@link UserStore} as OSGi service. + */ + public CompetitorResultsNotificationSet(BundleContext bundleContext) { + super(bundleContext); + } + @Override protected boolean shouldNotifyFor(CompetitorNotificationPreference pref) { return pref.isNotifyAboutResults(); From a1e9e8b1ea9d42c3e5b04b2498db7cf5057d1c00 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 12 Jul 2016 10:16:04 +0200 Subject: [PATCH 174/259] Moved UserProfilePreferencesPlace into its own subpackage --- .../profile/preferencestab/UserProfilePreferencesTabView.java | 2 +- .../sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java | 2 +- .../mobile/places/user/profile/UserProfileActivityProxy.java | 2 +- .../profile/preferences/UserProfilePreferencesActivity.java | 2 +- .../sailing/gwt/home/shared/app/ApplicationHistoryMapper.java | 2 +- .../shared/places/user/profile/AbstractUserProfilePlace.java | 2 +- .../profile/{ => preferences}/UserProfilePreferencesPlace.java | 3 ++- 7 files changed, 8 insertions(+), 7 deletions(-) rename java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/{ => preferences}/UserProfilePreferencesPlace.java (78%) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java index 5429da2ac33..1171775ba5a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/places/user/profile/preferencestab/UserProfilePreferencesTabView.java @@ -5,7 +5,7 @@ import com.google.gwt.user.client.ui.Composite; import com.sap.sailing.gwt.common.client.controls.tabbar.TabView; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileTabView; import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView; -import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; +import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace; import com.sap.sse.security.ui.authentication.app.AuthenticationContext; public class UserProfilePreferencesTabView extends Composite implements UserProfileTabView { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java index 81b99f7806c..55965701014 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/app/MobilePlacesNavigator.java @@ -28,7 +28,7 @@ import com.sap.sailing.gwt.home.shared.places.user.confirmation.ConfirmationPlac import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetPlace; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDefaultPlace; -import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; +import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace; public class MobilePlacesNavigator extends AbstractPlaceNavigator { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java index f1ec14b8b7d..84f889d582f 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/UserProfileActivityProxy.java @@ -5,7 +5,7 @@ import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory; import com.sap.sailing.gwt.home.mobile.places.user.profile.details.UserProfileDetailsActivity; import com.sap.sailing.gwt.home.mobile.places.user.profile.preferences.UserProfilePreferencesActivity; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; -import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; +import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace; import com.sap.sse.gwt.client.mvp.AbstractActivityProxy; public class UserProfileActivityProxy extends AbstractActivityProxy { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java index ea3606b505e..9a05c5da4c5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesActivity.java @@ -21,7 +21,7 @@ import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggested import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; -import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; +import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace; import com.sap.sse.gwt.dispatch.shared.commands.VoidResult; import com.sap.sse.security.ui.authentication.AuthenticationContextEvent; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java index 410dae97e84..ad5dc5087f2 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/app/ApplicationHistoryMapper.java @@ -37,7 +37,7 @@ import com.sap.sailing.gwt.home.shared.places.user.confirmation.ConfirmationPlac import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetPlace; import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDefaultPlace; import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfileDetailsPlace; -import com.sap.sailing.gwt.home.shared.places.user.profile.UserProfilePreferencesPlace; +import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace; @WithTokenizers({ AboutUsPlace.Tokenizer.class, ContactPlace.Tokenizer.class, EventPlace.Tokenizer.class, EventsPlace.Tokenizer.class, SolutionsPlace.Tokenizer.class, WhatsNewPlace.Tokenizer.class, diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/AbstractUserProfilePlace.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/AbstractUserProfilePlace.java index d3cc0b67114..4c4d38ff433 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/AbstractUserProfilePlace.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/AbstractUserProfilePlace.java @@ -22,6 +22,6 @@ public abstract class AbstractUserProfilePlace extends Place implements HasLocat return ""; } - abstract PLACE getRealPlace(); + protected abstract PLACE getRealPlace(); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/UserProfilePreferencesPlace.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/preferences/UserProfilePreferencesPlace.java similarity index 78% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/UserProfilePreferencesPlace.java rename to java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/preferences/UserProfilePreferencesPlace.java index 7d0007f3fe9..9478bc97842 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/UserProfilePreferencesPlace.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/places/user/profile/preferences/UserProfilePreferencesPlace.java @@ -1,8 +1,9 @@ -package com.sap.sailing.gwt.home.shared.places.user.profile; +package com.sap.sailing.gwt.home.shared.places.user.profile.preferences; import com.google.gwt.place.shared.Prefix; import com.sap.sailing.gwt.home.shared.app.HasMobileVersion; import com.sap.sailing.gwt.home.shared.places.PlaceTokenPrefixes; +import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace; public class UserProfilePreferencesPlace extends AbstractUserProfilePlace implements HasMobileVersion { From 786488b28b1e9b8e44495acea22725ea48f1df06 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 10:22:57 +0200 Subject: [PATCH 175/259] Added more JavaDocs --- .../impl/preferences/AbstractBoatClassNotificationSet.java | 7 ++++++- .../preferences/AbstractCompetitorNotificationSet.java | 7 ++++++- .../impl/preferences/BoatClassResultsNotificationSet.java | 5 +++++ .../preferences/BoatClassUpcomingRaceNotificationSet.java | 5 +++++ .../impl/preferences/CompetitorResultsNotificationSet.java | 5 +++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java index 9c5e1928515..0ac76467f4b 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractBoatClassNotificationSet.java @@ -12,13 +12,18 @@ import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPrefer import com.sap.sse.security.PreferenceObjectBasedNotificationSet; import com.sap.sse.security.UserStore; +/** + * {@link PreferenceObjectBasedNotificationSet} for associations of {@link BoatClass} to a set of users to notify about + * specific events for the {@link BoatClass}. Subclasses define the concrete case of notification based on the flags in + * {@link BoatClassNotificationPreference} via implementing {@link #shouldNotifyFor(BoatClassNotificationPreference)}. + */ public abstract class AbstractBoatClassNotificationSet extends PreferenceObjectBasedNotificationSet { public AbstractBoatClassNotificationSet(UserStore store) { super(BoatClassNotificationPreferences.PREF_NAME, store); } - + /** * Constructor used to automatically track {@link UserStore} as OSGi service. */ diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java index 377f6782370..2b35968c0b6 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/AbstractCompetitorNotificationSet.java @@ -12,13 +12,18 @@ import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPrefe import com.sap.sse.security.PreferenceObjectBasedNotificationSet; import com.sap.sse.security.UserStore; +/** + * {@link PreferenceObjectBasedNotificationSet} for associations of {@link Competitor} to a set of users to notify about + * specific events for the {@link Competitor}. Subclasses define the concrete case of notification based on the flags in + * {@link CompetitorNotificationPreference} via implementing {@link #shouldNotifyFor(CompetitorNotificationPreference)}. + */ public abstract class AbstractCompetitorNotificationSet extends PreferenceObjectBasedNotificationSet { public AbstractCompetitorNotificationSet(UserStore store) { super(CompetitorNotificationPreferences.PREF_NAME, store); } - + /** * Constructor used to automatically track {@link UserStore} as OSGi service. */ diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java index 5a8a1e2067c..25870d5919e 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassResultsNotificationSet.java @@ -2,9 +2,14 @@ package com.sap.sailing.server.impl.preferences; import org.osgi.framework.BundleContext; +import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; import com.sap.sse.security.UserStore; +/** + * Notification set that defines the association of a {@link BoatClass} to the set of Users that need to be notified + * whenever new results are available for a {@link BoatClass}. + */ public class BoatClassResultsNotificationSet extends AbstractBoatClassNotificationSet { public BoatClassResultsNotificationSet(UserStore store) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java index 42c4f9c3d7d..05745a32813 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/BoatClassUpcomingRaceNotificationSet.java @@ -2,9 +2,14 @@ package com.sap.sailing.server.impl.preferences; import org.osgi.framework.BundleContext; +import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreference; import com.sap.sse.security.UserStore; +/** + * Notification set that defines the association of a {@link BoatClass} to the set of Users that need to be notified + * whenever a race is known to start in the near future for a {@link BoatClass}. + */ public class BoatClassUpcomingRaceNotificationSet extends AbstractBoatClassNotificationSet { public BoatClassUpcomingRaceNotificationSet(UserStore store) { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java index fee4cab5224..db100bfcc14 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/CompetitorResultsNotificationSet.java @@ -2,9 +2,14 @@ package com.sap.sailing.server.impl.preferences; import org.osgi.framework.BundleContext; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreference; import com.sap.sse.security.UserStore; +/** + * Notification set that defines the association of a {@link Competitor} to the set of Users that need to be notified + * whenever new results are available for a {@link Competitor}. + */ public class CompetitorResultsNotificationSet extends AbstractCompetitorNotificationSet { public CompetitorResultsNotificationSet(UserStore store) { From c48ff2c72927bd0666f84ba215ea2653d1d8de93 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 10:29:13 +0200 Subject: [PATCH 176/259] Added more JavaDocs --- .../src/com/sap/sse/security/PreferenceConverter.java | 9 ++++++++- .../PreferenceConverterRegistrationManager.java | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java index 2ce5fba4e5c..68e4c31db5e 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverter.java @@ -2,11 +2,18 @@ package com.sap.sse.security; /** * Converter to be used by {@link UserStore} to convert preference objects to/from Strings. + * * @see UserStore#registerPreferenceConverter(String, PreferenceConverter) * - * @param The type of preference object, this converter handles. + * @param + * The type of preference object, this converter handles. */ public interface PreferenceConverter { + /** + * To be used when publishing {@link PreferenceConverter} instances to the OSGi service registry. A property with + * this key needs to be added to the publication that defines the preference key for which the specific converter + * instance should be registered at the {@link UserStore}. + */ public final String KEY_PARAMETER_NAME = "key"; String toPreferenceString(PREF preference); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java index b53e813675f..6a3ad330b52 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java @@ -12,7 +12,8 @@ import com.sap.sse.common.Stoppable; /** * Automatically registers/removes {@link PreferenceConverter} instances found in the OSGi service registry on the given - * {@link UserStore}.

        + * {@link UserStore}. + *

        * * {@link PreferenceConverter} found are required to have a property with the key * {@link PreferenceConverter#KEY_PARAMETER_NAME} defining the preference key the converter should be registered with. @@ -25,6 +26,13 @@ public class PreferenceConverterRegistrationManager implements Stoppable { private final ServiceTracker, PreferenceConverter> tracker; + /** + * @param bundleContext + * the {@link BundleContext} needed to track {@link PreferenceConverter} instances that need to be + * registered a the given UserStore. + * @param userStore + * the {@link UserStore} to register {@link PreferenceConverter} at. + */ public PreferenceConverterRegistrationManager(BundleContext bundleContext, UserStore userStore) { this.context = bundleContext; this.userStore = userStore; From 4dde6fb98291d397d98617882425182f9f13c8d9 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 10:32:29 +0200 Subject: [PATCH 177/259] Documentation improvements --- .../preferences/model/BoatClassNotificationPreference.java | 2 +- .../preferences/model/CompetitorNotificationPreference.java | 2 +- .../preferences/model/CompetitorNotificationPreferences.java | 2 +- .../server/impl/preferences/model/SailingPreferences.java | 4 ++++ .../sse/security/PreferenceObjectBasedNotificationSet.java | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreference.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreference.java index c4898abe1d9..282244bbca4 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreference.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/BoatClassNotificationPreference.java @@ -32,7 +32,7 @@ public class BoatClassNotificationPreference extends AbstractGenericSerializable // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and // Competitor domain objects, it wouldn't be GWT compatible anyway. - // The usage of Java Serialization isn't planned by now too. + // The usage of Java Serialization isn't planned by now, either. } public BoatClass getBoatClass() { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java index 9888e8f0058..8710f452e99 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreference.java @@ -29,7 +29,7 @@ public class CompetitorNotificationPreference extends AbstractGenericSerializabl // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and // Competitor domain objects, it wouldn't be GWT compatible anyway. - // The usage of Java Serialization isn't planned by now too. + // The usage of Java Serialization isn't planned by now, either. } public Competitor getCompetitor() { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java index 8804204f72e..0f563918abf 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java @@ -22,7 +22,7 @@ public class CompetitorNotificationPreferences extends AbstractGenericSerializab // Doing this, Java/GWT Serialization isn't working anymore. Because the preferences are only serialized as JSON // in the backend an transferred as DTO to the frontend, this isn't a problem. Due to usage of BoatClass and // Competitor domain objects, it wouldn't be GWT compatible anyway. - // The usage of Java Serialization isn't planned by now too. + // The usage of Java Serialization isn't planned by now, either. } public Iterable getCompetitors() { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java index 44451d9c539..54d0392529d 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/SailingPreferences.java @@ -1,5 +1,9 @@ package com.sap.sailing.server.impl.preferences.model; +/** + * Defines common prefixes for classes of preferences in SAP Sailing to ensure some level of consistency when defining + * preference keys. + */ public interface SailingPreferences { public static final String NOTIFICATION_PREFERENCES_PREFIX = "sailing.notifications."; } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 34075ef382b..4a6d57e2024 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -85,7 +85,7 @@ public abstract class PreferenceObjectBasedNotificationSet implements } /** - * Constructor used to work with a given {@link UserStore}. + * Constructor used to directly work with a given {@link UserStore}. */ public PreferenceObjectBasedNotificationSet(String key, UserStore store) { this(key, /* context */ (BundleContext) null); From 6449fe92973daf573a6e1db18db75c74aa8c3405 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 10:43:37 +0200 Subject: [PATCH 178/259] Using NamedReentrantReadWriteLock instead of synchronization --- .../META-INF/MANIFEST.MF | 3 ++- .../userstore/mongodb/UserStoreImpl.java | 23 ++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sse.security.userstore.mongodb/META-INF/MANIFEST.MF b/java/com.sap.sse.security.userstore.mongodb/META-INF/MANIFEST.MF index 12b89a6475f..23dc56c7dcd 100644 --- a/java/com.sap.sse.security.userstore.mongodb/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.security.userstore.mongodb/META-INF/MANIFEST.MF @@ -14,6 +14,7 @@ Require-Bundle: com.sap.sse.security, org.apache.shiro.core;bundle-version="1.2.2", com.sap.sse.mongodb, com.sap.sse.common, - com.sap.sse.security.common + com.sap.sse.security.common, + com.sap.sse.shared.android Export-Package: com.sap.sse.security.userstore.mongodb, com.sap.sse.security.userstore.mongodb.impl;x-friends:="com.sap.sse.security.test" diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 74538a910b6..5e900807d4e 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -17,6 +17,8 @@ import java.util.logging.Logger; import org.apache.shiro.SecurityUtils; import com.sap.sse.common.Util; +import com.sap.sse.concurrent.LockUtil; +import com.sap.sse.concurrent.NamedReentrantReadWriteLock; import com.sap.sse.security.PreferenceConverter; import com.sap.sse.security.PreferenceObjectListener; import com.sap.sse.security.SocialSettingsKeys; @@ -70,6 +72,8 @@ public class UserStoreImpl implements UserStore { private transient Map>> listeners; + private transient NamedReentrantReadWriteLock listenersLock; + /** * Won't be serialized and remains null on the de-serializing end. */ @@ -90,6 +94,8 @@ public class UserStoreImpl implements UserStore { preferenceConverters = new ConcurrentHashMap<>(); preferenceObjects = new ConcurrentHashMap<>(); listeners = new HashMap<>(); + listenersLock = new NamedReentrantReadWriteLock( + UserStoreImpl.class.getSimpleName() + " lock for listeners collection", false); this.mongoObjectFactory = mongoObjectFactory; if (domainObjectFactory != null) { for (Entry> e : domainObjectFactory.loadSettingTypes().entrySet()) { @@ -130,6 +136,8 @@ public class UserStoreImpl implements UserStore { private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); listeners = new HashMap<>(); + listenersLock = new NamedReentrantReadWriteLock( + UserStoreImpl.class.getSimpleName() + " lock for listeners collection", false); } private void writeObject(ObjectOutputStream out) throws IOException { @@ -647,20 +655,24 @@ public class UserStoreImpl implements UserStore { private void notifyListenersOnPreferenceObjectChange(String username, String key, Object oldPreference, Object newPreference) { - synchronized (listeners) { + LockUtil.lockForRead(listenersLock); + try { for (PreferenceObjectListener listener : Util.get(listeners, key, Collections.> emptySet())) { @SuppressWarnings("unchecked") PreferenceObjectListener listenerToFire = (PreferenceObjectListener) listener; listenerToFire.preferenceObjectChanged(username, key, oldPreference, newPreference); } + } finally { + LockUtil.unlockAfterRead(listenersLock); } } @Override public void addPreferenceObjectListener(String key, PreferenceObjectListener listener, boolean fireForAlreadyExistingPreferences) { - synchronized (listeners) { + LockUtil.lockForWrite(listenersLock); + try { Util.addToValueSet(listeners, key, listener); if (fireForAlreadyExistingPreferences) { final Set usersToProcess = new HashSet<>(preferences.keySet()); @@ -676,13 +688,18 @@ public class UserStoreImpl implements UserStore { } } } + } finally { + LockUtil.unlockAfterWrite(listenersLock); } } @Override public void removePreferenceObjectListener(PreferenceObjectListener listener) { - synchronized (listeners) { + LockUtil.lockForWrite(listenersLock); + try { Util.removeFromAllValueSets(listeners, listener); + } finally { + LockUtil.unlockAfterWrite(listenersLock); } } } From f47557de6041554d194575738a47415c72178bd6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 10:45:08 +0200 Subject: [PATCH 179/259] Added more JavaDocs --- .../sap/sse/security/userstore/mongodb/UserStoreImpl.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index 5e900807d4e..c0371f96e02 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -70,8 +70,15 @@ public class UserStoreImpl implements UserStore { */ private final ConcurrentHashMap> preferenceObjects; + /** + * Keys are preferences keys as used by {@link #preferenceObjects}, values are the listeners to inform on changes of + * the specific preference object for a {@link User}. + */ private transient Map>> listeners; + /** + * To be used for locking when working with {@link #listeners}. + */ private transient NamedReentrantReadWriteLock listenersLock; /** From ea1f8415cb3debedb6e08a85b744e1cc8b4baad8 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 12 Jul 2016 10:49:37 +0200 Subject: [PATCH 180/259] Adjusted SuggestedMultiSelection styles and imports --- .../multiselection/SuggestedMultiSelection.gss | 11 +++++++++-- .../multiselection/SuggestedMultiSelection.ui.xml | 3 +-- .../SuggestedMultiSelectionResources.java | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.gss index 397a5d5c1ea..28e44565f8e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.gss @@ -1,9 +1,16 @@ -.suggestions { +.suggestions, .suggestionsMobile { width: 100%; font-size: 1rem; + overflow: hidden; +} +.suggestions { border: 1px solid #dedede; border-radius: 0.333333333333333em; - overflow: hidden; +} + +.suggestionsMobile { + border-top: 1px solid #dedede; + border-bottom: 1px solid #dedede; } .suggestionsHeader { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.ui.xml index c3128836cd7..1d36038a970 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelection.ui.xml @@ -1,7 +1,6 @@ + xmlns:sp="urn:import:com.sap.sailing.gwt.home.shared.partials"> diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionResources.java index 190afbaffa2..05c5bd8ca28 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/SuggestedMultiSelectionResources.java @@ -13,6 +13,7 @@ public interface SuggestedMultiSelectionResources extends ClientBundle { public interface LocalCss extends CssResource { String suggestions(); + String suggestionsMobile(); String suggestionsHeader(); String suggestionsHeaderTitle(); String suggestionsContent(); From d49ee0f0d22aeb85a446b66b3f9ba40dca42ea11 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 10:54:09 +0200 Subject: [PATCH 181/259] Added more JavaDocs --- .../sse/security/PreferenceObjectListener.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java index 6d594d3169a..fa7ac835822 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectListener.java @@ -3,8 +3,23 @@ package com.sap.sse.security; /** * Listener used by UserStore to notify about changes of stored preference objects. * - * @param The type of preference object this Listener handles. + * @param + * The type of preference object this Listener handles. */ public interface PreferenceObjectListener { + /** + * Called when the preference object for the given user and preference key has changed. + * + * @param username + * the user for whom the preference object changed + * @param key + * the key of the changed preference object + * @param oldPreference + * the old state of the preference object. May be null if there was not preference object + * formerly. + * @param newPreference + * the new state of the preference object. May be null if the preference object is being + * deleted. + */ void preferenceObjectChanged(String username, String key, PrefT oldPreference, PrefT newPreference); } From e7bf7846d7ac4836475d1800e6623eac70a33ea2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 11:05:24 +0200 Subject: [PATCH 182/259] Skip users without verified email address when sending notifications --- ...ferenceObjectBasedNotificationSetTest.java | 27 ++++++++++++++++--- .../PreferenceObjectBasedNotificationSet.java | 7 ++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 9706cafb15c..231d4e698c0 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -3,6 +3,7 @@ package com.sap.sse.security.test; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.function.Consumer; @@ -170,7 +171,7 @@ public class PreferenceObjectBasedNotificationSetTest { @Test public void userMappingTest() throws UserManagementException { - store.createUser(user1, mail); + createUserWithVerifiedEmail(user1, mail); store.registerPreferenceConverter(prefKey, prefConverter); store.setPreferenceObject(user1, prefKey, values1); PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); @@ -182,9 +183,22 @@ public class PreferenceObjectBasedNotificationSetTest { } @Test - public void userMappingWithTwoUsersTest() throws UserManagementException { + public void userWithNonVerifiedEmailIsSkippedTest() throws UserManagementException { store.createUser(user1, mail); - store.createUser(user2, mail); + store.registerPreferenceConverter(prefKey, prefConverter); + store.setPreferenceObject(user1, prefKey, values1); + PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); + + UserConsumerMock mock = new UserConsumerMock(); + + notificationSet.forUsersMappedTo(A, mock); + Assert.assertTrue(Util.isEmpty(mock.calls)); + } + + @Test + public void userMappingWithTwoUsersTest() throws UserManagementException { + createUserWithVerifiedEmail(user1, mail); + createUserWithVerifiedEmail(user2, mail); store.registerPreferenceConverter(prefKey, prefConverter); store.setPreferenceObject(user1, prefKey, values1); store.setPreferenceObject(user2, prefKey, values2); @@ -201,7 +215,7 @@ public class PreferenceObjectBasedNotificationSetTest { @Test public void userMappingWithOneExistingAndOneUnknownUserTest() throws UserManagementException { - store.createUser(user1, mail); + createUserWithVerifiedEmail(user1, mail); store.registerPreferenceConverter(prefKey, prefConverter); store.setPreferenceObject(user1, prefKey, values1); store.setPreferenceObject(user2, prefKey, values2); @@ -247,6 +261,11 @@ public class PreferenceObjectBasedNotificationSetTest { return new HashSet<>(Arrays.asList(values)); } + private void createUserWithVerifiedEmail(String username, String email) throws UserManagementException { + store.createUser(username, email); + store.updateUser(new User(username, email, null, null, true, null, null, Collections.emptySet())); + } + private static class PreferenceObjectBasedNotificationSetImpl extends PreferenceObjectBasedNotificationSet, String> { public PreferenceObjectBasedNotificationSetImpl(String key, UserStore store) { diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 4a6d57e2024..44853544437 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -135,6 +135,7 @@ public abstract class PreferenceObjectBasedNotificationSet implements /** * The given consumer will be called for every user that needs to be notified about the given object. + * Users without a verified email address will be skipped. */ public void forUsersMappedTo(T object, Consumer consumer) { for (String username : getUsersnamesToNotifyFor(object)) { @@ -144,7 +145,11 @@ public abstract class PreferenceObjectBasedNotificationSet implements if (user == null) { logger.log(Level.SEVERE, "Could not get User for name \"" + username + "\""); } else { - consumer.accept(user); + // we can not exclude users without verified email address when calculating the association because this + // state could have changed meanwhile. So this need to be done on the fly. + if(user.isEmailValidated()) { + consumer.accept(user); + } } } } From 662e1e2002110d33ad63a98ad0f1a1c16b8eb2cd Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 11:07:28 +0200 Subject: [PATCH 183/259] Renamed method to make more clear what's happening --- .../PreferenceObjectBasedNotificationSetTest.java | 12 ++++++------ .../PreferenceObjectBasedNotificationSet.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 231d4e698c0..865f4a0b414 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -165,7 +165,7 @@ public class PreferenceObjectBasedNotificationSetTest { PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); UserConsumerMock mock = new UserConsumerMock(); - notificationSet.forUsersMappedTo(A, mock); + notificationSet.forUsersWithVerifiedEmailMappedTo(A, mock); Assert.assertEquals(0, mock.calls.size()); } @@ -178,7 +178,7 @@ public class PreferenceObjectBasedNotificationSetTest { UserConsumerMock mock = new UserConsumerMock(); - notificationSet.forUsersMappedTo(A, mock); + notificationSet.forUsersWithVerifiedEmailMappedTo(A, mock); Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); } @@ -191,7 +191,7 @@ public class PreferenceObjectBasedNotificationSetTest { UserConsumerMock mock = new UserConsumerMock(); - notificationSet.forUsersMappedTo(A, mock); + notificationSet.forUsersWithVerifiedEmailMappedTo(A, mock); Assert.assertTrue(Util.isEmpty(mock.calls)); } @@ -205,11 +205,11 @@ public class PreferenceObjectBasedNotificationSetTest { PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); UserConsumerMock mock = new UserConsumerMock(); - notificationSet.forUsersMappedTo(A, mock); + notificationSet.forUsersWithVerifiedEmailMappedTo(A, mock); Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); mock = new UserConsumerMock(); - notificationSet.forUsersMappedTo(B, mock); + notificationSet.forUsersWithVerifiedEmailMappedTo(B, mock); Assert.assertTrue(Util.equals(users(store.getUserByName(user1), store.getUserByName(user2)), mock.calls)); } @@ -222,7 +222,7 @@ public class PreferenceObjectBasedNotificationSetTest { PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); UserConsumerMock mock = new UserConsumerMock(); - notificationSet.forUsersMappedTo(B, mock); + notificationSet.forUsersWithVerifiedEmailMappedTo(B, mock); Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); } diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 44853544437..e6a9d30262a 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -137,7 +137,7 @@ public abstract class PreferenceObjectBasedNotificationSet implements * The given consumer will be called for every user that needs to be notified about the given object. * Users without a verified email address will be skipped. */ - public void forUsersMappedTo(T object, Consumer consumer) { + public void forUsersWithVerifiedEmailMappedTo(T object, Consumer consumer) { for (String username : getUsersnamesToNotifyFor(object)) { // User objects can change silently. So we just keep the usernames and get the associated user objects on // the fly. From 01ceea636774b89f33cba0a0a48ad8ab668b1abf Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 11:17:24 +0200 Subject: [PATCH 184/259] Minor documentation changes --- .../sse/security/PreferenceConverterRegistrationManager.java | 2 +- .../sap/sse/security/PreferenceObjectBasedNotificationSet.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java index 6a3ad330b52..5dc7b2afd52 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceConverterRegistrationManager.java @@ -72,7 +72,7 @@ public class PreferenceConverterRegistrationManager implements Stoppable { @Override public void modifiedService(ServiceReference> reference, PreferenceConverter service) { - // Should we do anything here? + // Should we do anything here? the preference key could have changed, but does this make any sense? } @Override diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index e6a9d30262a..2e0ed013d68 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -199,7 +199,6 @@ public abstract class PreferenceObjectBasedNotificationSet implements @Override public void modifiedService(ServiceReference reference, UserStore service) { - // Should we do anything here? the preference key could have changed, but does this make any sense? } @Override From 4be2211bab310978be2cd34b3ed12fe4117d9a85 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 12 Jul 2016 13:17:14 +0200 Subject: [PATCH 185/259] Adjusted imports in UserProfilePreferencesViewImpl UI --- .../profile/preferences/UserProfilePreferencesViewImpl.java | 2 +- .../profile/preferences/UserProfilePreferencesViewImpl.ui.xml | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java index b537da0f85b..befafbbce41 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.java @@ -12,9 +12,9 @@ import com.sap.sailing.domain.common.dto.BoatClassDTO; import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO; import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileView; import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelection; +import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelection.NotificationCallback; import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionBoatClassDataProvider; import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionCompetitorDataProvider; -import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelection.NotificationCallback; public class UserProfilePreferencesViewImpl extends AbstractUserProfileView implements UserProfilePreferencesView { private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml index d3a8b40a10b..e6547d811c1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/mobile/places/user/profile/preferences/UserProfilePreferencesViewImpl.ui.xml @@ -1,7 +1,5 @@ From 579f83fade2f9cd74ddc7b97b5af0f627250a0e8 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 12 Jul 2016 16:53:48 +0200 Subject: [PATCH 186/259] Preparations for mail notifications --- java/com.sap.sailing.server/.classpath | 15 ++- .../META-INF/MANIFEST.MF | 5 +- java/com.sap.sailing.server/build.properties | 3 +- .../stringmessages/StringMessages.properties | 6 + .../StringMessages_de.properties | 0 .../StringMessages_ja.properties | 0 .../StringMessages_ru.properties | 0 .../StringMessages_zh.properties | 0 .../StringMessages_zh_CN.properties | 0 .../sap/sailing/server/impl/Activator.java | 79 ++++++------ .../SailingNotificationService.java | 16 +++ .../impl/NotificationSetNotification.java | 50 ++++++++ .../impl/SailingNotificationServiceImpl.java | 121 ++++++++++++++++++ java/com.sap.sse.mail/META-INF/MANIFEST.MF | 7 +- .../sap/sse/mail/queue/MailNotification.java | 7 + .../src/com/sap/sse/mail/queue/MailQueue.java | 11 ++ .../mail/queue/impl/ExecutorMailQueue.java | 34 +++++ 17 files changed, 307 insertions(+), 47 deletions(-) create mode 100644 java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties create mode 100644 java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties create mode 100644 java/com.sap.sailing.server/resources/stringmessages/StringMessages_ja.properties create mode 100644 java/com.sap.sailing.server/resources/stringmessages/StringMessages_ru.properties create mode 100644 java/com.sap.sailing.server/resources/stringmessages/StringMessages_zh.properties create mode 100644 java/com.sap.sailing.server/resources/stringmessages/StringMessages_zh_CN.properties create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java create mode 100644 java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailNotification.java create mode 100644 java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailQueue.java create mode 100644 java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java diff --git a/java/com.sap.sailing.server/.classpath b/java/com.sap.sailing.server/.classpath index 4f83b2397ec..d47cca9a1e3 100644 --- a/java/com.sap.sailing.server/.classpath +++ b/java/com.sap.sailing.server/.classpath @@ -1,7 +1,8 @@ - - - - - - - + + + + + + + + diff --git a/java/com.sap.sailing.server/META-INF/MANIFEST.MF b/java/com.sap.sailing.server/META-INF/MANIFEST.MF index a3fd190d9b7..49cc7c75671 100644 --- a/java/com.sap.sailing.server/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server/META-INF/MANIFEST.MF @@ -7,6 +7,8 @@ Bundle-Activator: com.sap.sailing.server.impl.Activator Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.sap.sailing.server.gateway.deserialization, + javax.mail;version="1.4.0", + javax.mail.internet;version="1.4.0", org.json.simple, org.json.simple.parser, org.osgi.framework;version="1.3.0", @@ -33,7 +35,8 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sse.security, org.apache.shiro.web;bundle-version="1.2.2", org.apache.shiro.core;bundle-version="1.2.2", - javax.servlet;bundle-version="3.1.0" + javax.servlet;bundle-version="3.1.0", + com.sap.sse.mail Bundle-ClassPath: . Export-Package: com.sap.sailing.server, com.sap.sailing.server.impl; diff --git a/java/com.sap.sailing.server/build.properties b/java/com.sap.sailing.server/build.properties index 41eb6ade2b4..a2e16dfebcd 100755 --- a/java/com.sap.sailing.server/build.properties +++ b/java/com.sap.sailing.server/build.properties @@ -1,4 +1,5 @@ -source.. = src/ +source.. = src/,\ + resources/ output.. = bin/ bin.includes = META-INF/,\ . diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties new file mode 100644 index 00000000000..33fba37eb18 --- /dev/null +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -0,0 +1,6 @@ +boatClassResultsSubject=New results for boat class {0} in regatta {1} of event {2} +boatClassResultsBody=New results for boat class {0} in regatta {1} of event {2} are available. See: {3} +boatClassUpcomingRaceSubject=A race for boat class {0} in regatta {1} of event {2} will start soon +boatClassUpcomingRaceBody=A race for boat class {0} in regatta {1} of event {2} will start at {4}. See: {3} +competitorResultsSubject=New results for competitor {0} in regatta {1} of event {2} +competitorResultsBody=New results for competitor {0} in regatta {1} of event {2} are available. See: {3} \ No newline at end of file diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_ja.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_ja.properties new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_ru.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_ru.properties new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_zh.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_zh.properties new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_zh_CN.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_zh_CN.properties new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 38e74655080..105afa97588 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -46,49 +46,56 @@ public class Activator implements BundleActivator { private static final Logger logger = Logger.getLogger(Activator.class.getName()); private static final String CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME = "persistentcompetitors.clear"; - + private static ExtenderBundleTracker extenderBundleTracker; - + private CachedOsgiTypeBasedServiceFinderFactory serviceFinderFactory; private RacingEventServiceImpl racingEventService; - + private final boolean clearPersistentCompetitors; - + private Set> registrations = new HashSet<>(); private ObjectName mBeanName; - + private ServiceTracker masterDataImportClassLoaderServiceTracker; - + private ServiceTracker polarDataServiceTracker; private OSGiBasedTrackedRegattaListener trackedRegattaListener; - + public Activator() { - clearPersistentCompetitors = Boolean.valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, ""+false)); - logger.log(Level.INFO, "setting "+CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME+" to "+clearPersistentCompetitors); + clearPersistentCompetitors = Boolean + .valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, "" + false)); + logger.log(Level.INFO, + "setting " + CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME + " to " + clearPersistentCompetitors); // there is exactly one instance of the racingEventService in the whole server } - + public void start(BundleContext context) throws Exception { extenderBundleTracker = new ExtenderBundleTracker(context); extenderBundleTracker.open(); - + + // TODO implement +// MailQueue mailQueue = new ExecutorMailQueue(ServiceTrackerFactory.createAndOpen(context, MailService.class)); +// SailingNotificationService notificationService = new SailingNotificationServiceImpl(context, mailQueue); + trackedRegattaListener = new OSGiBasedTrackedRegattaListener(context); - + // At this point the OSGi resolver is used as device type service finder. // In the case that we are not in an OSGi context (e.g. running a JUnit test instead), // this code block is not run, and the test case can inject some other type of finder // instead. serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context); - racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory, trackedRegattaListener); - + racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory, + trackedRegattaListener); + masterDataImportClassLoaderServiceTracker = new ServiceTracker( context, MasterDataImportClassLoaderService.class, new MasterDataImportClassLoaderServiceTrackerCustomizer(context, racingEventService)); masterDataImportClassLoaderServiceTracker.open(); - + polarDataServiceTracker = new ServiceTracker(context, PolarDataService.class, new PolarDataServiceTrackerCustomizer(context, racingEventService)); polarDataServiceTracker.open(); @@ -96,41 +103,39 @@ public class Activator implements BundleActivator { // register the racing service in the OSGi registry racingEventService.setBundleContext(context); final Dictionary replicableServiceProperties = new Hashtable<>(); - replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name, racingEventService.getId().toString()); + replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name, + racingEventService.getId().toString()); context.registerService(Replicable.class.getName(), racingEventService, replicableServiceProperties); context.registerService(RacingEventService.class.getName(), racingEventService, null); context.registerService(ClearStateTestSupport.class.getName(), racingEventService, null); Dictionary properties = new Hashtable(); - final GPSFixMongoHandlerImpl gpsFixMongoHandler = new GPSFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(), - racingEventService.getDomainObjectFactory()); + final GPSFixMongoHandlerImpl gpsFixMongoHandler = new GPSFixMongoHandlerImpl( + racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory()); properties.put(TypeBasedServiceFinder.TYPE, GPSFixImpl.class.getName()); - registrations.add(context.registerService(FixMongoHandler.class, - gpsFixMongoHandler, properties)); + registrations.add(context.registerService(FixMongoHandler.class, gpsFixMongoHandler, properties)); // legacy type name; some DBs may still contain fixes marked with this old package name: properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixImpl"); - registrations.add(context.registerService(FixMongoHandler.class, - gpsFixMongoHandler, properties)); - final GPSFixMovingMongoHandlerImpl gpsFixMovingMongoHandler = new GPSFixMovingMongoHandlerImpl(racingEventService.getMongoObjectFactory(), - racingEventService.getDomainObjectFactory()); + registrations.add(context.registerService(FixMongoHandler.class, gpsFixMongoHandler, properties)); + final GPSFixMovingMongoHandlerImpl gpsFixMovingMongoHandler = new GPSFixMovingMongoHandlerImpl( + racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory()); properties.put(TypeBasedServiceFinder.TYPE, GPSFixMovingImpl.class.getName()); registrations.add(context.registerService(FixMongoHandler.class, gpsFixMovingMongoHandler, properties)); // legacy type name; some DBs may still contain fixes marked with this old package name: properties.put(TypeBasedServiceFinder.TYPE, "com.sap.sailing.domain.tracking.impl.GPSFixMovingImpl"); registrations.add(context.registerService(FixMongoHandler.class, gpsFixMovingMongoHandler, properties)); properties.put(TypeBasedServiceFinder.TYPE, DoubleVectorFixImpl.class.getName()); - registrations.add(context.registerService(FixMongoHandler.class, new DoubleVectorFixMongoHandlerImpl(racingEventService.getMongoObjectFactory(), - racingEventService.getDomainObjectFactory()), properties)); + registrations.add(context.registerService(FixMongoHandler.class, new DoubleVectorFixMongoHandlerImpl( + racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory()), properties)); - registerPreferenceConvertersForUserStore(context); - + // Add an MBean for the service to the JMX bean server: RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); mBeanName = new ObjectName("com.sap.sailing:type=RacingEventService"); mbs.registerMBean(mbean, mBeanName); - logger.log(Level.INFO, "Started "+context.getBundle().getSymbolicName()+". Character encoding: "+ - Charset.defaultCharset()); + logger.log(Level.INFO, "Started " + context.getBundle().getSymbolicName() + ". Character encoding: " + + Charset.defaultCharset()); } /** @@ -171,14 +176,15 @@ public class Activator implements BundleActivator { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); mbs.unregisterMBean(mBeanName); } - + private class MasterDataImportClassLoaderServiceTrackerCustomizer implements ServiceTrackerCustomizer { private final BundleContext context; private RacingEventServiceImpl racingEventService; - public MasterDataImportClassLoaderServiceTrackerCustomizer(BundleContext context, RacingEventServiceImpl racingEventService) { + public MasterDataImportClassLoaderServiceTrackerCustomizer(BundleContext context, + RacingEventServiceImpl racingEventService) { this.context = context; this.racingEventService = racingEventService; } @@ -193,7 +199,8 @@ public class Activator implements BundleActivator { @Override public void modifiedService(ServiceReference reference, - MasterDataImportClassLoaderService service) {} + MasterDataImportClassLoaderService service) { + } @Override public void removedService(ServiceReference reference, @@ -203,8 +210,8 @@ public class Activator implements BundleActivator { } - private class PolarDataServiceTrackerCustomizer implements - ServiceTrackerCustomizer { + private class PolarDataServiceTrackerCustomizer + implements ServiceTrackerCustomizer { private final BundleContext context; private RacingEventServiceImpl racingEventService; @@ -231,5 +238,5 @@ public class Activator implements BundleActivator { } } - + } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java new file mode 100644 index 00000000000..6762dc3684a --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java @@ -0,0 +1,16 @@ +package com.sap.sailing.server.notification; + +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sse.common.TimePoint; + +public interface SailingNotificationService { + + void notifyUserOnBoatClassResults(BoatClass boatClass, String eventName, String regattaDisplayName, String link); + + void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, String eventName, String regattaDisplayName, + TimePoint when, String link); + + void notifyUserOnCompetitorResults(Competitor competitor, String eventName, String regattaDisplayName, String link); + +} \ No newline at end of file diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java new file mode 100644 index 00000000000..d2dbe8f4342 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -0,0 +1,50 @@ +package com.sap.sailing.server.notification.impl; + +import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.mail.BodyPart; +import javax.mail.Multipart; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMultipart; + +import com.sap.sse.mail.MailService; +import com.sap.sse.mail.queue.MailNotification; +import com.sap.sse.security.PreferenceObjectBasedNotificationSet; + +public abstract class NotificationSetNotification implements MailNotification { + private static final Logger logger = Logger.getLogger(NotificationSetNotification.class.getName()); + + private final T objectToNotifyAbout; + private final PreferenceObjectBasedNotificationSet associatedNotificationSet; + + public NotificationSetNotification(T objectToNotifyAbout, PreferenceObjectBasedNotificationSet associatedNotificationSet) { + this.objectToNotifyAbout = objectToNotifyAbout; + this.associatedNotificationSet = associatedNotificationSet; + } + + @Override + public void sendNotifications(final MailService mailService) { + // TODO idea (c) by Axel Uhl: In case of performance/mail queue problems: group mail addresses by locale and + // send batches with the actual mail addresses as bcc? + associatedNotificationSet.forUsersWithVerifiedEmailMappedTo(objectToNotifyAbout, (user) -> { + // TODO user defined locale + Locale locale = Locale.ENGLISH; + Multipart multipart = new MimeMultipart(); + BodyPart bodyPart = new MimeBodyPart(); + try { + bodyPart.setContent(constructBody(objectToNotifyAbout, locale), "text/html"); + multipart.addBodyPart(bodyPart); + mailService.sendMail(user.getEmail(), constructSubject(objectToNotifyAbout, locale), multipart); + } catch (Exception e) { + logger.log(Level.SEVERE, + "Could not send mail notification for \"" + objectToNotifyAbout + "\" to user \" + user + \"", e); + } + }); + } + + protected abstract String constructSubject(T objectToNotifyAbout, Locale locale); + + protected abstract String constructBody(T objectToNotifyAbout, Locale locale); +} \ No newline at end of file diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java new file mode 100644 index 00000000000..b7d05a37268 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -0,0 +1,121 @@ +package com.sap.sailing.server.notification.impl; + +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import org.osgi.framework.BundleContext; + +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.server.impl.preferences.BoatClassResultsNotificationSet; +import com.sap.sailing.server.impl.preferences.BoatClassUpcomingRaceNotificationSet; +import com.sap.sailing.server.impl.preferences.CompetitorResultsNotificationSet; +import com.sap.sailing.server.notification.SailingNotificationService; +import com.sap.sse.common.Stoppable; +import com.sap.sse.common.TimePoint; +import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl; +import com.sap.sse.mail.queue.MailQueue; + +public class SailingNotificationServiceImpl implements Stoppable, SailingNotificationService { + private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/StringMessages"; + + private final Set toStop = new HashSet<>(); + private final MailQueue mailQueue; + private final ResourceBundleStringMessagesImpl messages; + + private final BoatClassResultsNotificationSet boatClassResults; + private final BoatClassUpcomingRaceNotificationSet boatClassUpcomingRace; + private final CompetitorResultsNotificationSet competitorResults; + + public SailingNotificationServiceImpl(BundleContext bundleContext, MailQueue mailQueue) { + this.mailQueue = mailQueue; + this.messages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, + this.getClass().getClassLoader()); + + toStop.add(boatClassResults = new BoatClassResultsNotificationSet(bundleContext)); + toStop.add(boatClassUpcomingRace = new BoatClassUpcomingRaceNotificationSet(bundleContext)); + toStop.add(competitorResults = new CompetitorResultsNotificationSet(bundleContext)); + } + + @Override + public void stop() { + toStop.forEach(Stoppable::stop); + } + + /* + * (non-Javadoc) + * + * @see com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnBoatClassResults(com.sap.sailing. + * domain.base.BoatClass, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public void notifyUserOnBoatClassResults(BoatClass boatClass, String eventName, String regattaDisplayName, + String link) { + mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { + @Override + protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { + return messages.get(locale, "boatClassResultsSubject", boatClass.getDisplayName(), regattaDisplayName, + eventName); + } + + @Override + protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + return messages.get(locale, "boatClassResultsBody", boatClass.getDisplayName(), regattaDisplayName, + eventName); + } + }); + } + + /* + * (non-Javadoc) + * + * @see + * com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnBoatClassUpcomingRace(com.sap.sailing. + * domain.base.BoatClass, java.lang.String, java.lang.String, com.sap.sse.common.TimePoint, java.lang.String) + */ + @Override + public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, String eventName, String regattaDisplayName, + TimePoint when, String link) { + mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) { + @Override + protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { + return messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName(), + regattaDisplayName, eventName); + } + + @Override + protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + // TODO properly format time in the user's locale + String time = when.toString(); + return messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), regattaDisplayName, + eventName, time); + } + }); + } + + /* + * (non-Javadoc) + * + * @see + * com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnCompetitorResults(com.sap.sailing. + * domain.base.Competitor, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public void notifyUserOnCompetitorResults(Competitor competitor, String eventName, String regattaDisplayName, + String link) { + mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { + @Override + protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) { + return messages.get(locale, "competitorResultsSubject", competitor.getName(), regattaDisplayName, + eventName); + } + + @Override + protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { + return messages.get(locale, "competitorResultsBody", competitor.getName(), regattaDisplayName, + eventName); + } + }); + } +} diff --git a/java/com.sap.sse.mail/META-INF/MANIFEST.MF b/java/com.sap.sse.mail/META-INF/MANIFEST.MF index d5aff706f24..ab125af96f5 100755 --- a/java/com.sap.sse.mail/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.mail/META-INF/MANIFEST.MF @@ -7,10 +7,13 @@ Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-Activator: com.sap.sse.mail.impl.Activator Export-Package: com.sap.sse.mail, - com.sap.sse.mail.impl + com.sap.sse.mail.impl, + com.sap.sse.mail.queue, + com.sap.sse.mail.queue.impl Import-Package: javax.mail, javax.mail.internet, - org.osgi.framework + org.osgi.framework, + org.osgi.util.tracker;version="1.5.1" Require-Bundle: com.sap.sse.replication, com.sap.sse.operationaltransformation, com.sap.sse.common, diff --git a/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailNotification.java b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailNotification.java new file mode 100644 index 00000000000..4dec0c06cbb --- /dev/null +++ b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailNotification.java @@ -0,0 +1,7 @@ +package com.sap.sse.mail.queue; + +import com.sap.sse.mail.MailService; + +public interface MailNotification { + void sendNotifications(final MailService mailService); +} \ No newline at end of file diff --git a/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailQueue.java b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailQueue.java new file mode 100644 index 00000000000..b2266073e5b --- /dev/null +++ b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/MailQueue.java @@ -0,0 +1,11 @@ +package com.sap.sse.mail.queue; + +import com.sap.sse.common.Stoppable; +import com.sap.sse.mail.MailService; + +/** + * Supports sending mails via {@link MailService} in a deferred way by enqueuing {@link MailNotification} instances. + */ +public interface MailQueue extends Stoppable { + void addNotification(MailNotification notification); +} diff --git a/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java new file mode 100644 index 00000000000..b462ef9e811 --- /dev/null +++ b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java @@ -0,0 +1,34 @@ +package com.sap.sse.mail.queue.impl; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.osgi.util.tracker.ServiceTracker; + +import com.sap.sse.mail.MailService; +import com.sap.sse.mail.queue.MailNotification; +import com.sap.sse.mail.queue.MailQueue; + +/** + * {@link MailQueue} implementation that uses a single threaded executor to process the {@link MailNotification}s. + */ +public class ExecutorMailQueue implements MailQueue { + private final ServiceTracker mailServiceTracker; + + private final ExecutorService executor = Executors.newSingleThreadExecutor( + (runnable) -> new Thread(runnable, ExecutorMailQueue.class.getName() + " executor")); + + public ExecutorMailQueue(ServiceTracker mailServiceTracker) { + this.mailServiceTracker = mailServiceTracker; + } + + @Override + public void stop() { + executor.shutdown(); + } + + @Override + public void addNotification(MailNotification notification) { + executor.execute(() -> notification.sendNotifications(mailServiceTracker.getService())); + } +} From e040866bba173aea77345e802f75cc02cffb5783 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 08:11:21 +0200 Subject: [PATCH 187/259] Executor Thread is now configured as daemon --- .../src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java index b462ef9e811..df839466a12 100644 --- a/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java +++ b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java @@ -16,7 +16,11 @@ public class ExecutorMailQueue implements MailQueue { private final ServiceTracker mailServiceTracker; private final ExecutorService executor = Executors.newSingleThreadExecutor( - (runnable) -> new Thread(runnable, ExecutorMailQueue.class.getName() + " executor")); + (runnable) -> { + Thread thread = new Thread(runnable, ExecutorMailQueue.class.getName() + " executor"); + thread.setDaemon(true); + return thread; + }); public ExecutorMailQueue(ServiceTracker mailServiceTracker) { this.mailServiceTracker = mailServiceTracker; From 4252c2b2703e2982b81792eb0629d0c3ab138ee2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 08:11:56 +0200 Subject: [PATCH 188/259] Removed non useful docs generated by Eclipse --- .../impl/SailingNotificationServiceImpl.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index b7d05a37268..bee4b57d96f 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -43,12 +43,6 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific toStop.forEach(Stoppable::stop); } - /* - * (non-Javadoc) - * - * @see com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnBoatClassResults(com.sap.sailing. - * domain.base.BoatClass, java.lang.String, java.lang.String, java.lang.String) - */ @Override public void notifyUserOnBoatClassResults(BoatClass boatClass, String eventName, String regattaDisplayName, String link) { @@ -67,13 +61,6 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific }); } - /* - * (non-Javadoc) - * - * @see - * com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnBoatClassUpcomingRace(com.sap.sailing. - * domain.base.BoatClass, java.lang.String, java.lang.String, com.sap.sse.common.TimePoint, java.lang.String) - */ @Override public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, String eventName, String regattaDisplayName, TimePoint when, String link) { @@ -94,13 +81,6 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific }); } - /* - * (non-Javadoc) - * - * @see - * com.sap.sailing.server.notification.SailingNotificationService#notifyUserOnCompetitorResults(com.sap.sailing. - * domain.base.Competitor, java.lang.String, java.lang.String, java.lang.String) - */ @Override public void notifyUserOnCompetitorResults(Competitor competitor, String eventName, String regattaDisplayName, String link) { From a4c4713e424b4c486540015fdcaf65fb253a54c3 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 10:42:37 +0200 Subject: [PATCH 189/259] Updated SailingNotificationService and the associated messages --- .../stringmessages/StringMessages.properties | 30 ++- .../SailingNotificationService.java | 34 ++- .../impl/SailingNotificationServiceImpl.java | 235 +++++++++++++++--- 3 files changed, 248 insertions(+), 51 deletions(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 33fba37eb18..aa925481168 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -1,6 +1,24 @@ -boatClassResultsSubject=New results for boat class {0} in regatta {1} of event {2} -boatClassResultsBody=New results for boat class {0} in regatta {1} of event {2} are available. See: {3} -boatClassUpcomingRaceSubject=A race for boat class {0} in regatta {1} of event {2} will start soon -boatClassUpcomingRaceBody=A race for boat class {0} in regatta {1} of event {2} will start at {4}. See: {3} -competitorResultsSubject=New results for competitor {0} in regatta {1} of event {2} -competitorResultsBody=New results for competitor {0} in regatta {1} of event {2} are available. See: {3} \ No newline at end of file +raceInRegattaOfEvent=race {0} in regatta {1} of event {2} +raceInFleetInRegattaOfEvent={0} ({3}) in regatta {1} of event {2} + +leaderboardOfEvent=leaderboard {0} of event {1} + +boatClassRaceFinishingSubject=Race for boat class {0} finishes - new results available +# 0: boatClassName, 1: raceDescription, 2: link +boatClassRaceFinishingBody=New results for boat class {0} in {1} are available. See: {2} + +boatClassScoreCorrectionSubject=New results are available for boat class {0} +# 0: boatClassName, 1: leaderboardDescription, 2: link +boatClassScoreCorrectionBody=New results for boat class {0} in {1} are available. See: {2} + +competitorPassesFinishSubject=Competitor {0} passed finish line in a race +# 0: competitorName, 1: raceDescription, 2: link +competitorPassesFinishBody=Competitor {0} passed finish line in {1}. See: {2} + +competitorScoreCorrectionSubject=New results are available for competitor {0} +# 0: competitorName, 1: leaderboardDescription, 2: link +boatClassScoreCorrectionBody=New results for competitor {0} in {1} are available. See: {2} + +boatClassUpcomingRaceSubject=A race for boat class {0} will start soon +# 0: boatClassName, 1: raceDescription, 2: time, 3: link +boatClassUpcomingRaceBody=A race for boat class {0} in {1} will start approximately at {2}. See: {3} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java index 6762dc3684a..2f8061df735 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java @@ -1,16 +1,42 @@ package com.sap.sailing.server.notification; +import com.sap.sailing.domain.abstractlog.race.state.RaceState; import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.common.TimePoint; public interface SailingNotificationService { - void notifyUserOnBoatClassResults(BoatClass boatClass, String eventName, String regattaDisplayName, String link); + /** + * Called when {@link RaceState} changes state to finishing/finished (?). + */ + void notifyUserOnBoatClassRaceChangesStateToFinishing(BoatClass boatClass, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet); + + /** + * Called on score correction for a race with BoatClass if the last score correction was more than one minute. + */ + void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard); + + /** + * Called whenever a start time is set for a race with {@link BoatClass} through the race's {@link RaceState}. + */ + void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet, TimePoint when); - void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, String eventName, String regattaDisplayName, - TimePoint when, String link); + /** + * Triggered when a competitor passes the finishing waypoint of a race. + */ + void notifyUserOnCompetitorPassesFinish(Competitor competitor, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet); - void notifyUserOnCompetitorResults(Competitor competitor, String eventName, String regattaDisplayName, String link); + /** + * Triggered when a score correction is set for competitor on any leaderboard. + */ + void notifyUserOnCompetitorScoreCorrections(Competitor competitor, Leaderboard leaderboard); } \ No newline at end of file diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index bee4b57d96f..0582d9f3695 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -3,17 +3,30 @@ package com.sap.sailing.server.notification.impl; import java.util.HashSet; import java.util.Locale; import java.util.Set; +import java.util.function.BiConsumer; import org.osgi.framework.BundleContext; 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.Event; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.server.RacingEventService; +import com.sap.sailing.server.impl.RacingEventServiceImpl; import com.sap.sailing.server.impl.preferences.BoatClassResultsNotificationSet; import com.sap.sailing.server.impl.preferences.BoatClassUpcomingRaceNotificationSet; import com.sap.sailing.server.impl.preferences.CompetitorResultsNotificationSet; import com.sap.sailing.server.notification.SailingNotificationService; import com.sap.sse.common.Stoppable; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util; +import com.sap.sse.common.Util.Pair; import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl; import com.sap.sse.mail.queue.MailQueue; @@ -22,6 +35,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific private final Set toStop = new HashSet<>(); private final MailQueue mailQueue; + private RacingEventService racingEventService; private final ResourceBundleStringMessagesImpl messages; private final BoatClassResultsNotificationSet boatClassResults; @@ -43,59 +57,198 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific toStop.forEach(Stoppable::stop); } - @Override - public void notifyUserOnBoatClassResults(BoatClass boatClass, String eventName, String regattaDisplayName, - String link) { - mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { - @Override - protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassResultsSubject", boatClass.getDisplayName(), regattaDisplayName, - eventName); - } + public void setRacingEventService(RacingEventServiceImpl racingEventService) { + this.racingEventService = racingEventService; + } - @Override - protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassResultsBody", boatClass.getDisplayName(), regattaDisplayName, - eventName); + private Pair calculateAssociatedEventForLeaderboard(final Leaderboard leaderboard) { + Set foundEvents = new HashSet<>(); + Set foundLeaderboardGroups = new HashSet<>(); + racingEventService.getAllEvents().forEach(event -> { + event.getLeaderboardGroups().forEach(leaderboardGroup -> { + if (Util.contains(leaderboardGroup.getLeaderboards(), leaderboard)) { + foundEvents.add(event); + foundLeaderboardGroups.add(leaderboardGroup); + } + }); + }); + int foundEventsCount = foundEvents.size(); + if (foundEventsCount == 1) { + return new Pair<>(Util.get(foundEvents, 0), Util.get(foundLeaderboardGroups, 0)); + } else if (foundEventsCount > 1 && foundLeaderboardGroups.size() == 1) { + // could be a series + LeaderboardGroup leaderboardGroup = Util.get(foundLeaderboardGroups, 0); + if (leaderboardGroup.hasOverallLeaderboard()) { + CourseArea defaultCourseArea = leaderboard.getDefaultCourseArea(); + if (defaultCourseArea != null) { + for (Event event : foundEvents) { + if (Util.contains(event.getVenue().getCourseAreas(), defaultCourseArea)) { + return new Pair<>(event, leaderboardGroup); + } + } + } } + } + // No associated event found or association is ambiguous + return null; + } + + private void doWithEvent(Leaderboard leaderboard, BiConsumer consumer) { + if (racingEventService == null) { + // TODO log + return; + } + Pair eventAndLeaderboardGroup = calculateAssociatedEventForLeaderboard(leaderboard); + if (eventAndLeaderboardGroup != null) { + consumer.accept(eventAndLeaderboardGroup.getA(), eventAndLeaderboardGroup.getB()); + } + } + + private String calculateRaceDescription(Locale locale, Event event, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet) { + String raceName = raceColumn.getName(); + String eventName = event.getName(); + String leaderboardDisplayName = leaderboard.getDisplayName() != null ? leaderboard.getDisplayName() + : leaderboard.getName(); + + if (Util.size(raceColumn.getFleets()) > 1) { + return messages.get(locale, "raceInFleetInRegattaOfEvent", raceName, leaderboardDisplayName, eventName, + fleet.getName()); + } else { + return messages.get(locale, "raceInRegattaOfEvent", raceName, leaderboardDisplayName, eventName); + + } + } + + private String calculateLeaderboardDescription(Locale locale, Event event, Leaderboard leaderboard) { + String eventName = event.getName(); + String leaderboardDisplayName = leaderboard.getDisplayName() != null ? leaderboard.getDisplayName() + : leaderboard.getName(); + + return messages.get(locale, "leaderboardOfEvent", leaderboardDisplayName, eventName); + } + + @Override + public void notifyUserOnBoatClassRaceChangesStateToFinishing(BoatClass boatClass, TrackedRace trackedRace, + Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { + doWithEvent(leaderboard, (event, leaderboardGroup) -> { + RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); + // TODO where to get the base URL? + String link = "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() + + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" + + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" + + raceIdentifier.getRegattaName(); + + mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { + @Override + protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { + return messages.get(locale, "boatClassRaceFinishingSubject", boatClass.getDisplayName()); + } + + @Override + protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); + return messages.get(locale, "boatClassRaceFinishingBody", boatClass.getDisplayName(), + raceDescription, link); + } + }); }); } @Override - public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, String eventName, String regattaDisplayName, - TimePoint when, String link) { - mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) { - @Override - protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName(), - regattaDisplayName, eventName); - } + public void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard) { + doWithEvent(leaderboard, (event, leaderboardGroup) -> { + // TODO where to get the base URL? + String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" + + leaderboard.getName(); - @Override - protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { - // TODO properly format time in the user's locale - String time = when.toString(); - return messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), regattaDisplayName, - eventName, time); - } + mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { + @Override + protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { + return messages.get(locale, "boatClassScoreCorrectionSubject", boatClass.getDisplayName()); + } + + @Override + protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); + return messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(), + leaderboardDescription, link); + } + }); + }); + } + + public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet, TimePoint when) { + doWithEvent(leaderboard, (event, leaderboardGroup) -> { + // TODO where to get the base URL? + String link = "/gwt/Home.html#/regatta/races/:eventId="+event.getId()+"®attaId=" + leaderboard.getName(); + + mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) { + @Override + protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { + return messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName()); + } + + @Override + protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); + // TODO properly format time in the user's locale + String time = when.toString(); + return messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), + raceDescription, time, link); + } + }); }); } @Override - public void notifyUserOnCompetitorResults(Competitor competitor, String eventName, String regattaDisplayName, - String link) { - mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { - @Override - protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) { - return messages.get(locale, "competitorResultsSubject", competitor.getName(), regattaDisplayName, - eventName); - } + public void notifyUserOnCompetitorPassesFinish(Competitor competitor, TrackedRace trackedRace, + Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { + doWithEvent(leaderboard, (event, leaderboardGroup) -> { + RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); + // TODO where to get the base URL? + String link = "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() + + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" + + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" + + raceIdentifier.getRegattaName(); - @Override - protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { - return messages.get(locale, "competitorResultsBody", competitor.getName(), regattaDisplayName, - eventName); - } + mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { + @Override + protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) { + return messages.get(locale, "competitorPassesFinishSubject", competitor.getName()); + } + + @Override + protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { + String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); + return messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription, + link); + } + }); + }); + } + + @Override + public void notifyUserOnCompetitorScoreCorrections(Competitor competitor, Leaderboard leaderboard) { + doWithEvent(leaderboard, (event, leaderboardGroup) -> { + // TODO where to get the base URL? + String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" + + leaderboard.getName(); + + mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { + @Override + protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) { + return messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()); + } + + @Override + protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { + String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); + return messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), + leaderboardDescription, link); + } + }); }); } } From 577f17ec1e48a90e3327cba19c79e31af49fc2fd Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 10:43:36 +0200 Subject: [PATCH 190/259] Updated the activator to properly start and stop SailingNotificationService --- .../sap/sailing/server/impl/Activator.java | 21 ++++++++++++++++--- .../mail/queue/impl/ExecutorMailQueue.java | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 105afa97588..81649269e50 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -34,12 +34,17 @@ import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceMXBean; import com.sap.sailing.server.impl.preferences.model.BoatClassNotificationPreferences; import com.sap.sailing.server.impl.preferences.model.CompetitorNotificationPreferences; +import com.sap.sailing.server.notification.impl.SailingNotificationServiceImpl; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.Util; +import com.sap.sse.mail.MailService; +import com.sap.sse.mail.queue.MailQueue; +import com.sap.sse.mail.queue.impl.ExecutorMailQueue; import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; import com.sap.sse.replication.Replicable; import com.sap.sse.security.PreferenceConverter; import com.sap.sse.util.ClearStateTestSupport; +import com.sap.sse.util.ServiceTrackerFactory; public class Activator implements BundleActivator { @@ -65,6 +70,12 @@ public class Activator implements BundleActivator { private OSGiBasedTrackedRegattaListener trackedRegattaListener; + private MailQueue mailQueue; + + private SailingNotificationServiceImpl notificationService; + + private ServiceTracker mailServiceTracker; + public Activator() { clearPersistentCompetitors = Boolean .valueOf(System.getProperty(CLEAR_PERSISTENT_COMPETITORS_PROPERTY_NAME, "" + false)); @@ -77,9 +88,9 @@ public class Activator implements BundleActivator { extenderBundleTracker = new ExtenderBundleTracker(context); extenderBundleTracker.open(); - // TODO implement -// MailQueue mailQueue = new ExecutorMailQueue(ServiceTrackerFactory.createAndOpen(context, MailService.class)); -// SailingNotificationService notificationService = new SailingNotificationServiceImpl(context, mailQueue); + mailServiceTracker = ServiceTrackerFactory.createAndOpen(context, MailService.class); + mailQueue = new ExecutorMailQueue(mailServiceTracker); + notificationService = new SailingNotificationServiceImpl(context, mailQueue); trackedRegattaListener = new OSGiBasedTrackedRegattaListener(context); @@ -90,6 +101,7 @@ public class Activator implements BundleActivator { serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context); racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory, trackedRegattaListener); + notificationService.setRacingEventService(racingEventService); masterDataImportClassLoaderServiceTracker = new ServiceTracker( context, MasterDataImportClassLoaderService.class, @@ -173,6 +185,9 @@ public class Activator implements BundleActivator { } trackedRegattaListener.close(); registrations.clear(); + notificationService.stop(); + mailQueue.stop(); + mailServiceTracker.close(); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); mbs.unregisterMBean(mBeanName); } diff --git a/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java index df839466a12..4fea8c29ba0 100644 --- a/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java +++ b/java/com.sap.sse.mail/src/com/sap/sse/mail/queue/impl/ExecutorMailQueue.java @@ -28,7 +28,7 @@ public class ExecutorMailQueue implements MailQueue { @Override public void stop() { - executor.shutdown(); + executor.shutdownNow(); } @Override From f63c634baef7619c423162d5532a294b195c2fc5 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 11:02:14 +0200 Subject: [PATCH 191/259] Code quality improvements --- .../impl/SailingNotificationServiceImpl.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 0582d9f3695..94bca316b40 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -1,9 +1,11 @@ package com.sap.sailing.server.notification.impl; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; import java.util.function.BiConsumer; +import java.util.logging.Logger; import org.osgi.framework.BundleContext; @@ -33,6 +35,8 @@ import com.sap.sse.mail.queue.MailQueue; public class SailingNotificationServiceImpl implements Stoppable, SailingNotificationService { private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/StringMessages"; + private static final Logger logger = Logger.getLogger(SailingNotificationServiceImpl.class.getName()); + private final Set toStop = new HashSet<>(); private final MailQueue mailQueue; private RacingEventService racingEventService; @@ -61,9 +65,14 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific this.racingEventService = racingEventService; } + /** + * Calculates the best matching {@link Event} and {@link LeaderboardGroup} for the given {@link Leaderboard}. If + * there is just one Event/LeaderboardGroup, this pair is returned. If an event series is found and the associated + * Event can be obtained, this combination is returned. The first Event of the series is used otherwise. + */ private Pair calculateAssociatedEventForLeaderboard(final Leaderboard leaderboard) { - Set foundEvents = new HashSet<>(); - Set foundLeaderboardGroups = new HashSet<>(); + Set foundEvents = new LinkedHashSet<>(); + Set foundLeaderboardGroups = new LinkedHashSet<>(); racingEventService.getAllEvents().forEach(event -> { event.getLeaderboardGroups().forEach(leaderboardGroup -> { if (Util.contains(leaderboardGroup.getLeaderboards(), leaderboard)) { @@ -74,6 +83,8 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific }); int foundEventsCount = foundEvents.size(); if (foundEventsCount == 1) { + // if multiple LeaderboardGroups of the single event reference the same leaderboard, we just use the + // first LeaderboardGroup. This could be a non optimal match but helps to e.g. construct valid links. return new Pair<>(Util.get(foundEvents, 0), Util.get(foundLeaderboardGroups, 0)); } else if (foundEventsCount > 1 && foundLeaderboardGroups.size() == 1) { // could be a series @@ -87,15 +98,24 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific } } } + // Event <-> Leaderboard association is not set up correctly. The UI will show the Leaderboard for + // multiple Events. So any of the found Events is ok for this case. + return new Pair<>(Util.get(foundEvents, 0), leaderboardGroup); } } // No associated event found or association is ambiguous return null; } + /** + * Calculated the best matching Event/LeaderBoardGroup pair via + * {@link #calculateAssociatedEventForLeaderboard(Leaderboard)} and calls the given consumer with these instances. + * If the racingEventService isn't already set, this will do nothing. + */ private void doWithEvent(Leaderboard leaderboard, BiConsumer consumer) { if (racingEventService == null) { - // TODO log + logger.severe( + "Can't send notifications if " + getClass().getSimpleName() + ".racingEventService isn't set"); return; } Pair eventAndLeaderboardGroup = calculateAssociatedEventForLeaderboard(leaderboard); @@ -182,7 +202,8 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific Fleet fleet, TimePoint when) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { // TODO where to get the base URL? - String link = "/gwt/Home.html#/regatta/races/:eventId="+event.getId()+"®attaId=" + leaderboard.getName(); + String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" + + leaderboard.getName(); mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) { @Override From 5847b016ce7f8a5037ff82fe303d0df3be5feac6 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 13:26:34 +0200 Subject: [PATCH 192/259] Extended User to have an optional locale field to store the user's language preference --- ...ferenceObjectBasedNotificationSetTest.java | 2 +- .../mongodb/impl/DomainObjectFactoryImpl.java | 5 +++- .../userstore/mongodb/impl/FieldNames.java | 1 + .../mongodb/impl/MongoObjectFactoryImpl.java | 1 + .../src/com/sap/sse/security/User.java | 24 +++++++++++++++++-- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 865f4a0b414..1494f36f063 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -263,7 +263,7 @@ public class PreferenceObjectBasedNotificationSetTest { private void createUserWithVerifiedEmail(String username, String email) throws UserManagementException { store.createUser(username, email); - store.updateUser(new User(username, email, null, null, true, null, null, Collections.emptySet())); + store.updateUser(new User(username, email, null, null, null, true, null, null, Collections.emptySet())); } private static class PreferenceObjectBasedNotificationSetImpl extends PreferenceObjectBasedNotificationSet, String> { diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/DomainObjectFactoryImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/DomainObjectFactoryImpl.java index 921b99b44d1..07e0487fc49 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/DomainObjectFactoryImpl.java @@ -3,6 +3,7 @@ package com.sap.sse.security.userstore.mongodb.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -66,6 +67,8 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { final String email = (String) userDBObject.get(FieldNames.User.EMAIL.name()); final String fullName = (String) userDBObject.get(FieldNames.User.FULLNAME.name()); final String company = (String) userDBObject.get(FieldNames.User.COMPANY.name()); + final String localeRaw = (String) userDBObject.get(FieldNames.User.LOCALE.name()); + final Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null; Boolean emailValidated = (Boolean) userDBObject.get(FieldNames.User.EMAIL_VALIDATED.name()); String passwordResetSecret = (String) userDBObject.get(FieldNames.User.PASSWORD_RESET_SECRET.name()); String validationSecret = (String) userDBObject.get(FieldNames.User.VALIDATION_SECRET.name()); @@ -85,7 +88,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { } DBObject accountsMap = (DBObject) userDBObject.get(FieldNames.User.ACCOUNTS.name()); Map accounts = createAccountMapFromdDBObject(accountsMap); - User result = new User(name, email, fullName, company, emailValidated==null?false:emailValidated, passwordResetSecret, validationSecret, accounts.values()); + User result = new User(name, email, fullName, company, locale, emailValidated==null?false:emailValidated, passwordResetSecret, validationSecret, accounts.values()); for (String role : roles) { result.addRole(role); } diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/FieldNames.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/FieldNames.java index 2827246a87a..6951a7d65dd 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/FieldNames.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/FieldNames.java @@ -6,6 +6,7 @@ public class FieldNames { NAME, FULLNAME, COMPANY, + LOCALE, EMAIL, ACCOUNTS, ROLES, PERMISSIONS, diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/MongoObjectFactoryImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/MongoObjectFactoryImpl.java index 9a70a948896..eadfc41af1d 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/MongoObjectFactoryImpl.java @@ -40,6 +40,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { dbUser.put(FieldNames.User.EMAIL.name(), user.getEmail()); dbUser.put(FieldNames.User.FULLNAME.name(), user.getFullName()); dbUser.put(FieldNames.User.COMPANY.name(), user.getCompany()); + dbUser.put(FieldNames.User.LOCALE.name(), user.getLocale() != null ? user.getLocale().toLanguageTag() : null); dbUser.put(FieldNames.User.EMAIL_VALIDATED.name(), user.isEmailValidated()); dbUser.put(FieldNames.User.PASSWORD_RESET_SECRET.name(), user.getPasswordResetSecret()); dbUser.put(FieldNames.User.VALIDATION_SECRET.name(), user.getValidationSecret()); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/User.java b/java/com.sap.sse.security/src/com/sap/sse/security/User.java index 6e0eaf536c7..7a0d39f1adf 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/User.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/User.java @@ -6,6 +6,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Locale; import java.util.Map; import java.util.Random; import java.util.Set; @@ -35,6 +36,12 @@ public class User implements NamedWithID { * corporate vs. private users, if used as a marketing tool. */ private String company; + + /** + * An optional field specifying the locale preference of the user. This can be used to internationalize User + * specific elements as UIs or notification mails. + */ + private Locale locale; private String email; @@ -66,16 +73,17 @@ public class User implements NamedWithID { } public User(String name, String email, Collection accounts) { - this(name, email, /* fullName */ null, /* company */ null, /* is email validated */ false, + this(name, email, /* fullName */ null, /* company */ null, /* locale */ null, /* is email validated */ false, /* password reset secret */ null, /* validation secret */ null, accounts); } - public User(String name, String email, String fullName, String company, Boolean emailValidated, + public User(String name, String email, String fullName, String company, Locale locale, Boolean emailValidated, String passwordResetSecret, String validationSecret, Collection accounts) { super(); this.name = name; this.fullName = fullName; this.company = company; + this.locale = locale; this.roles = new HashSet<>(); this.permissions = new HashSet<>(); this.email = email; @@ -119,6 +127,18 @@ public class User implements NamedWithID { public void setCompany(String company) { this.company = company; } + + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + + public Locale getLocaleOrDefault() { + return locale == null ? Locale.ENGLISH : locale; + } public Iterable getRoles() { return roles; From 1ae892f9937fd8df1598022ac53f20727cace209 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 13:28:39 +0200 Subject: [PATCH 193/259] Extended User.toString to also include fields added recently --- java/com.sap.sse.security/src/com/sap/sse/security/User.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/User.java b/java/com.sap.sse.security/src/com/sap/sse/security/User.java index 7a0d39f1adf..b42d2aec074 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/User.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/User.java @@ -263,7 +263,8 @@ public class User implements NamedWithID { @Override public String toString() { - return "User [name=" + name + ", email=" + email + (isEmailValidated()?" (validated)":")")+", roles=" + return "User [name=" + name + ", email=" + email + ", fullName=" + fullName + ", company=" + company + + ", locale=" + locale + (isEmailValidated() ? " (validated)" : ")") + ", roles=" + Arrays.toString(roles.toArray(new String[roles.size()])) + ", accounts=" + Arrays.toString(accounts.keySet().toArray(new AccountType[accounts.size()])) + "]"; } From b741d72f911a27fe1153acfe60262106ce2ab4c9 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 13:29:20 +0200 Subject: [PATCH 194/259] Added a test to verify that common masterdata fields of User are correctly stored --- .../test/UserStoreWithPersistenceTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java index d5d9d77c397..c152beae7b3 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java @@ -5,6 +5,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.net.UnknownHostException; +import java.util.Collections; +import java.util.Locale; import org.junit.Before; import org.junit.Test; @@ -13,6 +15,7 @@ import com.mongodb.DB; import com.mongodb.MongoException; import com.sap.sse.mongodb.MongoDBConfiguration; import com.sap.sse.mongodb.MongoDBService; +import com.sap.sse.security.User; import com.sap.sse.security.UserStore; import com.sap.sse.security.shared.UserManagementException; import com.sap.sse.security.userstore.mongodb.UserStoreImpl; @@ -23,6 +26,8 @@ import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; */ public class UserStoreWithPersistenceTest { private final String username = "abc"; + private final String fullName = "Arno Nym"; + private final String company = "SAP SE"; private final String email = "anonymous@sapsailing.com"; private final String prefKey = "pk"; private final String prefValue = "pv"; @@ -55,6 +60,18 @@ public class UserStoreWithPersistenceTest { assertNotNull(store.getUserByName(username)); assertNotNull(store.getUserByEmail(email)); } + + @Test + public void testMasterdataIsSaved() throws UserManagementException { + store.createUser(username, email); + store.updateUser(new User(username, email, fullName, company, Locale.GERMAN, false, null, null, Collections.emptySet())); + newStore(); + User savedUser = store.getUserByName(username); + assertEquals(username, savedUser.getName()); + assertEquals(email, savedUser.getEmail()); + assertEquals(company, savedUser.getCompany()); + assertEquals(Locale.GERMAN, savedUser.getLocale()); + } /** * There was a {@link NullPointerException} thrown if calling getUserByEmail for an email address for which there From 1b0c923bb1e944f83d14972bcfe68130427143c2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 13:32:46 +0200 Subject: [PATCH 195/259] Extended UserDTO to also include the user's locale --- .../ui/authentication/app/AuthenticationContextImpl.java | 2 +- .../sse/security/ui/server/UserManagementServiceImpl.java | 3 ++- .../main/java/com/sap/sse/security/ui/shared/UserDTO.java | 7 ++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/authentication/app/AuthenticationContextImpl.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/authentication/app/AuthenticationContextImpl.java index e9ae87755bf..f3f62c416f1 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/authentication/app/AuthenticationContextImpl.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/authentication/app/AuthenticationContextImpl.java @@ -11,7 +11,7 @@ import com.sap.sse.security.ui.shared.UserDTO; public class AuthenticationContextImpl implements AuthenticationContext { private final UserDTO currentUser; - private final static UserDTO ANONYMOUS = new UserDTO("Anonymous", "", "", "", false, new ArrayList(), + private final static UserDTO ANONYMOUS = new UserDTO("Anonymous", "", "", "", null, false, new ArrayList(), new ArrayList(), new ArrayList()); /** diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java index 5ab5cd037c1..2f4a83f6121 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java @@ -302,7 +302,8 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U } } userDTO = new UserDTO(user.getName(), user.getEmail(), user.getFullName(), user.getCompany(), - user.isEmailValidated(), accountDTOs, user.getRoles(), user.getPermissions()); + user.getLocale() != null ? user.getLocale().toLanguageTag() : null, user.isEmailValidated(), + accountDTOs, user.getRoles(), user.getPermissions()); return userDTO; } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java index 0711d793807..bf5fe3921ca 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java @@ -16,6 +16,7 @@ public class UserDTO implements IsSerializable { private String email; private String fullName; private String company; + private String locale; private List accounts; private Set roles; private Set permissions; @@ -23,7 +24,7 @@ public class UserDTO implements IsSerializable { UserDTO() {} // for serialization only - public UserDTO(String name, String email, String fullName, String company, boolean emailValidated, + public UserDTO(String name, String email, String fullName, String company, String locale, boolean emailValidated, List accounts, Iterable roles, Iterable stringPermissions) { this.name = name; this.email = email; @@ -50,6 +51,10 @@ public class UserDTO implements IsSerializable { public String getCompany() { return company; } + + public String getLocale() { + return locale; + } public Iterable getRoles() { return roles; From 0163cc55712f24edf82249162e96397b70d1333e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 13:37:47 +0200 Subject: [PATCH 196/259] Changed UserManagementService.updateUserProperties to also update the user's locale --- .../sap/sse/security/ui/client/UserManagementService.java | 2 +- .../security/ui/client/UserManagementServiceAsync.java | 2 +- .../sse/security/ui/server/UserManagementServiceImpl.java | 6 ++++-- .../shared/userdetails/UserDetailsPresenter.java | 3 ++- .../src/com/sap/sse/security/SecurityService.java | 3 ++- .../com/sap/sse/security/impl/SecurityServiceImpl.java | 8 +++++--- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java index 48b0ada4f0a..51707bb9fd0 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java @@ -31,7 +31,7 @@ public interface UserManagementService extends RemoteService { void updateSimpleUserEmail(String username, String newEmail, String validationBaseURL) throws UserManagementException, MailException; - void updateUserProperties(String username, String fullName, String company) throws UserManagementException; + void updateUserProperties(String username, String fullName, String company, String localeName) throws UserManagementException; void resetPassword(String username, String eMailAddress, String baseURL) throws UserManagementException, MailException; diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java index 159a67a00ff..a27a905f451 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java @@ -28,7 +28,7 @@ public interface UserManagementServiceAsync { void updateSimpleUserEmail(String username, String newEmail, String validationBaseURL, AsyncCallback callback); - void updateUserProperties(String username, String fullName, String company, AsyncCallback callback); + void updateUserProperties(String username, String fullName, String company, String localeName, AsyncCallback callback); void getFilteredSortedUserList(String filter, AsyncCallback> callback); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java index 2f4a83f6121..b1ad90064a8 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -166,11 +167,12 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U } @Override - public void updateUserProperties(final String username, String fullName, String company) throws UserManagementException { + public void updateUserProperties(final String username, String fullName, String company, String localeName) throws UserManagementException { final Subject subject = SecurityUtils.getSubject(); // the signed-in subject has role ADMIN or is changing own user if (subject.hasRole(DefaultRoles.ADMIN.getRolename()) || username.equals(subject.getPrincipal().toString())) { - getSecurityService().updateUserProperties(username, fullName, company); + getSecurityService().updateUserProperties(username, fullName, company, + localeName == null || localeName.isEmpty() ? null : Locale.forLanguageTag(localeName)); } else { throw new UserManagementException(UserManagementException.INVALID_CREDENTIALS); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java index fa50245238b..51ddb0c7dad 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java @@ -44,7 +44,8 @@ public class UserDetailsPresenter implements AbstractUserDetails.Presenter { @Override public void handleSaveChangesRequest(String fullName, String company) { final String username = authenticationManager.getAuthenticationContext().getCurrentUser().getName(); - userManagementService.updateUserProperties(username, fullName, company, + // FIXME set locale + userManagementService.updateUserProperties(username, fullName, company, null, new AsyncCallback() { @Override public void onSuccess(Void result) { diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java b/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java index d9e34b171ef..7382c68cda6 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java @@ -1,5 +1,6 @@ package com.sap.sse.security; +import java.util.Locale; import java.util.Map; import java.util.UUID; @@ -57,7 +58,7 @@ public interface SecurityService extends ReplicableWithObjectInputStreams.internalStoreUser(user)); } From 37512b41a7f7d1e6a59e7be84d8f0c0fad9d0298 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 14:04:49 +0200 Subject: [PATCH 197/259] Added missing assignment of locale field in UserDTO constructor --- .../src/main/java/com/sap/sse/security/ui/shared/UserDTO.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java index bf5fe3921ca..49f10f1f87b 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/UserDTO.java @@ -30,6 +30,7 @@ public class UserDTO implements IsSerializable { this.email = email; this.fullName = fullName; this.company = company; + this.locale = locale; this.emailValidated = emailValidated; this.accounts = accounts; this.roles = new HashSet<>(); From 9b40edc08dcd98b41cc2e97cd87acde32478832f Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 14:09:52 +0200 Subject: [PATCH 198/259] Added new field for the language selection to the user profile page --- .../ui/client/i18n/StringMessages.java | 1 + .../ui/client/i18n/StringMessages.properties | 3 +- .../client/i18n/StringMessages_de.properties | 3 +- .../userdetails/UserAccountDetails.ui.xml | 8 ++- .../mobile/userdetails/UserDetails.ui.xml | 6 ++ .../userdetails/AbstractUserDetails.java | 56 ++++++++++++++++++- .../userdetails/UserDetailsPresenter.java | 5 +- .../shared/userdetails/UserDetailsView.java | 2 +- 8 files changed, 76 insertions(+), 8 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java index 170b284a7dc..2fc3324879b 100755 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java @@ -98,4 +98,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { String accountConfirmation(); String error(); String refresh(); + String preferredLanguage(); } diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties index 695f2c8eadf..f4ebe2897bd 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties @@ -93,4 +93,5 @@ youAreNotSignedIn=You are currently not signed in. youDontHaveRequiredPermission=You don''t have the required permission. accountConfirmation=Account confirmation error=Unknown error -refresh=Refresh \ No newline at end of file +refresh=Refresh +preferredLanguage=Preferred language diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties index 961c3654b6a..616fdb0405b 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties @@ -93,4 +93,5 @@ youAreNotSignedIn=Sie sind aktuell nicht eingeloggt. youDontHaveRequiredPermission=Sie besitzen nicht die benötigten Rechte. accountConfirmation=Kontobestätigung error=Es ist ein Fehler aufgetreten -refresh=Aktualisieren \ No newline at end of file +refresh=Aktualisieren +preferredLanguage=Bevorzugte Sprache diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/desktop/userdetails/UserAccountDetails.ui.xml b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/desktop/userdetails/UserAccountDetails.ui.xml index aaa56199983..4f17c40cb94 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/desktop/userdetails/UserAccountDetails.ui.xml +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/desktop/userdetails/UserAccountDetails.ui.xml @@ -24,12 +24,18 @@ -
        +
        +
        + + +
        diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/mobile/userdetails/UserDetails.ui.xml b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/mobile/userdetails/UserDetails.ui.xml index de781b77064..f848eeb65ff 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/mobile/userdetails/UserDetails.ui.xml +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/mobile/userdetails/UserDetails.ui.xml @@ -25,6 +25,12 @@
        +
        +
        + +
        + +
        diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java index 0e49bc6a03a..4e7e1a7a34e 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java @@ -1,13 +1,23 @@ package com.sap.sse.security.ui.userprofile.shared.userdetails; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + import com.google.gwt.dom.client.InputElement; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.i18n.client.LocaleInfo; +import com.google.gwt.text.shared.Renderer; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; +import com.sap.sse.common.Util.Pair; import com.sap.sse.security.ui.client.i18n.StringMessages; import com.sap.sse.security.ui.shared.UserDTO; @@ -23,6 +33,27 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { @UiField public InputElement usernameUi; @UiField public TextBox nameUi; @UiField public TextBox companyUi; + + @UiField(provided = true) + public ValueListBox> localeUi = new ValueListBox>( + new Renderer>() { + @Override + public String render(Pair object) { + if (object == null) { + return ""; + } + if (object.getB() != null) { + return object.getB(); + } + return object.getA(); + } + + @Override + public void render(Pair object, Appendable appendable) throws IOException { + appendable.append(render(object)); + } + }); + @UiField public TextBox emailUi; @UiField public PasswordTextBox oldPasswordUi; @UiField public PasswordTextBox newPasswordUi; @@ -54,8 +85,29 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { usernameUi.setValue(currentUser.getName()); emailUi.setValue(currentUser.getEmail()); + String currentLocale = currentUser.getLocale(); + Collection> values = new ArrayList<>(); + Pair selectedValue = null; + for (String localeName : getAvailableLocales()) { + Pair value = new Pair(localeName, LocaleInfo.getLocaleNativeDisplayName(localeName)); + values.add(value); + if (currentLocale != null && currentLocale.equals(localeName)) { + selectedValue = value; + } + } + localeUi.setValue(selectedValue); + localeUi.setAcceptableValues(values); + clearPasswordFields(); } + + // FIXME taken from GWTLocaleUtil -> move GWTLocaleUtil somwhere else so it can be seen here + public static Iterable getAvailableLocales() { + List result = new ArrayList<>(); + result.addAll(Arrays.asList(LocaleInfo.getAvailableLocaleNames())); + result.remove("default"); + return result; + } public void clearPasswordFields() { oldPasswordUi.setValue(""); @@ -69,7 +121,9 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { @UiHandler("saveChangesUi") public void onSaveChangesClicked(ClickEvent event) { - presenter.handleSaveChangesRequest(nameUi.getValue(), companyUi.getValue()); + Pair selectedLocaleValue = localeUi.getValue(); + String locale = selectedLocaleValue != null ? selectedLocaleValue.getA() : null; + presenter.handleSaveChangesRequest(nameUi.getValue(), companyUi.getValue(), locale); } @UiHandler("changeEmailUi") diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java index 51ddb0c7dad..ae42fe54269 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsPresenter.java @@ -42,10 +42,9 @@ public class UserDetailsPresenter implements AbstractUserDetails.Presenter { } @Override - public void handleSaveChangesRequest(String fullName, String company) { + public void handleSaveChangesRequest(String fullName, String company, String locale) { final String username = authenticationManager.getAuthenticationContext().getCurrentUser().getName(); - // FIXME set locale - userManagementService.updateUserProperties(username, fullName, company, null, + userManagementService.updateUserProperties(username, fullName, company, locale, new AsyncCallback() { @Override public void onSuccess(Void result) { diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsView.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsView.java index 1053b8ba5dd..72305b3234d 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsView.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/UserDetailsView.java @@ -15,7 +15,7 @@ public interface UserDetailsView { void clearPasswordFields(); public interface Presenter { - void handleSaveChangesRequest(String fullName, String company); + void handleSaveChangesRequest(String fullName, String company, String locale); void handleEmailChangeRequest(String email); void handlePasswordChangeRequest(String oldPassword, String newPassword, String newPasswordConfirmation); } From d47e1cb70ec1b16e99a286c1ebc9380a5ff7bb48 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Wed, 13 Jul 2016 14:11:11 +0200 Subject: [PATCH 199/259] Using the actual user locale in NotificationSetNotification if available --- .../server/notification/impl/NotificationSetNotification.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java index d2dbe8f4342..8d051707277 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -29,8 +29,7 @@ public abstract class NotificationSetNotification implements MailNotification // TODO idea (c) by Axel Uhl: In case of performance/mail queue problems: group mail addresses by locale and // send batches with the actual mail addresses as bcc? associatedNotificationSet.forUsersWithVerifiedEmailMappedTo(objectToNotifyAbout, (user) -> { - // TODO user defined locale - Locale locale = Locale.ENGLISH; + Locale locale = user.getLocaleOrDefault(); Multipart multipart = new MimeMultipart(); BodyPart bodyPart = new MimeBodyPart(); try { From 8e26634e57b72e44cbafe8ea032e75d254d27ffb Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 14 Jul 2016 08:28:16 +0200 Subject: [PATCH 200/259] Improved testability --- .../impl/SailingNotificationServiceImpl.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 94bca316b40..faa6e4fd0dd 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -31,6 +31,7 @@ import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl; import com.sap.sse.mail.queue.MailQueue; +import com.sap.sse.security.UserStore; public class SailingNotificationServiceImpl implements Stoppable, SailingNotificationService { private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/StringMessages"; @@ -47,13 +48,32 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific private final CompetitorResultsNotificationSet competitorResults; public SailingNotificationServiceImpl(BundleContext bundleContext, MailQueue mailQueue) { + this(mailQueue, + new BoatClassResultsNotificationSet(bundleContext), + new BoatClassUpcomingRaceNotificationSet(bundleContext), + new CompetitorResultsNotificationSet(bundleContext)); + } + + /** + * Constructor used for unit tests to not need BundelContext but directly work with a given UserStore. + */ + public SailingNotificationServiceImpl(UserStore userStore, MailQueue mailQueue) { + this(mailQueue, + new BoatClassResultsNotificationSet(userStore), + new BoatClassUpcomingRaceNotificationSet(userStore), + new CompetitorResultsNotificationSet(userStore)); + } + + public SailingNotificationServiceImpl(MailQueue mailQueue, BoatClassResultsNotificationSet boatClassResults, + BoatClassUpcomingRaceNotificationSet boatClassUpcomingRace, + CompetitorResultsNotificationSet competitorResults) { this.mailQueue = mailQueue; this.messages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, this.getClass().getClassLoader()); - - toStop.add(boatClassResults = new BoatClassResultsNotificationSet(bundleContext)); - toStop.add(boatClassUpcomingRace = new BoatClassUpcomingRaceNotificationSet(bundleContext)); - toStop.add(competitorResults = new CompetitorResultsNotificationSet(bundleContext)); + + toStop.add(this.boatClassResults = boatClassResults); + toStop.add(this.boatClassUpcomingRace = boatClassUpcomingRace); + toStop.add(this.competitorResults = competitorResults); } @Override From da7d1e4fc4f545b94bd5d9bc0208cb20281ab392 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 14 Jul 2016 09:12:02 +0200 Subject: [PATCH 201/259] Moved GWTLocaleUtil to com.sap.sse.gwt for better reusability --- .../gwt/autoplay/client/place/start/DesktopStartView.java | 2 +- .../sap/sailing/gwt/home/desktop/partials/footer/Footer.java | 2 +- .../java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java | 2 +- .../java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java | 2 +- .../src/com/sap/sse/gwt}/client/GWTLocaleUtil.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename java/{com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common => com.sap.sse.gwt/src/com/sap/sse/gwt}/client/GWTLocaleUtil.java (98%) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/start/DesktopStartView.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/start/DesktopStartView.java index 3ec805f6f37..e716d2100d0 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/start/DesktopStartView.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/autoplay/client/place/start/DesktopStartView.java @@ -27,7 +27,6 @@ import com.sap.sailing.gwt.autoplay.client.app.PlaceNavigator; import com.sap.sailing.gwt.autoplay.client.place.player.AutoPlayerConfiguration; import com.sap.sailing.gwt.autoplay.client.shared.leaderboard.LeaderboardWithHeaderPerspectiveLifecycle; import com.sap.sailing.gwt.autoplay.client.shared.leaderboard.LeaderboardWithHeaderPerspectiveSettings; -import com.sap.sailing.gwt.common.client.GWTLocaleUtil; import com.sap.sailing.gwt.common.client.SharedResources; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.raceboard.RaceBoardPerspectiveLifecycle; @@ -36,6 +35,7 @@ import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO; import com.sap.sse.common.settings.Settings; +import com.sap.sse.gwt.client.GWTLocaleUtil; import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; import com.sap.sse.gwt.client.event.LocaleChangeEvent; import com.sap.sse.gwt.client.sapheader.SAPHeader; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/footer/Footer.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/footer/Footer.java index 257d2b9aaed..02fc522ec7e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/footer/Footer.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/desktop/partials/footer/Footer.java @@ -25,7 +25,6 @@ import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; import com.google.web.bindery.event.shared.EventBus; -import com.sap.sailing.gwt.common.client.GWTLocaleUtil; import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator; import com.sap.sailing.gwt.home.desktop.places.whatsnew.WhatsNewPlace; import com.sap.sailing.gwt.home.desktop.places.whatsnew.WhatsNewPlace.WhatsNewNavigationTabs; @@ -33,6 +32,7 @@ import com.sap.sailing.gwt.home.shared.SwitchingEntryPoint; import com.sap.sailing.gwt.home.shared.app.PlaceNavigation; import com.sap.sse.common.Util; import com.sap.sse.common.Util.Pair; +import com.sap.sse.gwt.client.GWTLocaleUtil; public class Footer extends Composite { private static FooterPanelUiBinder uiBinder = GWT.create(FooterPanelUiBinder.class); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index bd1cfdda6c9..e94731bd756 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -23,7 +23,6 @@ import com.google.gwt.user.client.ui.TextArea; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.common.client.GWTLocaleUtil; import com.sap.sailing.gwt.ui.client.DataEntryDialogWithBootstrap; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -33,6 +32,7 @@ import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.VenueDTO; +import com.sap.sse.gwt.client.GWTLocaleUtil; import com.sap.sse.gwt.client.IconResources; import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite; import com.sap.sse.gwt.client.controls.listedit.StringConstantsListEditorComposite; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java index e531c1754bd..ffc87d27031 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/VideoDialog.java @@ -14,12 +14,12 @@ import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.gwt.common.client.GWTLocaleUtil; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sse.common.Util; import com.sap.sse.common.media.MimeType; import com.sap.sse.gwt.adminconsole.URLFieldWithFileUpload; +import com.sap.sse.gwt.client.GWTLocaleUtil; import com.sap.sse.gwt.client.IconResources; import com.sap.sse.gwt.client.controls.IntegerBox; import com.sap.sse.gwt.client.controls.listedit.GenericStringListInlineEditorComposite; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/GWTLocaleUtil.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/GWTLocaleUtil.java similarity index 98% rename from java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/GWTLocaleUtil.java rename to java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/GWTLocaleUtil.java index d9265b0c6b1..74f920d50df 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/common/client/GWTLocaleUtil.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/GWTLocaleUtil.java @@ -1,4 +1,4 @@ -package com.sap.sailing.gwt.common.client; +package com.sap.sse.gwt.client; import java.util.ArrayList; import java.util.Arrays; From 7f0d169b820ee111e4e4e5b8fcda66f5e2126620 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 14 Jul 2016 09:15:03 +0200 Subject: [PATCH 202/259] Removed duplicate code by using GWTLocaleUtil --- .../shared/userdetails/AbstractUserDetails.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java index 4e7e1a7a34e..0116884f3af 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java @@ -2,9 +2,7 @@ package com.sap.sse.security.ui.userprofile.shared.userdetails; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.List; import com.google.gwt.dom.client.InputElement; import com.google.gwt.event.dom.client.ClickEvent; @@ -18,6 +16,7 @@ import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; import com.sap.sse.common.Util.Pair; +import com.sap.sse.gwt.client.GWTLocaleUtil; import com.sap.sse.security.ui.client.i18n.StringMessages; import com.sap.sse.security.ui.shared.UserDTO; @@ -88,7 +87,7 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { String currentLocale = currentUser.getLocale(); Collection> values = new ArrayList<>(); Pair selectedValue = null; - for (String localeName : getAvailableLocales()) { + for (String localeName : GWTLocaleUtil.getAvailableLocales()) { Pair value = new Pair(localeName, LocaleInfo.getLocaleNativeDisplayName(localeName)); values.add(value); if (currentLocale != null && currentLocale.equals(localeName)) { @@ -100,14 +99,6 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { clearPasswordFields(); } - - // FIXME taken from GWTLocaleUtil -> move GWTLocaleUtil somwhere else so it can be seen here - public static Iterable getAvailableLocales() { - List result = new ArrayList<>(); - result.addAll(Arrays.asList(LocaleInfo.getAvailableLocaleNames())); - result.remove("default"); - return result; - } public void clearPasswordFields() { oldPasswordUi.setValue(""); From 4f4f8c669e5c430f16b58b17234bb7f5b2d736ff Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 14 Jul 2016 09:40:40 +0200 Subject: [PATCH 203/259] Reusing more GWTLocaleUtil functionality for the user profile locale selection to simplify the code --- .../com/sap/sse/gwt/client/GWTLocaleUtil.java | 3 +- .../userdetails/AbstractUserDetails.java | 48 +++++-------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/GWTLocaleUtil.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/GWTLocaleUtil.java index 74f920d50df..61e7fc41274 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/GWTLocaleUtil.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/GWTLocaleUtil.java @@ -2,6 +2,7 @@ package com.sap.sse.gwt.client; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import com.google.gwt.i18n.client.LocaleInfo; @@ -35,7 +36,7 @@ public final class GWTLocaleUtil { * * @return all available client locales plus a null entry */ - public static Iterable getAvailableLocalesAndDefault() { + public static Collection getAvailableLocalesAndDefault() { List result = new ArrayList<>(); result.add(null); Util.addAll(getAvailableLocales(), result); diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java index 0116884f3af..f8b387fea3d 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/userprofile/shared/userdetails/AbstractUserDetails.java @@ -1,12 +1,9 @@ package com.sap.sse.security.ui.userprofile.shared.userdetails; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; import com.google.gwt.dom.client.InputElement; import com.google.gwt.event.dom.client.ClickEvent; -import com.google.gwt.i18n.client.LocaleInfo; import com.google.gwt.text.shared.Renderer; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; @@ -15,7 +12,6 @@ import com.google.gwt.user.client.ui.PasswordTextBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; -import com.sap.sse.common.Util.Pair; import com.sap.sse.gwt.client.GWTLocaleUtil; import com.sap.sse.security.ui.client.i18n.StringMessages; import com.sap.sse.security.ui.shared.UserDTO; @@ -34,24 +30,17 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { @UiField public TextBox companyUi; @UiField(provided = true) - public ValueListBox> localeUi = new ValueListBox>( - new Renderer>() { - @Override - public String render(Pair object) { - if (object == null) { - return ""; - } - if (object.getB() != null) { - return object.getB(); - } - return object.getA(); - } + public ValueListBox localeUi = new ValueListBox(new Renderer() { + @Override + public String render(String object) { + return GWTLocaleUtil.getDecoratedLanguageDisplayNameWithDefaultLocaleSupport(object); + } - @Override - public void render(Pair object, Appendable appendable) throws IOException { - appendable.append(render(object)); - } - }); + @Override + public void render(String object, Appendable appendable) throws IOException { + appendable.append(render(object)); + } + }); @UiField public TextBox emailUi; @UiField public PasswordTextBox oldPasswordUi; @@ -85,17 +74,8 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { emailUi.setValue(currentUser.getEmail()); String currentLocale = currentUser.getLocale(); - Collection> values = new ArrayList<>(); - Pair selectedValue = null; - for (String localeName : GWTLocaleUtil.getAvailableLocales()) { - Pair value = new Pair(localeName, LocaleInfo.getLocaleNativeDisplayName(localeName)); - values.add(value); - if (currentLocale != null && currentLocale.equals(localeName)) { - selectedValue = value; - } - } - localeUi.setValue(selectedValue); - localeUi.setAcceptableValues(values); + localeUi.setValue(currentLocale); + localeUi.setAcceptableValues(GWTLocaleUtil.getAvailableLocalesAndDefault()); clearPasswordFields(); } @@ -112,9 +92,7 @@ public class AbstractUserDetails extends Composite implements UserDetailsView { @UiHandler("saveChangesUi") public void onSaveChangesClicked(ClickEvent event) { - Pair selectedLocaleValue = localeUi.getValue(); - String locale = selectedLocaleValue != null ? selectedLocaleValue.getA() : null; - presenter.handleSaveChangesRequest(nameUi.getValue(), companyUi.getValue(), locale); + presenter.handleSaveChangesRequest(nameUi.getValue(), companyUi.getValue(), localeUi.getValue()); } @UiHandler("changeEmailUi") From aec8cb7bf255d380e23ce7c4058b1da170d353f2 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 14 Jul 2016 09:44:57 +0200 Subject: [PATCH 204/259] Removed code duplications --- .../impl/SailingNotificationServiceImpl.java | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index faa6e4fd0dd..968950a9b86 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -168,16 +168,29 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific return messages.get(locale, "leaderboardOfEvent", leaderboardDisplayName, eventName); } + private String createRaceBoardLink(TrackedRace trackedRace, Leaderboard leaderboard, Event event, + LeaderboardGroup leaderboardGroup) { + RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); + // TODO where to get the base URL? + String link = "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() + + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" + + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" + + raceIdentifier.getRegattaName(); + return link; + } + + private String createHomeRacesListLink(Leaderboard leaderboard, Event event) { + // TODO where to get the base URL? + String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" + + leaderboard.getName(); + return link; + } + @Override public void notifyUserOnBoatClassRaceChangesStateToFinishing(BoatClass boatClass, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); - // TODO where to get the base URL? - String link = "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() - + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" - + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" - + raceIdentifier.getRegattaName(); + String link = createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup); mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { @Override @@ -198,9 +211,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific @Override public void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - // TODO where to get the base URL? - String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" - + leaderboard.getName(); + String link = createHomeRacesListLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { @Override @@ -221,9 +232,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, TimePoint when) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - // TODO where to get the base URL? - String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" - + leaderboard.getName(); + String link = createHomeRacesListLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) { @Override @@ -247,12 +256,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific public void notifyUserOnCompetitorPassesFinish(Competitor competitor, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); - // TODO where to get the base URL? - String link = "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() - + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" - + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" - + raceIdentifier.getRegattaName(); + String link = createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup); mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { @Override @@ -273,9 +277,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific @Override public void notifyUserOnCompetitorScoreCorrections(Competitor competitor, Leaderboard leaderboard) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - // TODO where to get the base URL? - String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" - + leaderboard.getName(); + String link = createHomeRacesListLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { @Override From cb927ccb9c5e6fc8c39e7512a5538afc7b8fafc9 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 14 Jul 2016 09:49:16 +0200 Subject: [PATCH 205/259] Linking to leaderboard for score correction related notifications --- .../impl/SailingNotificationServiceImpl.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 968950a9b86..38186517bca 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -180,8 +180,16 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific } private String createHomeRacesListLink(Leaderboard leaderboard, Event event) { + return createHomeRegattaLink("races", leaderboard, event); + } + + private String createHomeLeaderboardLink(Leaderboard leaderboard, Event event) { + return createHomeRegattaLink("leaderboard", leaderboard, event); + } + + private String createHomeRegattaLink(String tab, Leaderboard leaderboard, Event event) { // TODO where to get the base URL? - String link = "/gwt/Home.html#/regatta/races/:eventId=" + event.getId() + "®attaId=" + String link = "/gwt/Home.html#/regatta/" + tab + "/:eventId=" + event.getId() + "®attaId=" + leaderboard.getName(); return link; } @@ -211,7 +219,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific @Override public void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - String link = createHomeRacesListLink(leaderboard, event); + String link = createHomeLeaderboardLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { @Override @@ -277,7 +285,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific @Override public void notifyUserOnCompetitorScoreCorrections(Competitor competitor, Leaderboard leaderboard) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - String link = createHomeRacesListLink(leaderboard, event); + String link = createHomeLeaderboardLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { @Override From 97c25d6bcd5716f2a59c6df6541237c96408d28c Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 13:56:07 +0200 Subject: [PATCH 206/259] added baseURL property to EventBase Change-Id: I0fbd92b14331918986d817fc86a06912ae8f603d --- .../impl/DomainObjectFactoryImpl.java | 8 ++++ .../domain/persistence/impl/FieldNames.java | 1 + .../impl/MongoObjectFactoryImpl.java | 1 + .../sap/sailing/domain/base/EventBase.java | 10 +++++ .../domain/base/impl/EventBaseImpl.java | 13 ++++++- .../ui/adminconsole/EventCreateDialog.java | 2 + .../gwt/ui/adminconsole/EventDialog.java | 38 ++++++++++--------- .../gwt/ui/adminconsole/EventEditDialog.java | 2 + .../ui/adminconsole/EventListComposite.java | 10 ++--- .../StructureImportManagementPanel.java | 6 +-- .../sailing/gwt/ui/client/SailingService.java | 8 ++-- .../gwt/ui/client/SailingServiceAsync.java | 9 +++-- .../sailing/gwt/ui/client/StringMessages.java | 1 + .../gwt/ui/client/StringMessages.properties | 1 + .../ui/client/StringMessages_de.properties | 1 + .../gwt/ui/server/SailingServiceImpl.java | 31 ++++++++------- .../sailing/gwt/ui/shared/EventBaseDTO.java | 2 +- ...estStoringAndLoadingEventsAndRegattas.java | 3 ++ .../impl/EventBaseJsonDeserializer.java | 8 ++++ .../impl/EventBaseJsonSerializer.java | 2 + .../test/EventDataJsonSerializerTest.java | 3 ++ ...tDataJsonSerializerWithNullValuesTest.java | 2 + ...NullStartAndEndDataJsonSerializerTest.java | 4 ++ .../impl/SensorDataImportServlet.java | 2 - .../server/test/MasterDataImportTest.java | 12 +++--- .../test/RemoveLeaderboardGroupTest.java | 6 +-- .../server/test/SearchServiceTest.java | 8 ++-- .../sailing/server/RacingEventService.java | 9 +++-- .../server/impl/RacingEventServiceImpl.java | 20 +++++----- .../impl/SailingNotificationServiceImpl.java | 12 ++++-- .../CreateEvent.java | 7 +++- .../UpdateEvent.java | 8 ++-- 32 files changed, 165 insertions(+), 85 deletions(-) diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java index 54843dc4675..d6e907ce40c 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/DomainObjectFactoryImpl.java @@ -1033,6 +1033,14 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { logger.severe("Error parsing official website URL "+officialWebSiteURLAsString+" for event "+name+". Ignoring this URL."); } } + String baseURLAsString = (String) eventDBObject.get(FieldNames.EVENT_BASE_URL.name()); + if (baseURLAsString != null) { + try { + result.setBaseURL(new URL(baseURLAsString)); + } catch (MalformedURLException e) { + logger.severe("Error parsing base URL "+baseURLAsString+" for event "+name+". Ignoring this URL."); + } + } BasicDBList images = (BasicDBList) eventDBObject.get(FieldNames.EVENT_IMAGES.name()); if (images != null) { for (Object imageObject : images) { diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java index c29862d9e1a..35146b6ef80 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/FieldNames.java @@ -22,6 +22,7 @@ public enum FieldNames { EVENT_IMAGES, EVENT_VIDEOS, EVENT_OFFICIAL_WEBSITE_URL, + EVENT_BASE_URL, EVENT_SAILORS_INFO_WEBSITE_URL, EVENT_SAILORS_INFO_WEBSITES, EVENT_LOGO_IMAGE_URL, diff --git a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java index b84f20b8426..23eb4b7e61d 100644 --- a/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java +++ b/java/com.sap.sailing.domain.persistence/src/com/sap/sailing/domain/persistence/impl/MongoObjectFactoryImpl.java @@ -550,6 +550,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { eventDBObject.put(FieldNames.EVENT_DESCRIPTION.name(), event.getDescription()); eventDBObject.put(FieldNames.EVENT_ID.name(), event.getId()); eventDBObject.put(FieldNames.EVENT_OFFICIAL_WEBSITE_URL.name(), event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null); + eventDBObject.put(FieldNames.EVENT_BASE_URL.name(), event.getBaseURL() != null ? event.getBaseURL().toString() : null); storeTimePoint(event.getStartDate(), eventDBObject, FieldNames.EVENT_START_DATE); storeTimePoint(event.getEndDate(), eventDBObject, FieldNames.EVENT_END_DATE); eventDBObject.put(FieldNames.EVENT_IS_PUBLIC.name(), event.isPublic()); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java index ad3cd38f7ff..59efc7d8b80 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/EventBase.java @@ -49,6 +49,16 @@ public interface EventBase extends NamedWithID, WithDescription, Renamable, With void setOfficialWebsiteURL(URL officialWebsiteURL); + /** + * @return the URL under which the event's landing page in the {@code sapsailing.com} universe can be reached. This + * could be something like {@code tw2015.sapsailing.com} or {@link 505worlds2012.sapsailing.com} or similar. + * It shall be a URL to which relative paths to pages in the context of this event can be appended, such + * as links to race boards, leaderboards or the regatta overview. + */ + URL getBaseURL(); + + void setBaseURL(URL baseURL); + /** * Returns a mapping of Locales to URLs where the URLs are meant as an external web site containing sailor related * information like protests, official results, etc. diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java index ef8092abecc..84d0b07641d 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/EventBaseImpl.java @@ -38,6 +38,7 @@ public abstract class EventBaseImpl implements EventBase { private TimePoint startDate; private TimePoint endDate; private URL officialWebsiteURL; + private URL baseURL; private CopyOnWriteHashMap sailorsInfoWebsiteURLs; private ConcurrentLinkedQueue images; private ConcurrentLinkedQueue videos; @@ -144,12 +145,22 @@ public abstract class EventBaseImpl implements EventBase { public URL getOfficialWebsiteURL() { return officialWebsiteURL; } - + @Override public void setOfficialWebsiteURL(URL officialWebsiteURL) { this.officialWebsiteURL = officialWebsiteURL; } + @Override + public URL getBaseURL() { + return baseURL; + } + + @Override + public void setBaseURL(URL baseURL) { + this.baseURL = baseURL; + } + @Override public Map getSailorsInfoWebsiteURLs() { return Collections.unmodifiableMap(sailorsInfoWebsiteURLs); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java index 8f326c00669..6ad13ea3c6c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java @@ -39,6 +39,8 @@ public class EventCreateDialog extends EventDialog { endDateBox.ensureDebugId("EndDateTimeBox"); officialWebsiteURLEntryField = createTextBox(null); officialWebsiteURLEntryField.setVisibleLength(50); + baseURLEntryField = createTextBox(null); + baseURLEntryField.setVisibleLength(50); sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(Collections. emptyMap()); isPublicCheckBox = createCheckbox(""); isPublicCheckBox.setValue(false); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index e94731bd756..556a7dd3a10 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -49,6 +49,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap protected CheckBox isPublicCheckBox; protected UUID id; protected TextBox officialWebsiteURLEntryField; + protected TextBox baseURLEntryField; protected Map sailorsInfoWebsiteURLEntryFields = new HashMap<>(); protected CourseAreaListInlineEditorComposite courseAreaNameList; protected StringConstantsListEditorComposite leaderboardGroupList; @@ -176,6 +177,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap result.setName(nameEntryField.getText()); result.setDescription(descriptionEntryField.getText()); result.setOfficialWebsiteURL(officialWebsiteURLEntryField.getText().trim().isEmpty() ? null : officialWebsiteURLEntryField.getText().trim()); + result.setBaseURL(baseURLEntryField.getText().trim().isEmpty() ? null : baseURLEntryField.getText().trim()); for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { TextBox sailorsInfoWebsiteURLEntryField = sailorsInfoWebsiteUrlEntry.getValue(); String sailorsInfoWebsiteURL = sailorsInfoWebsiteURLEntryField.getText().trim(); @@ -205,23 +207,25 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap panel.add(additionalWidget); } Grid formGrid = new Grid(9 + GWTLocaleUtil.getLanguageCountWithDefault(), 2); - formGrid.setWidget(0, 0, new Label(stringMessages.name() + ":")); - formGrid.setWidget(0, 1, nameEntryField); - formGrid.setWidget(1, 0, new Label(stringMessages.description() + ":")); - formGrid.setWidget(1, 1, descriptionEntryField); - formGrid.setWidget(2, 0, new Label(stringMessages.venue() + ":")); - formGrid.setWidget(2, 1, venueEntryField); - formGrid.setWidget(3, 0, new Label(stringMessages.timeZone() + ":")); - formGrid.setWidget(3, 1, new Label(DateAndTimeFormatterUtil.getClientTimeZoneAsGMTString())); - formGrid.setWidget(4, 0, new Label(stringMessages.startDate() + ":")); - formGrid.setWidget(4, 1, startDateBox); - formGrid.setWidget(5, 0, new Label(stringMessages.endDate() + ":")); - formGrid.setWidget(5, 1, endDateBox); - formGrid.setWidget(6, 0, new Label(stringMessages.isPublic() + ":")); - formGrid.setWidget(6, 1, isPublicCheckBox); - formGrid.setWidget(7, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":")); - formGrid.setWidget(7, 1, officialWebsiteURLEntryField); - int rowIndex = 8; + int rowIndex = 0; + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.name() + ":")); + formGrid.setWidget(rowIndex++, 1, nameEntryField); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.description() + ":")); + formGrid.setWidget(rowIndex++, 1, descriptionEntryField); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.venue() + ":")); + formGrid.setWidget(rowIndex++, 1, venueEntryField); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.timeZone() + ":")); + formGrid.setWidget(rowIndex++, 1, new Label(DateAndTimeFormatterUtil.getClientTimeZoneAsGMTString())); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.startDate() + ":")); + formGrid.setWidget(rowIndex++, 1, startDateBox); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.endDate() + ":")); + formGrid.setWidget(rowIndex++, 1, endDateBox); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.isPublic() + ":")); + formGrid.setWidget(rowIndex++, 1, isPublicCheckBox); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventOfficialWebsiteURL() + ":")); + formGrid.setWidget(rowIndex++, 1, officialWebsiteURLEntryField); + formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventBaseURL() + ":")); + formGrid.setWidget(rowIndex++, 1, baseURLEntryField); for (Map.Entry sailorsInfoWebsiteUrlEntry : sailorsInfoWebsiteURLEntryFields.entrySet()) { String suffix = " ["+ (sailorsInfoWebsiteUrlEntry.getKey() == null ? stringMessages.defaultLocale() + "*" : sailorsInfoWebsiteUrlEntry.getKey()) + "]"; formGrid.setWidget(rowIndex, 0, new Label(stringMessages.eventSailorsInfoWebsiteURL() + suffix + ":")); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index 60989b5a63f..1374838de43 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -30,6 +30,8 @@ public class EventEditDialog extends EventDialog { id = event.id; officialWebsiteURLEntryField = createTextBox(event.getOfficialWebsiteURL()); officialWebsiteURLEntryField.setVisibleLength(50); + baseURLEntryField = createTextBox(event.getOfficialWebsiteURL()); + baseURLEntryField.setVisibleLength(50); sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(event.getSailorsInfoWebsiteURLs()); courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas())); List leaderboardGroupNames = new ArrayList<>(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java index ee0c227e2b0..59d99183862 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventListComposite.java @@ -596,9 +596,9 @@ public class EventListComposite extends Composite implements EventsRefresher, Le updatedEvent.startDate, updatedEvent.endDate, updatedEvent.venue, updatedEvent.isPublic, updatedEventLeaderboardGroupIds, updatedEvent.getOfficialWebsiteURL(), - updatedEvent.getSailorsInfoWebsiteURLs(), - updatedEvent.getImages(), updatedEvent.getVideos(), - new AsyncCallback() { + updatedEvent.getBaseURL(), + updatedEvent.getSailorsInfoWebsiteURLs(), updatedEvent.getImages(), + updatedEvent.getVideos(), new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError("Error trying to update sailing event" + oldEvent.getName() + ": " + t.getMessage()); @@ -670,8 +670,8 @@ public class EventListComposite extends Composite implements EventsRefresher, Le courseAreaNames.add(courseAreaDTO.getName()); } sailingService.createEvent(newEvent.getName(), newEvent.getDescription(), newEvent.startDate, newEvent.endDate, - newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(), newEvent.getSailorsInfoWebsiteURLs(), - newEvent.getImages(), newEvent.getVideos(), newEvent.getLeaderboardGroupIds(), new AsyncCallback() { + newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(), newEvent.getBaseURL(), + newEvent.getSailorsInfoWebsiteURLs(), newEvent.getImages(), newEvent.getVideos(), newEvent.getLeaderboardGroupIds(), new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError("Error trying to create new event " + newEvent.getName() + ": " + t.getMessage()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java index 573870fdbd0..f6807bb9ab4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/StructureImportManagementPanel.java @@ -265,9 +265,9 @@ public class StructureImportManagementPanel extends SimplePanel implements Regat courseAreaNames.add(courseAreaDTO.getName()); } sailingService.createEvent(newEvent.getName(), newEvent.getDescription(), newEvent.startDate, newEvent.endDate, - newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(), newEvent.getSailorsInfoWebsiteURLs(), - newEvent.getImages(), newEvent.getVideos(), - newEvent.getLeaderboardGroupIds(), new AsyncCallback() { + newEvent.venue.getName(), newEvent.isPublic, courseAreaNames, newEvent.getOfficialWebsiteURL(), newEvent.getBaseURL(), + newEvent.getSailorsInfoWebsiteURLs(), newEvent.getImages(), + newEvent.getVideos(), newEvent.getLeaderboardGroupIds(), new AsyncCallback() { @Override public void onFailure(Throwable t) { errorReporter.reportError(stringMessages.errorTryingToCreateNewEvent(newEvent.getName(), t.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 aec9df51e7e..addce312607 100755 --- 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 @@ -314,13 +314,13 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS Pair resolveImageDimensions(String imageUrlAsString) throws Exception; EventDTO updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, - VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURL, Map sailorsInfoWebsiteURLsByLocaleName, - Iterable images, Iterable videos) throws Exception; + VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURL, String baseURLAsString, + Map sailorsInfoWebsiteURLsByLocaleName, Iterable images, Iterable videos) throws Exception; EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, boolean isPublic, List courseAreaNames, String officialWebsiteURL, - Map sailorsInfoWebsiteURLsByLocaleName, Iterable images, - Iterable videos, Iterable leaderboardGroupIds) throws Exception; + String baseURLAsString, Map sailorsInfoWebsiteURLsByLocaleName, + Iterable images, Iterable videos, Iterable leaderboardGroupIds) throws Exception; void removeEvent(UUID eventId); 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 32e4da5e929..0da1f54f312 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 @@ -407,13 +407,14 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan void removeEvents(Collection eventIds, AsyncCallback asyncCallback); void createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, - boolean isPublic, List courseAreaNames, String officialWebsiteURL, Map sailorsInfoWebsiteURLsByLocaleName, - Iterable images, Iterable videos, Iterable leaderboardGroupIDs, AsyncCallback callback); + boolean isPublic, List courseAreaNames, String officialWebsiteURL, String baseURL, + Map sailorsInfoWebsiteURLsByLocaleName, Iterable images, + Iterable videos, Iterable leaderboardGroupIDs, AsyncCallback callback); void updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURL, - Map sailorsInfoWebsiteURLsByLocaleName, Iterable images, Iterable videos, - AsyncCallback callback); + String baseURL, Map sailorsInfoWebsiteURLsByLocaleName, Iterable images, + Iterable videos, AsyncCallback callback); void resolveImageDimensions(String imageUrlAsString, AsyncCallback> callback); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 31f3e439295..21f6717d9f9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1131,6 +1131,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String pleaseSelectAScoringResult(); String timeZone(); String eventOfficialWebsiteURL(); + String eventBaseURL(); String eventSailorsInfoWebsiteURL(); String eventOverviewURL(); String eventLogoImageURL(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 0f1cbd99bbb..fa5d98d3577 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1104,6 +1104,7 @@ advancePassId=Advance Pass ID pleaseSelectAScoringResult=Please select a scoring result... timeZone=Time zone eventOfficialWebsiteURL=Official Website URL +eventBaseURL=Event''s Base URL (http://something.sapsailing.com) eventSailorsInfoWebsiteURL=Sailors Info Website URL eventOverviewURL=Event Overview URL eventLogoImageURL=Logo Image URL diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 1bd1b9375b9..2bd459a9988 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1094,6 +1094,7 @@ advancePassId=Pass ID erhöhen pleaseSelectAScoringResult=Bitte ein Ergebnis auswählen... timeZone=Zeitzone eventOfficialWebsiteURL=URL der offiziellen Veranstaltungswebseite +eventBaseURL=Stamm-URL der Veranstaltung (http://something.sapsailing.com) eventSailorsInfoWebsiteURL=URL zur Webseite mit Seglerinfos eventOverviewURL=URL der Veranstaltungsübersicht eventLogoImageURL=URL des Veranstaltungslogos 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 9ab13fa7a9c..2b8f0c3a85f 100644 --- 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 @@ -3397,11 +3397,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public List getEvents() throws MalformedURLException { - String requestBaseURL = getRequestBaseURL().toString(); List result = new ArrayList(); for (Event event : getService().getAllEvents()) { EventDTO eventDTO = convertToEventDTO(event, false); - eventDTO.setBaseURL(requestBaseURL); + eventDTO.setBaseURL(getEventBaseURLFromEventOrRequest(event)); eventDTO.setIsOnRemoteServer(false); result.add(eventDTO); } @@ -3421,11 +3420,11 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S final com.sap.sse.common.Util.Pair, Exception> eventsOrException = serverRefAndEventsOrException.getValue(); final RemoteSailingServerReference serverRef = serverRefAndEventsOrException.getKey(); final Iterable remoteEvents = eventsOrException.getA(); - String baseURL = getBaseURL(serverRef.getURL()).toString(); + String baseURLFromServerReference = getBaseURL(serverRef.getURL()).toString(); if (remoteEvents != null) { for (EventBase remoteEvent : remoteEvents) { EventBaseDTO remoteEventDTO = convertToEventDTO(remoteEvent); - remoteEventDTO.setBaseURL(baseURL); + remoteEventDTO.setBaseURL(remoteEvent.getBaseURL() == null ? baseURLFromServerReference : remoteEvent.getBaseURL().toString()); remoteEventDTO.setIsOnRemoteServer(true); result.add(remoteEventDTO); } @@ -3480,36 +3479,38 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public EventDTO updateEvent(UUID eventId, String eventName, String eventDescription, Date startDate, Date endDate, - VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURLString, Map sailorsInfoWebsiteURLsByLocaleName, - Iterable images, Iterable videos) throws MalformedURLException { + VenueDTO venue, boolean isPublic, Iterable leaderboardGroupIds, String officialWebsiteURLString, String baseURLAsString, + Map sailorsInfoWebsiteURLsByLocaleName, Iterable images, Iterable videos) throws MalformedURLException { TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null; URL officialWebsiteURL = officialWebsiteURLString != null ? new URL(officialWebsiteURLString) : null; + URL baseURL = baseURLAsString != null ? new URL(baseURLAsString) : null; Map sailorsInfoWebsiteURLs = convertToLocalesAndUrls(sailorsInfoWebsiteURLsByLocaleName); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( new UpdateEvent(eventId, eventName, eventDescription, startTimePoint, endTimePoint, venue.getName(), - isPublic, leaderboardGroupIds, officialWebsiteURL, sailorsInfoWebsiteURLs, eventImages, eventVideos)); + isPublic, leaderboardGroupIds, officialWebsiteURL, baseURL, sailorsInfoWebsiteURLs, eventImages, eventVideos)); return getEventById(eventId, false); } @Override public EventDTO createEvent(String eventName, String eventDescription, Date startDate, Date endDate, String venue, - boolean isPublic, List courseAreaNames, String officialWebsiteURLAsString, Map sailorsInfoWebsiteURLsByLocaleName, - Iterable images, Iterable videos, Iterable leaderboardGroupIds) + boolean isPublic, List courseAreaNames, String officialWebsiteURLAsString, String baseURLAsString, + Map sailorsInfoWebsiteURLsByLocaleName, Iterable images, Iterable videos, Iterable leaderboardGroupIds) throws MalformedURLException { UUID eventUuid = UUID.randomUUID(); TimePoint startTimePoint = startDate != null ? new MillisecondsTimePoint(startDate) : null; TimePoint endTimePoint = endDate != null ? new MillisecondsTimePoint(endDate) : null; URL officialWebsiteURL = officialWebsiteURLAsString != null ? new URL(officialWebsiteURLAsString) : null; + URL baseURL = baseURLAsString != null ? new URL(baseURLAsString) : null; Map sailorsInfoWebsiteURLs = convertToLocalesAndUrls(sailorsInfoWebsiteURLsByLocaleName); List eventImages = convertToImages(images); List eventVideos = convertToVideos(videos); getService().apply( new CreateEvent(eventName, eventDescription, startTimePoint, endTimePoint, venue, isPublic, eventUuid, - officialWebsiteURL, sailorsInfoWebsiteURLs, eventImages, eventVideos, leaderboardGroupIds)); + officialWebsiteURL, baseURL, sailorsInfoWebsiteURLs, eventImages, eventVideos, leaderboardGroupIds)); createCourseAreas(eventUuid, courseAreaNames.toArray(new String[courseAreaNames.size()])); return getEventById(eventUuid, false); } @@ -3560,16 +3561,19 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S @Override public EventDTO getEventById(UUID id, boolean withStatisticalData) throws MalformedURLException { EventDTO result = null; - String requestBaseURL = getRequestBaseURL().toString(); Event event = getService().getEvent(id); if (event != null) { result = convertToEventDTO(event, withStatisticalData); - result.setBaseURL(requestBaseURL); + result.setBaseURL(getEventBaseURLFromEventOrRequest(event)); result.setIsOnRemoteServer(false); } return result; } + private String getEventBaseURLFromEventOrRequest(Event event) throws MalformedURLException { + return event.getBaseURL() == null ? getRequestBaseURL().toString() : event.getBaseURL().toString(); + } + private EventBaseDTO convertToEventDTO(EventBase event) { final EventBaseDTO eventDTO; if (event == null) { @@ -3602,6 +3606,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S eventDTO.id = (UUID) event.getId(); eventDTO.setDescription(event.getDescription()); eventDTO.setOfficialWebsiteURL(event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null); + eventDTO.setBaseURL(event.getBaseURL() != null ? event.getBaseURL().toString() : null); for(Map.Entry sailorsInfoWebsiteEntry : event.getSailorsInfoWebsiteURLs().entrySet()) { eventDTO.setSailorsInfoWebsiteURL(sailorsInfoWebsiteEntry.getKey() == null ? null : sailorsInfoWebsiteEntry .getKey().toLanguageTag(), sailorsInfoWebsiteEntry.getValue().toExternalForm()); @@ -4363,7 +4368,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } updateEvent(newEvent.id, newEvent.getName(), description, newEvent.startDate, newEvent.endDate, newEvent.venue, newEvent.isPublic, eventLeaderboardGroupUUIDs, newEvent.getOfficialWebsiteURL(), - newEvent.getSailorsInfoWebsiteURLs(), newEvent.getImages(), newEvent.getVideos()); + newEvent.getBaseURL(), newEvent.getSailorsInfoWebsiteURLs(), newEvent.getImages(), newEvent.getVideos()); } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java index 9595acc29ea..9daa8e7a97d 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/EventBaseDTO.java @@ -100,7 +100,7 @@ public class EventBaseDTO extends NamedDTO implements IsSerializable { public void setOfficialWebsiteURL(String officialWebsiteURL) { this.officialWebsiteURL = officialWebsiteURL; } - + public Map getSailorsInfoWebsiteURLs() { return sailorsInfoWebsiteURLs; } diff --git a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java index 8bde462494d..d791f91b93e 100755 --- a/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java +++ b/java/com.sap.sailing.mongodb.test/src/com/sap/sailing/mongodb/test/TestStoringAndLoadingEventsAndRegattas.java @@ -132,6 +132,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest final String venueName = "Venue Name"; final String[] courseAreaNames = new String[] { "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrott" }; final URL officialWebsiteURL = new URL("http://official.website.com"); + final URL baseURL = new URL("http://base.url.com"); final URL sailorsInfoWebsiteURL = new URL("http://sailorsinfo.website.com"); final URL sailorsInfoWebsiteURLDE = new URL("http://sailorsinfo-de.website.com"); final Venue venue = new VenueImpl(venueName); @@ -148,6 +149,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest event.addLeaderboardGroup(lg2); event.setDescription(eventDescription); event.setOfficialWebsiteURL(officialWebsiteURL); + event.setBaseURL(baseURL); event.setSailorsInfoWebsiteURL(null, sailorsInfoWebsiteURL); event.setSailorsInfoWebsiteURL(Locale.GERMAN, sailorsInfoWebsiteURLDE); mof.storeEvent(event); @@ -174,6 +176,7 @@ public class TestStoringAndLoadingEventsAndRegattas extends AbstractMongoDBTest assertEquals(eventName, loadedEvent.getName()); assertEquals(eventDescription, loadedEvent.getDescription()); assertEquals(event.getOfficialWebsiteURL(), loadedEvent.getOfficialWebsiteURL()); + assertEquals(event.getBaseURL(), loadedEvent.getBaseURL()); assertEquals(sailorsInfoWebsiteURL, loadedEvent.getSailorsInfoWebsiteURL(null)); assertEquals(sailorsInfoWebsiteURLDE, loadedEvent.getSailorsInfoWebsiteURL(Locale.GERMAN)); assertEquals(2, loadedEvent.getSailorsInfoWebsiteURLs().size()); diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java index 6a58129445d..d27c9900f5b 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/impl/EventBaseJsonDeserializer.java @@ -39,6 +39,7 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { String name = (String) eventJson.get(EventBaseJsonSerializer.FIELD_NAME); String description = (String) eventJson.get(EventBaseJsonSerializer.FIELD_DESCRIPTION); String officialWebsiteURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_OFFICIAL_WEBSITE_URL); + String baseURLAsString = (String) eventJson.get(EventBaseJsonSerializer.FIELD_BASE_URL); Number startDate = (Number) eventJson.get(EventBaseJsonSerializer.FIELD_START_DATE); Number endDate = (Number) eventJson.get(EventBaseJsonSerializer.FIELD_END_DATE); final Venue venue; @@ -65,6 +66,13 @@ public class EventBaseJsonDeserializer implements JsonDeserializer { throw new JsonDeserializationException("Error deserializing official website URL for event "+name, e); } } + if (baseURLAsString != null) { + try { + result.setBaseURL(new URL(baseURLAsString)); + } catch (MalformedURLException e) { + throw new JsonDeserializationException("Error deserializing base URL for event "+name, e); + } + } JSONArray imagesJson = (JSONArray) eventJson.get(EventBaseJsonSerializer.FIELD_IMAGES); if (imagesJson != null) { for (Object imageJson : imagesJson) { diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java index 1f24f0e7775..63a8b90575a 100644 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/serialization/impl/EventBaseJsonSerializer.java @@ -27,6 +27,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { public static final String FIELD_IMAGE_HEIGHT = "imageHeight"; public static final String FIELD_VIDEO_URL = "videoURL"; public static final String FIELD_OFFICIAL_WEBSITE_URL = "officialWebsiteURL"; + public static final String FIELD_BASE_URL = "baseURL"; public static final String FIELD_SAILORS_INFO_WEBSITE_URLS = "sailorsInfoWebsiteURLs"; public static final String FIELDS_LEADERBOARD_GROUPS = "leaderboardGroups"; @@ -63,6 +64,7 @@ public class EventBaseJsonSerializer implements JsonSerializer { result.put(FIELD_NAME, event.getName()); result.put(FIELD_DESCRIPTION, event.getDescription()); result.put(FIELD_OFFICIAL_WEBSITE_URL, event.getOfficialWebsiteURL() != null ? event.getOfficialWebsiteURL().toString() : null); + result.put(FIELD_BASE_URL, event.getBaseURL() != null ? event.getBaseURL().toString() : null); result.put(FIELD_START_DATE, event.getStartDate() != null ? event.getStartDate().asMillis() : null); result.put(FIELD_END_DATE, event.getStartDate() != null ? event.getEndDate().asMillis() : null); result.put(FIELD_VENUE, venueSerializer.serialize(event.getVenue())); diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java index 40101a39a72..246f3bd65f4 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerTest.java @@ -48,6 +48,7 @@ public class EventDataJsonSerializerTest { protected final TimePoint expectedEndDate = new MillisecondsTimePoint(new Date()); protected final Venue expectedVenue = new VenueImpl("Expected Venue"); protected final URL expectedOfficialWebsiteURL; + protected final URL expectedBaseURL; protected final Map expectedSailorsInfoWebsiteURLs; protected final URL expectedLogoImageURL; protected final ImageDescriptor expectedLogoImageDescriptor; @@ -60,6 +61,7 @@ public class EventDataJsonSerializerTest { public EventDataJsonSerializerTest() throws MalformedURLException { expectedOfficialWebsiteURL = new URL("http://official.website.com"); + expectedBaseURL = new URL("http://our.own.com"); expectedLogoImageURL = new URL("http://official.logo.com/logo.png"); expectedLogoImageDescriptor = new ImageDescriptorImpl(expectedLogoImageURL, MillisecondsTimePoint.now()); expectedSailorsInfoWebsiteURLs = new HashMap<>(); @@ -76,6 +78,7 @@ public class EventDataJsonSerializerTest { when(event.getName()).thenReturn(expectedName); when(event.getDescription()).thenReturn(expectedDescription); when(event.getOfficialWebsiteURL()).thenReturn(expectedOfficialWebsiteURL); + when(event.getBaseURL()).thenReturn(expectedBaseURL); when(event.getSailorsInfoWebsiteURLs()).thenReturn(expectedSailorsInfoWebsiteURLs); when(event.getSailorsInfoWebsiteURL(null)).thenReturn(expectedSailorsInfoWebsiteURLs.get(null)); when(event.getStartDate()).thenReturn(expectedStartDate); diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java index ed382321b68..c69749bfbd7 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventDataJsonSerializerWithNullValuesTest.java @@ -43,6 +43,7 @@ public class EventDataJsonSerializerWithNullValuesTest { protected final TimePoint expectedEndDate = new MillisecondsTimePoint(new Date()); protected final Venue expectedVenue = new VenueImpl("Expected Venue"); protected final URL expectedOfficialWebsiteURL = null; + protected final URL expectedBaseURL = null; protected final LeaderboardGroup expectedLeaderbaordGroup = mock(LeaderboardGroup.class); protected JsonSerializer venueSerializer; @@ -59,6 +60,7 @@ public class EventDataJsonSerializerWithNullValuesTest { when(event.getName()).thenReturn(expectedName); when(event.getDescription()).thenReturn(expectedDescription); when(event.getOfficialWebsiteURL()).thenReturn(expectedOfficialWebsiteURL); + when(event.getBaseURL()).thenReturn(expectedBaseURL); when(event.getStartDate()).thenReturn(expectedStartDate); when(event.getEndDate()).thenReturn(expectedEndDate); when(event.getVenue()).thenReturn(expectedVenue); diff --git a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java index 0bb26795cf6..b66d29f065b 100755 --- a/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java +++ b/java/com.sap.sailing.server.gateway.serialization.test/src/com/sap/sailing/server/gateway/serialization/test/EventWithNullStartAndEndDataJsonSerializerTest.java @@ -46,6 +46,7 @@ public class EventWithNullStartAndEndDataJsonSerializerTest { protected final TimePoint expectedEndDate = null; protected final Venue expectedVenue = new VenueImpl("Expected Venue"); protected final URL expectedOfficialWebsiteURL; + protected final URL expectedBaseURL; protected final URL expectedLogoImageURL; protected final ImageDescriptor expectedLogoImageDescriptor; protected final LeaderboardGroupBase expectedLeaderboardGroup = mock(LeaderboardGroupBase.class); @@ -58,6 +59,7 @@ public class EventWithNullStartAndEndDataJsonSerializerTest { public EventWithNullStartAndEndDataJsonSerializerTest() throws MalformedURLException { expectedOfficialWebsiteURL = new URL("http://official.website.com"); + expectedBaseURL = new URL("http://our.veryown.com"); expectedLogoImageURL = new URL("http://official.logo.com/logo.png"); expectedLogoImageDescriptor = new ImageDescriptorImpl(expectedLogoImageURL, MillisecondsTimePoint.now()); } @@ -74,6 +76,7 @@ public class EventWithNullStartAndEndDataJsonSerializerTest { when(event.getName()).thenReturn(expectedName); when(event.getDescription()).thenReturn(expectedDescription); when(event.getOfficialWebsiteURL()).thenReturn(expectedOfficialWebsiteURL); + when(event.getBaseURL()).thenReturn(expectedBaseURL); when(event.getStartDate()).thenReturn(expectedStartDate); when(event.getEndDate()).thenReturn(expectedEndDate); when(event.getVenue()).thenReturn(expectedVenue); @@ -104,6 +107,7 @@ public class EventWithNullStartAndEndDataJsonSerializerTest { assertEquals(expectedName, deserializedEvent.getName()); assertEquals(expectedDescription, deserializedEvent.getDescription()); assertEquals(expectedOfficialWebsiteURL, deserializedEvent.getOfficialWebsiteURL()); + assertEquals(expectedBaseURL, deserializedEvent.getBaseURL()); assertEquals(1, Util.size(deserializedEvent.getImages())); assertEquals(expectedLogoImageURL, deserializedEvent.getImages().iterator().next().getURL()); LeaderboardGroupBase deserializedLg = deserializedEvent.getLeaderboardGroups().iterator().next(); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java index fb3f944344f..5d3f8db5a36 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/trackfiles/impl/SensorDataImportServlet.java @@ -52,8 +52,6 @@ public class SensorDataImportServlet extends AbstractFileUploadServlet { * Searches the requested importer in the importers provided by the OSGi registry and imports the priovided sensor * data file. * - * @param files - * @return * @throws IOException */ private Iterable importFiles(Iterable> files) diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java index 3993c0fc5de..915604c2c40 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/MasterDataImportTest.java @@ -1369,9 +1369,9 @@ public class MasterDataImportTest { Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */null, new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), - /* officialWebsiteURL */null, /* sailorsInfoWebsiteURL */null, - /* images */Collections. emptyList(), /* videos */ - Collections. emptyList()); + /* officialWebsiteURL */null, /*baseURL*/null, + /* sailorsInfoWebsiteURL */null, /* videos */ + /* images */Collections. emptyList(), Collections. emptyList()); CourseArea defaultCourseArea = sourceService.addCourseAreas(event.getId(), new String[] { "ECHO" }, new UUID[] { UUID.randomUUID() })[0]; @@ -1437,9 +1437,9 @@ public class MasterDataImportTest { Event event = sourceService.createEventWithoutReplication("Test Event", /* eventDescription */null, new MillisecondsTimePoint(0), new MillisecondsTimePoint(10), "testvenue", false, UUID.randomUUID(), - /* officialWebsiteURL */null, /* sailorsInfoWebsiteURL */null, - /* images */Collections. emptyList(), /* videos */ - Collections. emptyList()); + /* officialWebsiteURL */null, /*baseURL*/null, + /* sailorsInfoWebsiteURL */null, /* videos */ + /* images */Collections. emptyList(), Collections. emptyList()); CourseArea defaultCourseArea = sourceService.addCourseAreas(event.getId(), new String[] { "ECHO" }, new UUID[] { UUID.randomUUID() })[0]; diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java index 482d86be248..16ecd2cc100 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/RemoveLeaderboardGroupTest.java @@ -68,9 +68,9 @@ public class RemoveLeaderboardGroupTest { cal.set(2014, 5, 8, 16, 00); final TimePoint pfingstbuschEndDate = new MillisecondsTimePoint(cal.getTime()); pfingstbusch = server.apply(new CreateEvent("Pfingstbusch", /* eventDescription */ null, pfingstbuschStartDate, pfingstbuschEndDate, - "Kiel", /* isPublic */ true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /* sailorsInfoWebsiteURLAsString */ null, - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* leaderboardGroupIds */ Collections. emptyList())); + "Kiel", /* isPublic */ true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /*baseURL*/null, + /* sailorsInfoWebsiteURLAsString */ null, /* images */Collections. emptyList(), + /* videos */Collections. emptyList(), /* leaderboardGroupIds */ Collections. emptyList())); final LeaderboardGroup pfingstbuschLeaderboardGroup = server.apply(new CreateLeaderboardGroup("Pfingstbusch", "Pfingstbusch", /* displayName */ null, /* displayGroupsInReverseOrder */ false, /* leaderboard names */ Collections.emptyList(), new int[0], /* overallLeaderboardScoringSchemeType */ ScoringSchemeType.LOW_POINT)); diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java index c442be5241e..a0d055f88e3 100755 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/SearchServiceTest.java @@ -126,8 +126,8 @@ public class SearchServiceTest { cal.set(2014, 5, 8, 16, 00); final TimePoint pfingstbuschEndDate = new MillisecondsTimePoint(cal.getTime()); pfingstbusch = server.apply(new CreateEvent("Pfingsbusch", /* eventDescription */ null, pfingstbuschStartDate, pfingstbuschEndDate, - "Kiel", /* isPublic */ true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /* sailorsInfoWebsiteURLAsString */ null, - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* leaderboardGroupIds */ Collections. emptyList())); + "Kiel", /* isPublic */ true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /*baseURL*/null, + /* sailorsInfoWebsiteURLAsString */ null, /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* leaderboardGroupIds */ Collections. emptyList())); kiel = pfingstbusch.getVenue(); final CourseAreaImpl kielAlpha = new CourseAreaImpl("Alpha", UUID.randomUUID()); kiel.addCourseArea(kielAlpha); @@ -164,8 +164,8 @@ public class SearchServiceTest { cal.set(2014, 5, 8, 18, 00); final TimePoint aalEndDate = new MillisecondsTimePoint(cal.getTime()); aalEvent = server.apply(new CreateEvent("Aalregatta", /* eventDescription */ null, aalStartDate, aalEndDate, - "Flensburg", /* isPublic */ true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /*sailorsInfoWebsiteURLAsString */ null, - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* leaderboardGroupIds */ Collections. emptyList())); + "Flensburg", /* isPublic */ true, UUID.randomUUID(), /* officialWebsiteURLAsString */ null, /*baseURL*/null, + /*sailorsInfoWebsiteURLAsString */ null, /* images */Collections. emptyList(), /* videos */Collections. emptyList(), /* leaderboardGroupIds */ Collections. emptyList())); flensburg = aalEvent.getVenue(); final CourseAreaImpl flensburgStandard = new CourseAreaImpl("Standard", UUID.randomUUID()); flensburg.addCourseArea(flensburgStandard); 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 d28ea8c2a6c..f300a5348d3 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 @@ -369,11 +369,12 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch * The name of the venue of the event * @param isPublic * Indicates whether the event is public accessible via the publication URL or not + * @param baseURL TODO * @return The new event */ void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, - String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, Map sailorsInfoWebsiteURLs, - Iterable images, Iterable videos); + String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, URL baseURL, + Map sailorsInfoWebsiteURLs, Iterable images, Iterable videos); /** * Renames a sailing event. If a sailing event by the name oldName does not exist in {@link #getEvents()}, @@ -468,8 +469,8 @@ public interface RacingEventService extends TrackedRegattaRegistry, RegattaFetch ConcurrentHashMap getPersistentRegattasForRaceIDs(); Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, URL officialWebsiteURL, Map sailorsInfoWebsiteURLs, Iterable images, - Iterable videos); + boolean isPublic, UUID id, URL officialWebsiteURL, URL baseURL, Map sailorsInfoWebsiteURLs, + Iterable images, Iterable videos); void setRegattaForRace(Regatta regatta, String raceIdAsString); 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 591d303a811..5775aba10a2 100644 --- 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 @@ -2672,12 +2672,12 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public Event addEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, boolean isPublic, UUID id) { Event result = createEventWithoutReplication(eventName, eventDescription, startDate, endDate, venue, isPublic, - id, /* officialWebsiteURL */null, /* sailorsInfoWebsiteURLAsString */null, - /* images */Collections. emptyList(), /* videos */Collections. emptyList()); + id, /* officialWebsiteURL */null, /* baseURL */null, + /* sailorsInfoWebsiteURLAsString */null, /* images */Collections. emptyList(), /* videos */Collections. emptyList()); replicate(new CreateEvent(eventName, eventDescription, startDate, endDate, venue, isPublic, id, - /* officialWebsiteURLAsString */null, /* sailorsInfoWebsiteURLAsString */null, - /* images */Collections. emptyList(), /* videos */Collections. emptyList(), - /* leaderboardGroupIds */ Collections. emptyList())); + /* officialWebsiteURLAsString */null, /*baseURL*/null, + /* sailorsInfoWebsiteURLAsString */null, /* images */Collections. emptyList(), + /* videos */Collections. emptyList(), /* leaderboardGroupIds */ Collections. emptyList())); return result; } @@ -2688,12 +2688,13 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes @Override public Event createEventWithoutReplication(String eventName, String eventDescription, TimePoint startDate, - TimePoint endDate, String venue, boolean isPublic, UUID id, URL officialWebsiteURL, Map sailorsInfoWebsiteURLs, - Iterable images, Iterable videos) { + TimePoint endDate, String venue, boolean isPublic, UUID id, URL officialWebsiteURL, URL baseURL, + Map sailorsInfoWebsiteURLs, Iterable images, Iterable videos) { Event result = new EventImpl(eventName, startDate, endDate, venue, isPublic, id); addEvent(result); result.setDescription(eventDescription); result.setOfficialWebsiteURL(officialWebsiteURL); + result.setBaseURL(baseURL); result.setSailorsInfoWebsiteURLs(sailorsInfoWebsiteURLs); result.setImages(images); result.setVideos(videos); @@ -2711,8 +2712,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes @Override public void updateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, - String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, Map sailorsInfoWebsiteURLs, - Iterable images, Iterable videos) { + String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, URL baseURL, + Map sailorsInfoWebsiteURLs, Iterable images, Iterable videos) { final Event event = eventsById.get(id); if (event == null) { throw new IllegalArgumentException("Sailing event with ID " + id + " does not exist."); @@ -2735,6 +2736,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } event.setLeaderboardGroups(leaderboardGroups); event.setOfficialWebsiteURL(officialWebsiteURL); + event.setBaseURL(baseURL); event.setSailorsInfoWebsiteURLs(sailorsInfoWebsiteURLs); event.setImages(images); event.setVideos(videos); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 38186517bca..3644e50a968 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -1,5 +1,6 @@ package com.sap.sailing.server.notification.impl; +import java.net.URL; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Locale; @@ -171,8 +172,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific private String createRaceBoardLink(TrackedRace trackedRace, Leaderboard leaderboard, Event event, LeaderboardGroup leaderboardGroup) { RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); - // TODO where to get the base URL? - String link = "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() + String link = getBaseURL(event).toString() + "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" + raceIdentifier.getRegattaName(); @@ -183,13 +183,17 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific return createHomeRegattaLink("races", leaderboard, event); } + private URL getBaseURL(final Event event) { + // TODO where to get the base URL? + return event.getBaseURL(); + } + private String createHomeLeaderboardLink(Leaderboard leaderboard, Event event) { return createHomeRegattaLink("leaderboard", leaderboard, event); } private String createHomeRegattaLink(String tab, Leaderboard leaderboard, Event event) { - // TODO where to get the base URL? - String link = "/gwt/Home.html#/regatta/" + tab + "/:eventId=" + event.getId() + "®attaId=" + String link = getBaseURL(event).toString() + "/gwt/Home.html#/regatta/" + tab + "/:eventId=" + event.getId() + "®attaId=" + leaderboard.getName(); return link; } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java index 0b89f354a42..9d893ab042d 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/CreateEvent.java @@ -33,11 +33,13 @@ public class CreateEvent extends AbstractEventOperation { private final Iterable images; private final Iterable videos; private final URL officialWebsiteURL; + private final URL baseURL; private final Map sailorsInfoWebsiteURLs; private final Iterable leaderboardGroupIds; public CreateEvent(String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, String venue, - boolean isPublic, UUID id, URL officialWebsiteURL, Map sailorsInfoWebsiteURLs, Iterable images, Iterable videos, Iterable leaderboardGroupIds) { + boolean isPublic, UUID id, URL officialWebsiteURL, URL baseURL, Map sailorsInfoWebsiteURLs, + Iterable images, Iterable videos, Iterable leaderboardGroupIds) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -46,6 +48,7 @@ public class CreateEvent extends AbstractEventOperation { this.venue = venue; this.isPublic = isPublic; this.officialWebsiteURL = officialWebsiteURL; + this.baseURL = baseURL; this.sailorsInfoWebsiteURLs = sailorsInfoWebsiteURLs; this.images = images; this.videos = videos; @@ -71,7 +74,7 @@ public class CreateEvent extends AbstractEventOperation { @Override public Event internalApplyTo(RacingEventService toState) { final Event result = toState.createEventWithoutReplication(getEventName(), eventDescription, startDate, endDate, venue, isPublic, - getId(), officialWebsiteURL, sailorsInfoWebsiteURLs, images, videos); + getId(), officialWebsiteURL, baseURL, sailorsInfoWebsiteURLs, images, videos); List lgl = new ArrayList<>(); for (final UUID lgid : leaderboardGroupIds) { final LeaderboardGroup lg = toState.getLeaderboardGroupByID(lgid); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java index bd22cb972f2..4cabbe3c4a4 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/operationaltransformation/UpdateEvent.java @@ -21,13 +21,14 @@ public class UpdateEvent extends AbstractEventOperation { private final String eventName; private final String eventDescription; private final URL officialWebsiteURL; + private final URL baseURL; private final Map sailorsInfoWebsiteURLs; private final Iterable images; private final Iterable videos; public UpdateEvent(UUID id, String eventName, String eventDescription, TimePoint startDate, TimePoint endDate, - String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, Map sailorsInfoWebsiteURLs, - Iterable images, Iterable videos) { + String venueName, boolean isPublic, Iterable leaderboardGroupIds, URL officialWebsiteURL, URL baseURL, + Map sailorsInfoWebsiteURLs, Iterable images, Iterable videos) { super(id); this.eventName = eventName; this.eventDescription = eventDescription; @@ -37,6 +38,7 @@ public class UpdateEvent extends AbstractEventOperation { this.isPublic = isPublic; this.leaderboardGroupIds = leaderboardGroupIds; this.officialWebsiteURL = officialWebsiteURL; + this.baseURL = baseURL; this.sailorsInfoWebsiteURLs = sailorsInfoWebsiteURLs; this.images = images; this.videos = videos; @@ -57,7 +59,7 @@ public class UpdateEvent extends AbstractEventOperation { @Override public Void internalApplyTo(RacingEventService toState) { toState.updateEvent(getId(), eventName, eventDescription, startDate, endDate, venueName, isPublic, - leaderboardGroupIds, officialWebsiteURL, sailorsInfoWebsiteURLs, images, videos); + leaderboardGroupIds, officialWebsiteURL, baseURL, sailorsInfoWebsiteURLs, images, videos); return null; } } From e9a3cbbbcedaa838465cdd3ca5a235324b4be746 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 14:18:38 +0200 Subject: [PATCH 207/259] fixed handling of event base URL in UI Change-Id: Iec853e4983ac27209fd8f91a7b25df7d7962e7e5 --- .../sailing/gwt/ui/adminconsole/EventDetailsComposite.java | 6 +++++- .../com/sap/sailing/gwt/ui/adminconsole/EventDialog.java | 2 +- .../sap/sailing/gwt/ui/adminconsole/EventEditDialog.java | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java index b110b287b99..44994a011c6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDetailsComposite.java @@ -33,6 +33,7 @@ public class EventDetailsComposite extends Composite { private final Label endDate; private final Label isPublic; private final Anchor officialWebsiteURL; + private final Anchor baseURL; private final SimpleAnchorListComposite sailorsInfoWebsiteURLList; private final Anchor eventOverviewURL; private final SimpleStringListComposite courseAreaNamesList; @@ -51,7 +52,7 @@ public class EventDetailsComposite extends Composite { VerticalPanel vPanel = new VerticalPanel(); mainPanel.add(vPanel); - int rows = 16; + int rows = 17; Grid grid = new Grid(rows, 2); vPanel.add(grid); @@ -64,6 +65,7 @@ public class EventDetailsComposite extends Composite { endDate = createLabelAndValueWidget(grid, currentRow++, stringMessages.endDate(), "EndDateLabel"); isPublic = createLabelAndValueWidget(grid, currentRow++, stringMessages.isPublic(), "IsPublicLabel"); officialWebsiteURL = createLabelAndAnchorWidget(grid, currentRow++, stringMessages.eventOfficialWebsiteURL(), "OfficialWebsiteURLLabel"); + baseURL = createLabelAndAnchorWidget(grid, currentRow++, stringMessages.eventBaseURL(), "BaseURLLabel"); sailorsInfoWebsiteURLList = createLabelAndAnchorListWidget(grid, currentRow++, stringMessages.eventSailorsInfoWebsiteURL(), "SailorsInfoWebsiteURLLabel"); eventOverviewURL = createLabelAndAnchorWidget(grid, currentRow++, stringMessages.eventOverviewURL(), "EventOverviewURLLabel"); courseAreaNamesList = createLabelAndValueListWidget(grid, currentRow++, stringMessages.courseAreas(), "CourseAreaValueList"); @@ -133,6 +135,8 @@ public class EventDetailsComposite extends Composite { isPublic.setText(String.valueOf(event.isPublic)); officialWebsiteURL.setText(event.getOfficialWebsiteURL()); officialWebsiteURL.setHref(event.getOfficialWebsiteURL()); + baseURL.setText(event.getBaseURL()); + baseURL.setHref(event.getBaseURL()); sailorsInfoWebsiteURLList.setValues(new ArrayList(event.getSailorsInfoWebsiteURLs().values())); String regattaOverviewLink = EntryPointWithSettingsLinkFactory .createRegattaOverviewLink(new RegattaOverviewBaseSettings(event.id, false)); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 556a7dd3a10..adadf4aae41 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -206,7 +206,7 @@ public abstract class EventDialog extends DataEntryDialogWithBootstrap if (additionalWidget != null) { panel.add(additionalWidget); } - Grid formGrid = new Grid(9 + GWTLocaleUtil.getLanguageCountWithDefault(), 2); + Grid formGrid = new Grid(10 + GWTLocaleUtil.getLanguageCountWithDefault(), 2); int rowIndex = 0; formGrid.setWidget(rowIndex, 0, new Label(stringMessages.name() + ":")); formGrid.setWidget(rowIndex++, 1, nameEntryField); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index 1374838de43..a426618a9bd 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -30,7 +30,7 @@ public class EventEditDialog extends EventDialog { id = event.id; officialWebsiteURLEntryField = createTextBox(event.getOfficialWebsiteURL()); officialWebsiteURLEntryField.setVisibleLength(50); - baseURLEntryField = createTextBox(event.getOfficialWebsiteURL()); + baseURLEntryField = createTextBox(event.getBaseURL()); baseURLEntryField.setVisibleLength(50); sailorsInfoWebsiteURLEntryFields = createTextBoxesForLocalesAndDefault(event.getSailorsInfoWebsiteURLs()); courseAreaNameList.setValue(new ArrayList<>(event.venue.getCourseAreas())); From 721808aa777783e0ef10ca3fccc47a4c39b37c97 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 14:27:58 +0200 Subject: [PATCH 208/259] use EventBase.getBaseURL() in SailingNotificationServiceImpl Change-Id: I5d2afbc26f5ddb35c877fcc0dc5126f47d795db8 --- .../impl/SailingNotificationServiceImpl.java | 20 +++++++++++++++++-- .../release_notes_admin.html | 6 ++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 3644e50a968..55314c9eb6b 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -1,11 +1,13 @@ package com.sap.sailing.server.notification.impl; +import java.net.MalformedURLException; import java.net.URL; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; import java.util.function.BiConsumer; +import java.util.logging.Level; import java.util.logging.Logger; import org.osgi.framework.BundleContext; @@ -183,9 +185,23 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific return createHomeRegattaLink("races", leaderboard, event); } + /** + * The base URL for notifications as extracted from the {@link Event#getBaseURL() event}; defaults + * to {@code https://www.sapsailing.com} if no base URL has been provided for the event. + */ private URL getBaseURL(final Event event) { - // TODO where to get the base URL? - return event.getBaseURL(); + URL result; + if (event.getBaseURL() == null) { + try { + result = new URL("https://www.sapsailing.com"); + } catch (MalformedURLException e) { + logger.log(Level.WARNING, "Strange... why isn't https://www.sapsailing.com a valid URL?", e); + result = null; + } + } else { + result = event.getBaseURL(); + } + return result; } private String createHomeLeaderboardLink(Leaderboard leaderboard, Event event) { diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 09fb4f758f5..444b03c990c 100644 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -46,6 +46,12 @@ now possible to enter a time stamp for the fix. This way it is also possible to adjust a mark's position to a fixed lat/lng for some time point in the past. +
      • An event now has a "Base URL" which should be used to enable useful e-mail notifications with + links embedded in them that lead to the correct server. If a notification is to contain + a link to a dedicated event server, the event cannot be reached through www.sapsailing.com, + and so if this generic link is used as a default, users will end up not finding the page + linked to by the notification. +
      • June 2016

        From aa748878c1f497fedd30cd828bbfc0ab945f5e01 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 15:22:10 +0200 Subject: [PATCH 209/259] clear the UserStoreImpl.listeners map in the UserStoreImpl.clear() method; fresh replicas should start with no listeners Change-Id: I43211599b4d0369efba5cde426975475d563b891 --- .../com/sap/sse/security/userstore/mongodb/UserStoreImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index c0371f96e02..bc6ec42abe6 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -153,6 +153,7 @@ public class UserStoreImpl implements UserStore { @Override public void clear() { + listeners.clear(); preferences.clear(); preferenceConverters.clear(); preferenceObjects.clear(); From d6419c51cb4813383e903f5afa3e7648bf8118a2 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 18:38:24 +0200 Subject: [PATCH 210/259] wired user notifications to a new LeaderboardScoreCorrectionNotifier in RacingEventService; wired notifications with TrackedRaceReplicatorAndNotifier Change-Id: I4ff77cf49700140b134dc95326a3f7a844958d95 --- .../impl/DomainFactoryImpl.java | 8 +- .../domain/leaderboard/Leaderboard.java | 16 ++ .../leaderboard/LeaderboardCacheManager.java | 4 +- .../leaderboard/ScoreCorrectionListener.java | 2 +- .../leaderboard/SettableScoreCorrection.java | 4 + .../impl/AbstractSimpleLeaderboardImpl.java | 23 ++ .../impl/RegattaLeaderboardImpl.java | 14 +- .../leaderboard/impl/ScoreCorrectionImpl.java | 8 +- .../meta/AbstractMetaLeaderboard.java | 6 +- .../meta/MetaLeaderboardScoreCorrection.java | 6 +- .../test/AbstractServerReplicationTest.java | 4 +- .../stringmessages/StringMessages.properties | 4 +- .../sap/sailing/server/impl/Activator.java | 2 +- ...java => RaceLogReplicatorAndNotifier.java} | 15 +- .../server/impl/RacingEventServiceImpl.java | 271 +++++++++++++++--- .../server/impl/RegattaLogReplicator.java | 2 +- .../SailingNotificationService.java | 5 +- .../impl/SailingNotificationServiceImpl.java | 45 ++- 18 files changed, 346 insertions(+), 93 deletions(-) rename java/com.sap.sailing.server/src/com/sap/sailing/server/impl/{RaceLogReplicator.java => RaceLogReplicatorAndNotifier.java} (82%) diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java index 2ce3c3f76ae..6d721a5e89b 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/DomainFactoryImpl.java @@ -612,18 +612,18 @@ public class DomainFactoryImpl implements DomainFactory { @Override public BoatClass getDominantBoatClass(Iterable competitorClassNames) { + final BoatClass result; if (competitorClassNames == null) { - return null; - + result = null; } else { Collection boatClasses = new ArrayList<>(); for (String competitorClassName : competitorClassNames) { BoatClass boatClass = getOrCreateBoatClass(competitorClassName); boatClasses.add(boatClass); } - - return Util.getDominantObject(boatClasses); + result = Util.getDominantObject(boatClasses); } + return result; } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java index d0635587a1f..f8ba35fa65c 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/Leaderboard.java @@ -6,6 +6,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; +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.DomainFactory; @@ -28,6 +29,7 @@ import com.sap.sailing.domain.tracking.TrackedRegattaRegistry; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; +import com.sap.sse.common.Util.Pair; /** * A leaderboard is used to display the results of one or more {@link TrackedRace races}. It manages the competitors' @@ -532,4 +534,18 @@ public interface Leaderboard extends LeaderboardBase, HasRaceColumns { NumberOfCompetitorsInLeaderboardFetcher getNumberOfCompetitorsInLeaderboardFetcher(); + /** + * Looks through all {@link #getRaceColumns() race columns} and their {@link RaceColumn#getFleets() fleets} and checks + * if {@code trackedRace} is {@link RaceColumn#getTrackedRace(Fleet) linked} to that combination. If such a slot is found + * that "slot" is returned by a pair specifying the non-{@code null} {@link RaceColumn} and {@code Fleet} pair. Otherwise, + * {@code null} is returned. + */ + Pair getRaceColumnAndFleet(TrackedRace trackedRace); + + /** + * Gets the ("dominant") boat class for this leaderboard. For a {@link RegattaLeaderboard} this is the {@link Regatta}'s boat class. + * For a {@link FlexibleLeaderboard} the implementation is more complex because no fixed boat class is set for the leaderboard. There, + * the boat class will be determined based on the most frequently occurring boat class when iterating across the competitors. + */ + BoatClass getBoatClass(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java index 2dd3fc8375c..a4ba3c0c0ec 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/LeaderboardCacheManager.java @@ -160,8 +160,8 @@ public class LeaderboardCacheManager { } @Override - public void maxPointsReasonChanced(Competitor competitor, MaxPointsReason oldMaxPointsReason, - MaxPointsReason newMaxPointsReason) { + public void maxPointsReasonChanced(Competitor competitor, RaceColumn raceColumn, + MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason) { removeFromCache(leaderboard); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java index 0cdf41e2f3f..eb64022400d 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/ScoreCorrectionListener.java @@ -8,7 +8,7 @@ import com.sap.sse.common.TimePoint; public interface ScoreCorrectionListener { void correctedScoreChanced(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, Double newCorrectedScore); - void maxPointsReasonChanced(Competitor competitor, MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason); + void maxPointsReasonChanced(Competitor competitor, RaceColumn raceColumn, MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason); void carriedPointsChanged(Competitor competitor, Double oldCarriedPoints, Double newCarriedPoints); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java index 7d5cad8055b..10b1eaeb283 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/SettableScoreCorrection.java @@ -6,6 +6,10 @@ import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sse.common.TimePoint; public interface SettableScoreCorrection extends ScoreCorrection { + /** + * The listeners added are transient and do not need to be {@link Serializable}. When this object is + * de-serialized, it starts out with an empty set of listeners. + */ void addScoreCorrectionListener(ScoreCorrectionListener listener); void removeScoreCorrectionListener(ScoreCorrectionListener listener); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java index 30894929bd4..e6833b076e3 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/AbstractSimpleLeaderboardImpl.java @@ -29,10 +29,13 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import com.sap.sailing.domain.abstractlog.race.InvalidatesLeaderboardCache; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; +import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Course; import com.sap.sailing.domain.base.DomainFactory; @@ -93,6 +96,7 @@ import com.sap.sailing.util.impl.RaceColumnListeners; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.Util; +import com.sap.sse.common.Util.Pair; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.concurrent.LockUtil; import com.sap.sse.concurrent.NamedReentrantReadWriteLock; @@ -1938,6 +1942,25 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race return new NumberOfCompetitorsFetcherImpl(); } + @Override + public Pair getRaceColumnAndFleet(TrackedRace trackedRace) { + for (final RaceColumn raceColumn : getRaceColumns()) { + for (final Fleet fleet : raceColumn.getFleets()) { + if (raceColumn.getTrackedRace(fleet) == trackedRace) { + return new Pair<>(raceColumn, fleet); + } + } + } + return null; + } + + + @Override + public BoatClass getBoatClass() { + return Util.getDominantObject(StreamSupport.stream(getCompetitors().spliterator(), /* parallel */ false). + map(c->c.getBoat().getBoatClass()).collect(Collectors.toList())); + } + protected abstract LeaderboardType getLeaderboardType(); } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java index d5af239cf6a..72cfd8ca4d4 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/RegattaLeaderboardImpl.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; +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.Fleet; @@ -53,10 +54,14 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R public Regatta getRegatta() { return regatta; } - + + public static String getLeaderboardNameForRegatta(Regatta regatta) { + return regatta.getName(); + } + @Override public String getName() { - return getRegatta().getName(); + return getLeaderboardNameForRegatta(getRegatta()); } @Override @@ -120,4 +125,9 @@ public class RegattaLeaderboardImpl extends AbstractLeaderboardImpl implements R protected LeaderboardType getLeaderboardType() { return LeaderboardType.RegattaLeaderboard; } + + @Override + public BoatClass getBoatClass() { + return getRegatta().getBoatClass(); + } } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java index 8b2e2d59ca4..47d1e4fb489 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/impl/ScoreCorrectionImpl.java @@ -103,10 +103,10 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection { } } - protected void notifyListeners(Competitor competitor, MaxPointsReason oldMaxPointsReason, - MaxPointsReason newMaxPointsReason) { + protected void notifyListeners(Competitor competitor, RaceColumn raceColumn, + MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason) { for (ScoreCorrectionListener listener : getScoreCorrectionListeners()) { - listener.maxPointsReasonChanced(competitor, oldMaxPointsReason, newMaxPointsReason); + listener.maxPointsReasonChanced(competitor, raceColumn, oldMaxPointsReason, newMaxPointsReason); } } @@ -148,7 +148,7 @@ public class ScoreCorrectionImpl implements SettableScoreCorrection { } else { oldMaxPointsReason = maxPointsReasons.put(key, reason); } - notifyListeners(competitor, oldMaxPointsReason, reason); + notifyListeners(competitor, raceColumn, oldMaxPointsReason, reason); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java index 030b22f75db..460ab3af697 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/AbstractMetaLeaderboard.java @@ -74,9 +74,9 @@ public abstract class AbstractMetaLeaderboard extends AbstractSimpleLeaderboardI } @Override - public void maxPointsReasonChanced(Competitor competitor, MaxPointsReason oldMaxPointsReason, - MaxPointsReason newMaxPointsReason) { - getScoreCorrection().notifyListeners(competitor, oldMaxPointsReason, newMaxPointsReason); + public void maxPointsReasonChanced(Competitor competitor, RaceColumn raceColumn, + MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason) { + getScoreCorrection().notifyListeners(competitor, raceColumn, oldMaxPointsReason, newMaxPointsReason); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java index 11206d8011e..7e5643534eb 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/meta/MetaLeaderboardScoreCorrection.java @@ -36,9 +36,9 @@ public class MetaLeaderboardScoreCorrection extends ScoreCorrectionImpl { * These redefinitions are required for scoping reasons, to make the method visible also to other classes in this package. */ @Override - protected void notifyListeners(Competitor competitor, MaxPointsReason oldMaxPointsReason, - MaxPointsReason newMaxPointsReason) { - super.notifyListeners(competitor, oldMaxPointsReason, newMaxPointsReason); + protected void notifyListeners(Competitor competitor, RaceColumn raceColumn, + MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason) { + super.notifyListeners(competitor, raceColumn, oldMaxPointsReason, newMaxPointsReason); } @Override diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java index 269a75ebe99..8a729da4acf 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java @@ -55,7 +55,7 @@ public abstract class AbstractServerReplicationTest extends com.sap.sse.replicat @Override public DomainFactory getBaseDomainFactory() { return baseDomainFactory; } @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } }; - }, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, null, null); + }, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, null, null, /* sailingNotificationService */ null); } @Override @@ -74,7 +74,7 @@ public abstract class AbstractServerReplicationTest extends com.sap.sse.replicat @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } }; }, MediaDBFactory.INSTANCE.getMediaDB(mongoDBService), EmptyWindStore.INSTANCE, EmptySensorFixStore.INSTANCE, - /* serviceFinderFactory */ null, null); + /* serviceFinderFactory */ null, null, /* sailingNotificationService */ null); } } } diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index aa925481168..42b4ed01af8 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -3,9 +3,9 @@ raceInFleetInRegattaOfEvent={0} ({3}) in regatta {1} of event {2} leaderboardOfEvent=leaderboard {0} of event {1} -boatClassRaceFinishingSubject=Race for boat class {0} finishes - new results available +boatClassRaceFinishedSubject=Race for boat class {0} has finished - new results available # 0: boatClassName, 1: raceDescription, 2: link -boatClassRaceFinishingBody=New results for boat class {0} in {1} are available. See: {2} +boatClassRaceFinishedBody=New results for boat class {0} in {1} are available. See: {2} boatClassScoreCorrectionSubject=New results are available for boat class {0} # 0: boatClassName, 1: leaderboardDescription, 2: link diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 81649269e50..8695253dc8c 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -100,7 +100,7 @@ public class Activator implements BundleActivator { // instead. serviceFinderFactory = new CachedOsgiTypeBasedServiceFinderFactory(context); racingEventService = new RacingEventServiceImpl(clearPersistentCompetitors, serviceFinderFactory, - trackedRegattaListener); + trackedRegattaListener, notificationService); notificationService.setRacingEventService(racingEventService); masterDataImportClassLoaderServiceTracker = new ServiceTracker( diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicatorAndNotifier.java similarity index 82% rename from java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicator.java rename to java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicatorAndNotifier.java index df2e1f6b302..a231a79a8a5 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RaceLogReplicatorAndNotifier.java @@ -18,21 +18,28 @@ import com.sap.sailing.server.operationaltransformation.RecordRaceLogEventOnLead import com.sap.sailing.server.operationaltransformation.RecordRaceLogEventOnRegatta; /** - * Being a {@link RaceColumnListener}, this replicator must be added to all {@link RaceColumn}s managing a + * Being a {@link RaceColumnListener}, this replicator and notifier must be added to all {@link RaceColumn}s managing a * {@link RaceLog} so as to be notified about changes to the race log. This largely happens by callbacks to the * {@link #raceLogEventAdded(RaceColumn, RaceLogIdentifier, RaceLogEvent)} method. This object will then use the * {@link Replicator} passed to this object's constructor and send a {@link RecordRaceLogEventOnLeaderboard} or a - * {@link RecordRaceLogEventOnRegatta} operation to all replicas. + * {@link RecordRaceLogEventOnRegatta} operation to all replicas.

        + * + * Since all {@link RaceColumn}s can manage a {@link RaceLog}, this object is registered on all relevant + * {@link RaceColumn}s. This also lets this object conveniently being informed about all other events that + * a {@link RaceColumnListener} is notified about, some of which contain interesting information regarding + * the notifying of users interested in certain types of changes. For example, when a {@link TrackedRace} + * {@link #trackedRaceLinked(RaceColumn, Fleet, TrackedRace) is linked} to a race column, this may be of + * interest to some users. * * @author Axel Uhl (d043530) * */ -public class RaceLogReplicator implements RaceColumnListener { +public class RaceLogReplicatorAndNotifier implements RaceColumnListener { private static final long serialVersionUID = 7190510926643574068L; private final Replicator service; - public RaceLogReplicator(Replicator service) { + public RaceLogReplicatorAndNotifier(Replicator service) { this.service = service; } 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 5775aba10a2..d94b2eff851 100644 --- 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 @@ -95,6 +95,7 @@ import com.sap.sailing.domain.base.impl.RemoteSailingServerReferenceImpl; import com.sap.sailing.domain.common.DataImportProgress; import com.sap.sailing.domain.common.DataImportSubProgress; import com.sap.sailing.domain.common.Distance; +import com.sap.sailing.domain.common.MaxPointsReason; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.RegattaAndRaceIdentifier; import com.sap.sailing.domain.common.RegattaIdentifier; @@ -119,7 +120,9 @@ import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.leaderboard.LeaderboardRegistry; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sailing.domain.leaderboard.ScoreCorrectionListener; import com.sap.sailing.domain.leaderboard.ScoringScheme; +import com.sap.sailing.domain.leaderboard.SettableScoreCorrection; import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl; import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl; @@ -177,6 +180,7 @@ import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJ import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardSearchResultBaseJsonDeserializer; import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer; import com.sap.sailing.server.masterdata.DataImportLockWithProgress; +import com.sap.sailing.server.notification.SailingNotificationService; import com.sap.sailing.server.operationaltransformation.AddCourseAreas; import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta; import com.sap.sailing.server.operationaltransformation.AddMediaTrackOperation; @@ -220,6 +224,7 @@ import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclu import com.sap.sailing.server.simulation.SimulationService; import com.sap.sailing.server.simulation.SimulationServiceFactory; import com.sap.sse.ServerInfo; +import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.Util; @@ -362,7 +367,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes */ private final ConcurrentHashMap persistentRegattasForRaceIDs; - private final RaceLogReplicator raceLogReplicator; + private final RaceLogReplicatorAndNotifier raceLogReplicator; private final RegattaLogReplicator regattaLogReplicator; private final RaceLogScoringReplicator raceLogScoringReplicator; @@ -390,6 +395,18 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes private final SimulationService simulationService; + /** + * A service that, if not {@code null}, must be called when certain events that the service can notify users about + * have occurred. For example, the + * {@link SailingNotificationService#notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(com.sap.sailing.domain.base.BoatClass, Leaderboard)} + * method must be called whenever a new set of score corrections have been made available.

        + * + * The field is transient because we don't want the service to be serialized from a master to a replica. + * Replicas are expected to not notify users about anything, particularly because they usually don't + * have a valid mail service, either. + */ + private transient final SailingNotificationService notificationService; + /** * Allow only one master data import at a time to avoid situation where multiple Imports override each other in * unpredictable fashion @@ -422,6 +439,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes private SailingServerConfiguration sailingServerConfiguration; private final TrackedRegattaListener trackedRegattaListener; + + private transient ConcurrentHashMap scoreCorrectionListenersByLeaderboard; /** * Providing the constructor parameters for a new {@link RacingEventServiceImpl} instance is a bit tricky @@ -453,7 +472,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public RacingEventServiceImpl(WindStore windStore, SensorFixStore sensorFixStore, TypeBasedServiceFinderFactory serviceFinderFactory) { - this(true, windStore, sensorFixStore, serviceFinderFactory); + this(true, windStore, sensorFixStore, serviceFinderFactory, /* sailingNotificationService */ null); } void setBundleContext(BundleContext bundleContext) { @@ -461,7 +480,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory) { - this(clearPersistentCompetitorStore, serviceFinderFactory, null); + this(clearPersistentCompetitorStore, serviceFinderFactory, null, /* sailingNotificationService */ null); } /** @@ -472,8 +491,12 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes * if true, the {@link PersistentCompetitorStore} is created empty, with the corresponding * database collection cleared as well. Use with caution! When used with false, competitors * created and stored during previous service executions will initially be loaded. + * @param sailingNotificationService + * a notification service to call upon events worth notifying users about, or {@code null} if no + * notification service is available, e.g., in test set-ups */ - public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory, TrackedRegattaListener trackedRegattaListener) { + public RacingEventServiceImpl(boolean clearPersistentCompetitorStore, final TypeBasedServiceFinderFactory serviceFinderFactory, + TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService) { this((final RaceLogResolver raceLogResolver)-> { return new ConstructorParameters() { private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory); @@ -486,11 +509,11 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); } @Override public CompetitorStore getCompetitorStore() { return competitorStore; } }; - }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory ,trackedRegattaListener); + }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), null, null, serviceFinderFactory ,trackedRegattaListener, sailingNotificationService); } private RacingEventServiceImpl(final boolean clearPersistentCompetitorStore, WindStore windStore, - SensorFixStore sensorFixStore, final TypeBasedServiceFinderFactory serviceFinderFactory) { + SensorFixStore sensorFixStore, final TypeBasedServiceFinderFactory serviceFinderFactory, SailingNotificationService sailingNotificationService) { this((final RaceLogResolver raceLogResolver)-> { return new ConstructorParameters() { private final MongoObjectFactory mongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(serviceFinderFactory); @@ -503,29 +526,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes @Override public DomainFactory getBaseDomainFactory() { return competitorStore.getBaseDomainFactory(); } @Override public CompetitorStore getCompetitorStore() { return competitorStore; } }; - }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, sensorFixStore, serviceFinderFactory, null); + }, MediaDBFactory.INSTANCE.getDefaultMediaDB(), windStore, sensorFixStore, serviceFinderFactory, null, sailingNotificationService); } - /** - * Uses the default factories for the tracking adapters and the {@link DomainFactory base domain factory} of the - * {@link PersistenceFactory#getDefaultDomainObjectFactory() default domain object factory}. This constructor should - * be used for testing because it provides a transient {@link CompetitorStore} as required for competitor - * persistence. - */ - public RacingEventServiceImpl(Function domainObjectFactoryProvider, - final MongoObjectFactory mongoObjectFactory, MediaDB mediaDB, WindStore windStore, SensorFixStore sensorFixStore) { - this((final RaceLogResolver raceLogResolver)-> { - return new ConstructorParameters() { - private final DomainObjectFactory domainObjectFactory = domainObjectFactoryProvider.apply(raceLogResolver); - - @Override public DomainObjectFactory getDomainObjectFactory() { return domainObjectFactory; } - @Override public MongoObjectFactory getMongoObjectFactory() { return mongoObjectFactory; } - @Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); } - @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } - }; - }, mediaDB, windStore, sensorFixStore, null, null); - } - public RacingEventServiceImpl(final DomainObjectFactory domainObjectFactory, MongoObjectFactory mongoObjectFactory, MediaDB mediaDB, WindStore windStore, SensorFixStore sensorFixStore) { this((final RaceLogResolver raceLogResolver)-> { @@ -535,7 +538,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes @Override public DomainFactory getBaseDomainFactory() { return domainObjectFactory.getBaseDomainFactory(); } @Override public CompetitorStore getCompetitorStore() { return getBaseDomainFactory().getCompetitorStore(); } }; - }, mediaDB, windStore, sensorFixStore, null, null); + }, mediaDB, windStore, sensorFixStore, null, null, /* sailingNotificationService */ null); } /** @@ -546,10 +549,15 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes * used to find the services handling specific types of tracking devices, such as the persistent storage * of {@link DeviceIdentifier}s of specific device types or the managing of the device-to-competitor * associations per race tracked. + * @param sailingNotificationService + * a notification service to call upon events worth notifying users about, or {@code null} if no + * notification service is available, e.g., in test set-ups */ public RacingEventServiceImpl(Function constructorParametersProvider, MediaDB mediaDb, - final WindStore windStore, final SensorFixStore sensorFixStore, TypeBasedServiceFinderFactory serviceFinderFactory, TrackedRegattaListener trackedRegattaListener) { + final WindStore windStore, final SensorFixStore sensorFixStore, TypeBasedServiceFinderFactory serviceFinderFactory, + TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService) { logger.info("Created " + this); + this.notificationService = sailingNotificationService; final ConstructorParameters constructorParameters = constructorParametersProvider.apply(this); this.domainObjectFactory = constructorParameters.getDomainObjectFactory(); this.masterDataClassLoaders.add(this.getClass().getClassLoader()); @@ -606,7 +614,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes Thread.NORM_PRIORITY, /* daemon */true)); // TODO: initialize smart-future-cache for simulation-results and add to simulation-service simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, this); - this.raceLogReplicator = new RaceLogReplicator(this); + this.raceLogReplicator = new RaceLogReplicatorAndNotifier(this); this.regattaLogReplicator = new RegattaLogReplicator(this); this.raceLogScoringReplicator = new RaceLogScoringReplicator(this); this.mediaLibrary = new MediaLibrary(); @@ -777,6 +785,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes leaderboard.addRaceColumnListener(raceLogReplicator); leaderboard.addRaceColumnListener(raceLogScoringReplicator); } + final LeaderboardScoreCorrectionNotifier scoreCorrectionListener = new LeaderboardScoreCorrectionNotifier(leaderboard); + scoreCorrectionListenersByLeaderboard.put(leaderboard, scoreCorrectionListener); + leaderboard.getScoreCorrection().addScoreCorrectionListener(scoreCorrectionListener); } private void loadStoredLeaderboardsAndGroups() { @@ -1008,6 +1019,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes if (leaderboard != null) { leaderboard.removeRaceColumnListener(raceLogReplicator); leaderboard.removeRaceColumnListener(raceLogScoringReplicator); + final ScoreCorrectionListener scoreCorrectionListener = scoreCorrectionListenersByLeaderboard.remove(leaderboard); + if (scoreCorrectionListener != null) { + leaderboard.getScoreCorrection().removeScoreCorrectionListener(scoreCorrectionListener); + } mongoObjectFactory.removeLeaderboard(leaderboardName); syncGroupsAfterLeaderboardRemove(leaderboardName, true); if (leaderboard instanceof FlexibleLeaderboard) { @@ -1537,7 +1552,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes * service, the service adds the tracked race to the default leaderboard and links it to the leaderboard columns * that were previously connected to it. Additionally, a {@link RaceChangeListener} is added to the * {@link TrackedRace} which is responsible for triggering the replication of all relevant changes to the tracked - * race. When a tracked race is removed, the {@link TrackedRaceReplicator} that was added as listener to that + * race. When a tracked race is removed, the {@link TrackedRaceReplicatorAndNotifier} that was added as listener to that * tracked race is removed again. * * A {@link PolarFixCacheUpdater} is added to every race so that polar fixes are aggregated when new GPS fixes @@ -1549,18 +1564,18 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes private class RaceAdditionListener implements RaceListener, Serializable { private static final long serialVersionUID = 1036955460477000265L; - private final Map trackedRaceReplicators; + private final Map trackedRaceReplicators; private final Map polarFixCacheUpdaters; public RaceAdditionListener() { - this.trackedRaceReplicators = new HashMap(); + this.trackedRaceReplicators = new HashMap(); this.polarFixCacheUpdaters = new HashMap(); } @Override public void raceRemoved(TrackedRace trackedRace) { - TrackedRaceReplicator trackedRaceReplicator = trackedRaceReplicators.remove(trackedRace); + TrackedRaceReplicatorAndNotifier trackedRaceReplicator = trackedRaceReplicators.remove(trackedRace); if (trackedRaceReplicator != null) { trackedRace.removeListener(trackedRaceReplicator); } @@ -1578,7 +1593,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes trackedRace.getMillisecondsOverWhichToAverageSpeed()); replicate(op); linkRaceToConfiguredLeaderboardColumns(trackedRace); - TrackedRaceReplicator trackedRaceReplicator = new TrackedRaceReplicator(trackedRace); + TrackedRaceReplicatorAndNotifier trackedRaceReplicator = new TrackedRaceReplicatorAndNotifier(trackedRace); trackedRaceReplicators.put(trackedRace, trackedRaceReplicator); trackedRace.addListener(trackedRaceReplicator, /* fire wind already loaded */true, true); @@ -1591,6 +1606,98 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } } } + + /** + * A score correction listener for a leaderboard that notifies interested users through the + * {@link RacingEventServiceImpl#notificationService} if one is available. + * + * @author Axel Uhl (d043530) + * + */ + private class LeaderboardScoreCorrectionNotifier implements ScoreCorrectionListener { + /** + * We don't want to flood the users with notifications about what's basically caused by the + * same original event. For example, when many single score correction updates are applied to + * the same leaderboard, we don't want to notify users for each such change if they are generally + * interested in new results for that leaderboard or this boat class. + */ + private final Duration HOW_LONG_BETWEEN_TWO_NOTIFICATIONS_FOR_SIMILAR_EVENT = Duration.ONE_MINUTE.times(5); + + private TimePoint lastNotificationForLeaderboard; + + private final ConcurrentHashMap lastNotificationForCompetitor; + + private final Leaderboard leaderboard; + + /** + * Callers are expected to {@link SettableScoreCorrection#addScoreCorrectionListener(ScoreCorrectionListener) + * register} this listener as a {@link ScoreCorrectionListener} themselves. + */ + public LeaderboardScoreCorrectionNotifier(Leaderboard leaderboard) { + this.leaderboard = leaderboard; + this.lastNotificationForCompetitor = new ConcurrentHashMap<>(); + } + + @Override + public void correctedScoreChanced(Competitor competitor, RaceColumn raceColumn, Double oldCorrectedScore, + Double newCorrectedScore) { + notifyForCompetitorIfNotAlreadyNotifiedRecently(competitor, raceColumn); + } + + @Override + public void maxPointsReasonChanced(Competitor competitor, RaceColumn raceColumn, MaxPointsReason oldMaxPointsReason, MaxPointsReason newMaxPointsReason) { + notifyForCompetitorIfNotAlreadyNotifiedRecently(competitor, raceColumn); + } + + @Override + public void carriedPointsChanged(Competitor competitor, Double oldCarriedPoints, Double newCarriedPoints) { + notifyForCompetitorIfNotAlreadyNotifiedRecently(competitor, /* no raceColumn in case of carried points */ null); + } + + @Override + public void isSuppressedChanged(Competitor competitor, boolean newIsSuppressed) { + // do nothing + } + + @Override + public void timePointOfLastCorrectionsValidityChanged(TimePoint oldTimePointOfLastCorrectionsValidity, + TimePoint newTimePointOfLastCorrectionsValidity) { + notifyForLeaderboardIfNotAlreadyNotifiedRecently(); + } + + @Override + public void commentChanged(String oldComment, String newComment) { + notifyForLeaderboardIfNotAlreadyNotifiedRecently(); + } + + private void notifyForLeaderboardIfNotAlreadyNotifiedRecently() { + final TimePoint now = MillisecondsTimePoint.now(); + if (notificationService != null && (lastNotificationForLeaderboard == null || + lastNotificationForLeaderboard.until(now).compareTo(HOW_LONG_BETWEEN_TWO_NOTIFICATIONS_FOR_SIMILAR_EVENT) >= 0)) { + new Thread(()->notificationService.notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable( + leaderboard.getBoatClass(), leaderboard), + "Score correction notifier for leaderboard "+leaderboard.getName()).start(); + lastNotificationForLeaderboard = now; + } + } + + /** + * @param raceColumn + * may be {@code null} which means that something may have changed for the competitor outside of a + * specific race column, such as the carried points + */ + private void notifyForCompetitorIfNotAlreadyNotifiedRecently(Competitor competitor, RaceColumn raceColumn) { + final TimePoint now = MillisecondsTimePoint.now(); + if (notificationService != null && (!lastNotificationForCompetitor.containsKey(competitor) || + lastNotificationForCompetitor.get(competitor).until(now).compareTo(HOW_LONG_BETWEEN_TWO_NOTIFICATIONS_FOR_SIMILAR_EVENT) >= 0)) { + new Thread(()->notificationService.notifyUserOnCompetitorScoreCorrections(competitor, leaderboard), + "Score correction notifier for competitor "+competitor.getName()+" in leaderboard "+ + leaderboard.getName()).start(); + lastNotificationForCompetitor.put(competitor, now); + } + } + + } private class PolarFixCacheUpdater extends AbstractRaceChangeListener { @@ -1619,10 +1726,19 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes } - private class TrackedRaceReplicator implements RaceChangeListener { + /** + * When changes occur on a {@link TrackedRace}, this object will be notified in its role of being a + * {@link RaceChangeListener}. It does two things: replicate the changes to replica servers and, potentially, if + * this is a replica, back to a master; notify users who expressed a corresponding interest about the change if we + * have a {@link RacingEventServiceImpl##notificationService} available. + * + * @author Axel Uhl (d043530) + * + */ + private class TrackedRaceReplicatorAndNotifier implements RaceChangeListener { private final TrackedRace trackedRace; - public TrackedRaceReplicator(TrackedRace trackedRace) { + public TrackedRaceReplicatorAndNotifier(TrackedRace trackedRace) { this.trackedRace = trackedRace; } @@ -1648,14 +1764,28 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes @Override public void startOfRaceChanged(TimePoint oldStartOfRace, TimePoint newStartOfRace) { - // no action required; the update signaled by this call is implicit; for explicit updates + // no replication action required; the update signaled by this call is implicit; for explicit updates // see raceTimesChanged(TimePoint, TimePoint, TimePoint). + + if (newStartOfRace != null && newStartOfRace.after(MillisecondsTimePoint.now())) { + new Thread(()-> + // Notify interested users if the new start time is in the future + notificationService.notifyUserOnBoatClassUpcomingRace(trackedRace.getRace().getBoatClass(), + getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet(), newStartOfRace), + "Notifier about startOfRaceChanged for "+trackedRace).start(); + } } @Override public void finishedTimeChanged(TimePoint oldFinishedTime, TimePoint newFinishedTime) { // no action required; the update signaled by this call is implicit; the race log // updates that led to this change are replicated separately + + new Thread(()-> + // Notify interested users: + notificationService.notifyUserOnBoatClassRaceChangesStateToFinished(trackedRace.getRace().getBoatClass(), trackedRace, + getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet()), + "Notifier about finishedTimeChanged for "+trackedRace).start(); } @Override @@ -1713,6 +1843,14 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public void markPassingReceived(Competitor competitor, Map oldMarkPassings, Iterable markPassings) { replicate(new UpdateMarkPassings(getRaceIdentifier(), competitor, markPassings)); + final MarkPassing last = Util.last(markPassings); + if (last != null && last.getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint() && + trackedRace.getStatus().getStatus() != TrackedRaceStatusEnum.LOADING) { + new Thread(()-> + // Notify interested users: + notificationService.notifyUserOnCompetitorPassesFinish(competitor, trackedRace, getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet()), + "Notifier about finish waypoing passed for "+trackedRace).start(); + } } @Override @@ -1748,6 +1886,62 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes public void raceLogDetached(RaceLog raceLog) { // no action required } + + private Leaderboard getMostAppropriateLeaderboard() { + final Triple slot = findMostAppropriateLeaderboardSlot(); + return slot == null ? null : slot.getA(); + } + + private RaceColumn getMostAppropriateRaceColumn() { + final Triple slot = findMostAppropriateLeaderboardSlot(); + return slot == null ? null : slot.getB(); + } + + private Fleet getMostAppropriateFleet() { + final Triple slot = findMostAppropriateLeaderboardSlot(); + return slot == null ? null : slot.getC(); + } + + /** + * When all we have is a {@link #trackedRace} and we're looking for a slot in a leaderboard, we have to + * search the enclosing {@link RacingEventService} for a leaderboard that has the {@link #trackedRace} + * in a {@link RaceColumn}/{@link Fleet} slot.

        + * + * As a first approximation we'll use the fact that a {@link RegattaLeaderboard}'s name is derived + * from the {@link Regatta} and as such can be looked up in constant time. Only if such a regatta + * leaderboard is not found, a search across all leaderboards will need to be carried out.

        + * + * Note that this method should be called in a background thread that runs outside of the call stack + * of the notification sent to this {@link RaceChangeListener}, ideally as a task in an executor. + * This will avoid performance hits due to an attempt to send out notifications. + */ + private Triple findMostAppropriateLeaderboardSlot() { + final Regatta regatta = trackedRace.getTrackedRegatta().getRegatta(); + final String regattaLeaderboardName = RegattaLeaderboardImpl.getLeaderboardNameForRegatta(regatta); + final Leaderboard regattaLeaderboard = getLeaderboardByName(regattaLeaderboardName); + Leaderboard leaderboard = null; + Pair raceColumnAndFleet = null; + if (regattaLeaderboard != null) { + leaderboard = regattaLeaderboard; + raceColumnAndFleet = regattaLeaderboard.getRaceColumnAndFleet(trackedRace); + } else { + for (final Leaderboard l : getLeaderboards().values()) { + final Pair rcaf = l.getRaceColumnAndFleet(trackedRace); + if (rcaf != null) { + leaderboard = l; + raceColumnAndFleet = rcaf; + break; + } + } + } + final Triple result; + if (leaderboard != null && raceColumnAndFleet != null) { + result = new Triple<>(leaderboard, raceColumnAndFleet.getA(), raceColumnAndFleet.getB()); + } else { + result = null; + } + return result; + } } /** @@ -2658,6 +2852,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes LockUtil.lockForWrite(leaderboardsByNameLock); try { leaderboardsByName.clear(); + scoreCorrectionListenersByLeaderboard.clear(); } finally { LockUtil.unlockAfterWrite(leaderboardsByNameLock); } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RegattaLogReplicator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RegattaLogReplicator.java index 928825e5055..f29f2329e91 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RegattaLogReplicator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RegattaLogReplicator.java @@ -20,7 +20,7 @@ import com.sap.sailing.server.operationaltransformation.RecordRegattaLogEventOnR * passed to this object's constructor and send a {@link RecordRegattaLogEventOnRegatta} or a * {@link RecordRegattaLogEventOnFlexibleLeaderboard} operation to all replicas. * - * This class is a modified version of {@link RaceLogReplicator} + * This class is a modified version of {@link RaceLogReplicatorAndNotifier} * */ public class RegattaLogReplicator implements RegattaLikeListener { diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java index 2f8061df735..acd48c15a88 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java @@ -12,10 +12,9 @@ import com.sap.sse.common.TimePoint; public interface SailingNotificationService { /** - * Called when {@link RaceState} changes state to finishing/finished (?). + * Called when {@link RaceState} changes state to finished. */ - void notifyUserOnBoatClassRaceChangesStateToFinishing(BoatClass boatClass, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, - Fleet fleet); + void notifyUserOnBoatClassRaceChangesStateToFinished(BoatClass boatClass, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet); /** * Called on score correction for a race with BoatClass if the last score correction was more than one minute. diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 55314c9eb6b..56a7e41cf6c 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -7,7 +7,6 @@ import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; import java.util.function.BiConsumer; -import java.util.logging.Level; import java.util.logging.Logger; import org.osgi.framework.BundleContext; @@ -49,8 +48,9 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific private final BoatClassResultsNotificationSet boatClassResults; private final BoatClassUpcomingRaceNotificationSet boatClassUpcomingRace; private final CompetitorResultsNotificationSet competitorResults; + private final URL defaultBaseURL; - public SailingNotificationServiceImpl(BundleContext bundleContext, MailQueue mailQueue) { + public SailingNotificationServiceImpl(BundleContext bundleContext, MailQueue mailQueue) throws MalformedURLException { this(mailQueue, new BoatClassResultsNotificationSet(bundleContext), new BoatClassUpcomingRaceNotificationSet(bundleContext), @@ -59,8 +59,9 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific /** * Constructor used for unit tests to not need BundelContext but directly work with a given UserStore. + * @throws MalformedURLException */ - public SailingNotificationServiceImpl(UserStore userStore, MailQueue mailQueue) { + public SailingNotificationServiceImpl(UserStore userStore, MailQueue mailQueue) throws MalformedURLException { this(mailQueue, new BoatClassResultsNotificationSet(userStore), new BoatClassUpcomingRaceNotificationSet(userStore), @@ -69,10 +70,11 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific public SailingNotificationServiceImpl(MailQueue mailQueue, BoatClassResultsNotificationSet boatClassResults, BoatClassUpcomingRaceNotificationSet boatClassUpcomingRace, - CompetitorResultsNotificationSet competitorResults) { + CompetitorResultsNotificationSet competitorResults) throws MalformedURLException { this.mailQueue = mailQueue; this.messages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, this.getClass().getClassLoader()); + this.defaultBaseURL = new URL("https://www.sapsailing.com"); toStop.add(this.boatClassResults = boatClassResults); toStop.add(this.boatClassUpcomingRace = boatClassUpcomingRace); @@ -109,21 +111,22 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific // if multiple LeaderboardGroups of the single event reference the same leaderboard, we just use the // first LeaderboardGroup. This could be a non optimal match but helps to e.g. construct valid links. return new Pair<>(Util.get(foundEvents, 0), Util.get(foundLeaderboardGroups, 0)); - } else if (foundEventsCount > 1 && foundLeaderboardGroups.size() == 1) { + } else if (foundEventsCount > 1) { // could be a series - LeaderboardGroup leaderboardGroup = Util.get(foundLeaderboardGroups, 0); - if (leaderboardGroup.hasOverallLeaderboard()) { - CourseArea defaultCourseArea = leaderboard.getDefaultCourseArea(); - if (defaultCourseArea != null) { - for (Event event : foundEvents) { - if (Util.contains(event.getVenue().getCourseAreas(), defaultCourseArea)) { - return new Pair<>(event, leaderboardGroup); + for (final LeaderboardGroup leaderboardGroup : foundLeaderboardGroups) { + if (leaderboardGroup.hasOverallLeaderboard()) { + CourseArea defaultCourseArea = leaderboard.getDefaultCourseArea(); + if (defaultCourseArea != null) { + for (Event event : foundEvents) { + if (Util.contains(event.getVenue().getCourseAreas(), defaultCourseArea)) { + return new Pair<>(event, leaderboardGroup); + } } } } // Event <-> Leaderboard association is not set up correctly. The UI will show the Leaderboard for // multiple Events. So any of the found Events is ok for this case. - return new Pair<>(Util.get(foundEvents, 0), leaderboardGroup); + return new Pair<>(Util.get(foundEvents, 0), Util.get(foundLeaderboardGroups, 0)); } } // No associated event found or association is ambiguous @@ -190,14 +193,9 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific * to {@code https://www.sapsailing.com} if no base URL has been provided for the event. */ private URL getBaseURL(final Event event) { - URL result; + final URL result; if (event.getBaseURL() == null) { - try { - result = new URL("https://www.sapsailing.com"); - } catch (MalformedURLException e) { - logger.log(Level.WARNING, "Strange... why isn't https://www.sapsailing.com a valid URL?", e); - result = null; - } + result = defaultBaseURL; } else { result = event.getBaseURL(); } @@ -215,7 +213,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific } @Override - public void notifyUserOnBoatClassRaceChangesStateToFinishing(BoatClass boatClass, TrackedRace trackedRace, + public void notifyUserOnBoatClassRaceChangesStateToFinished(BoatClass boatClass, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { String link = createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup); @@ -223,13 +221,13 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { @Override protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassRaceFinishingSubject", boatClass.getDisplayName()); + return messages.get(locale, "boatClassRaceFinishedSubject", boatClass.getDisplayName()); } @Override protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); - return messages.get(locale, "boatClassRaceFinishingBody", boatClass.getDisplayName(), + return messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(), raceDescription, link); } }); @@ -238,6 +236,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific @Override public void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard) { + // TODO don't send notifications when a notification for the same boatClass / leaderboard has already been sent shortly before doWithEvent(leaderboard, (event, leaderboardGroup) -> { String link = createHomeLeaderboardLink(leaderboard, event); From 451a67cb82ada2c103c5742051e50c161d3a517b Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 19:45:36 +0200 Subject: [PATCH 211/259] properly initialize this.scoreCorrectionListenersByLeaderboard in RacingEventServiceImpl Change-Id: I5091865beef52d630793c521fc44bd1ddaf411e2 --- .../src/com/sap/sailing/server/impl/RacingEventServiceImpl.java | 1 + 1 file changed, 1 insertion(+) 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 d94b2eff851..ec7b85c78ed 100644 --- 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 @@ -557,6 +557,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes final WindStore windStore, final SensorFixStore sensorFixStore, TypeBasedServiceFinderFactory serviceFinderFactory, TrackedRegattaListener trackedRegattaListener, SailingNotificationService sailingNotificationService) { logger.info("Created " + this); + this.scoreCorrectionListenersByLeaderboard = new ConcurrentHashMap<>(); this.notificationService = sailingNotificationService; final ConstructorParameters constructorParameters = constructorParametersProvider.apply(this); this.domainObjectFactory = constructorParameters.getDomainObjectFactory(); From 42429da7a1926b30d75a5effdc25806851bd2566 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 19:46:10 +0200 Subject: [PATCH 212/259] encode URLs before sending them in an HTML e-mail Change-Id: Ic71c4a6a66a110dac3148261f01aa5b2ffd1c19c --- .../impl/SailingNotificationServiceImpl.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 56a7e41cf6c..719887fe7fa 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -1,12 +1,15 @@ package com.sap.sailing.server.notification.impl; +import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLEncoder; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; import java.util.function.BiConsumer; +import java.util.logging.Level; import java.util.logging.Logger; import org.osgi.framework.BundleContext; @@ -228,7 +231,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); return messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(), - raceDescription, link); + raceDescription, encodeLink(link)); } }); }); @@ -250,7 +253,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); return messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(), - leaderboardDescription, link); + leaderboardDescription, encodeLink(link)); } }); }); @@ -273,12 +276,24 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific // TODO properly format time in the user's locale String time = when.toString(); return messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), - raceDescription, time, link); + raceDescription, time, encodeLink(link)); } }); }); } + + private String encodeLink(String link) { + String encodedLink; + try { + encodedLink = URLEncoder.encode(link, "UTF-8"); + } catch (UnsupportedEncodingException e) { + logger.log(Level.WARNING, "Why is UTF-8 not known?", e); + encodedLink = link; + } + return encodedLink; + } + @Override public void notifyUserOnCompetitorPassesFinish(Competitor competitor, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { @@ -295,7 +310,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); return messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription, - link); + encodeLink(link)); } }); }); @@ -316,7 +331,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); return messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), - leaderboardDescription, link); + leaderboardDescription, encodeLink(link)); } }); }); From 9526d78d706d15d508ae6bcbbfb398dda44ab686 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 19:46:27 +0200 Subject: [PATCH 213/259] a little speed-up in Util.addToValueSet, avoiding duplicate look-up Change-Id: I428fbe0a331e3989c357db5947f046b59ddd6631 --- java/com.sap.sse.common/src/com/sap/sse/common/Util.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java index 5569ae173f6..76837ee6bcc 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/Util.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/Util.java @@ -359,10 +359,12 @@ public class Util { } public static void addToValueSet(Map> map, K key, V value) { - if (! map.containsKey(key)) { - map.put(key, new HashSet()); + Set set = map.get(key); + if (set == null) { + set = new HashSet(); + map.put(key, set); } - map.get(key).add(value); + set.add(value); } public static void removeFromAllValueSets(Map> map, V value) { From 4adb6ba386c540459a633bfb433207f12ac03564 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 19:53:44 +0200 Subject: [PATCH 214/259] open the OSGi service tracker, or else nothing happens... Change-Id: I5b278f4ef72849f2910b2b58dfa9b622cc9631bd --- .../sap/sse/security/PreferenceObjectBasedNotificationSet.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java index 2e0ed013d68..6555e5951c9 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/PreferenceObjectBasedNotificationSet.java @@ -80,6 +80,7 @@ public abstract class PreferenceObjectBasedNotificationSet implements this.tracker = null; } else { this.tracker = new ServiceTracker(context, UserStore.class, new Cutomizer()); + this.tracker.open(); } this.lock = new NamedReentrantReadWriteLock(getClass().getName()+" for "+key, /* fair */ false); } From 6c199d8598ccda0a91016d5a49c001a4cfc51026 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 19:58:39 +0200 Subject: [PATCH 215/259] also notify users interested in leaderboard correction changes if only a single competitor was changed Change-Id: I67f37d60679b96e3a3dd4c640e24f61f580428f6 --- .../src/com/sap/sailing/server/impl/RacingEventServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) 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 ec7b85c78ed..1b0a2bd44f2 100644 --- 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 @@ -1696,6 +1696,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes leaderboard.getName()).start(); lastNotificationForCompetitor.put(competitor, now); } + // a change to a single competitor also means a change to the leaderboard + notifyForLeaderboardIfNotAlreadyNotifiedRecently(); } } From 568d6cd7679d08b4e1dc18813b431475b5e8d836 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 19:59:00 +0200 Subject: [PATCH 216/259] in the HTML mail embed the link as a element Change-Id: I5c89ddf6de6872ca0991f5e738b0d8e1d5907c66 --- .../impl/SailingNotificationServiceImpl.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 719887fe7fa..2f60ce3462a 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -1,15 +1,12 @@ package com.sap.sailing.server.notification.impl; -import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; -import java.net.URLEncoder; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Set; import java.util.function.BiConsumer; -import java.util.logging.Level; import java.util.logging.Logger; import org.osgi.framework.BundleContext; @@ -284,13 +281,7 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific private String encodeLink(String link) { - String encodedLink; - try { - encodedLink = URLEncoder.encode(link, "UTF-8"); - } catch (UnsupportedEncodingException e) { - logger.log(Level.WARNING, "Why is UTF-8 not known?", e); - encodedLink = link; - } + String encodedLink = ""+link.replace("&", "&")+""; return encodedLink; } From 1c5604be22e6df5907266d3038f93b10e027e37c Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Fri, 15 Jul 2016 20:01:35 +0200 Subject: [PATCH 217/259] fixed message texts for notifications Change-Id: Ie127ea34b58ceb087433b7d6570f3149a0c633c0 --- .../resources/stringmessages/StringMessages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 42b4ed01af8..0a380024413 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -17,7 +17,7 @@ competitorPassesFinishBody=Competitor {0} passed finish line in {1}. See: {2} competitorScoreCorrectionSubject=New results are available for competitor {0} # 0: competitorName, 1: leaderboardDescription, 2: link -boatClassScoreCorrectionBody=New results for competitor {0} in {1} are available. See: {2} +competitorScoreCorrectionBody=New results for competitor {0} in {1} are available. See: {2} boatClassUpcomingRaceSubject=A race for boat class {0} will start soon # 0: boatClassName, 1: raceDescription, 2: time, 3: link From 23615ef97ff9d74d2a5438070db4be21de575045 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 18 Jul 2016 16:17:44 +0200 Subject: [PATCH 218/259] Changes notification mails to use html with styled link buttons --- .../impl/notification-mail-template.html | 27 ++++ .../stringmessages/StringMessages.properties | 26 ++-- .../impl/NotificationMailTemplate.java | 42 ++++++ .../impl/NotificationSetNotification.java | 46 +++++- .../impl/SailingNotificationServiceImpl.java | 139 +++++++++--------- 5 files changed, 192 insertions(+), 88 deletions(-) create mode 100644 java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html new file mode 100644 index 00000000000..e26d3e760bb --- /dev/null +++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html @@ -0,0 +1,27 @@ + + + + ${title} + + + + ${body} + + \ No newline at end of file diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 0a380024413..62d6ddca390 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -2,23 +2,29 @@ raceInRegattaOfEvent=race {0} in regatta {1} of event {2} raceInFleetInRegattaOfEvent={0} ({3}) in regatta {1} of event {2} leaderboardOfEvent=leaderboard {0} of event {1} +leaderboardShowResultsLinkTitle=Show results +racesOverviewLinkTitle=Show races overview +raceboardShowRaceLinkTitle=Show race +raceboardRaceAnalysisLinkTitle=Show race analysis boatClassRaceFinishedSubject=Race for boat class {0} has finished - new results available -# 0: boatClassName, 1: raceDescription, 2: link -boatClassRaceFinishedBody=New results for boat class {0} in {1} are available. See: {2} +# 0: boatClassName, 1: raceDescription +boatClassRaceFinishedBody=New results for boat class {0} in {1} are available. boatClassScoreCorrectionSubject=New results are available for boat class {0} -# 0: boatClassName, 1: leaderboardDescription, 2: link -boatClassScoreCorrectionBody=New results for boat class {0} in {1} are available. See: {2} +# 0: boatClassName, 1: leaderboardDescription +boatClassScoreCorrectionBody=New results for boat class {0} in {1} are available. competitorPassesFinishSubject=Competitor {0} passed finish line in a race -# 0: competitorName, 1: raceDescription, 2: link -competitorPassesFinishBody=Competitor {0} passed finish line in {1}. See: {2} +# 0: competitorName, 1: raceDescription +competitorPassesFinishBody=Competitor {0} passed finish line in {1}. competitorScoreCorrectionSubject=New results are available for competitor {0} -# 0: competitorName, 1: leaderboardDescription, 2: link -competitorScoreCorrectionBody=New results for competitor {0} in {1} are available. See: {2} +# 0: competitorName, 1: leaderboardDescription +competitorScoreCorrectionBody=New results for competitor {0} in {1} are available. boatClassUpcomingRaceSubject=A race for boat class {0} will start soon -# 0: boatClassName, 1: raceDescription, 2: time, 3: link -boatClassUpcomingRaceBody=A race for boat class {0} in {1} will start approximately at {2}. See: {3} +# 0: boatClassName, 1: raceDescription, 2: time +boatClassUpcomingRaceBody=A race for boat class {0} in {1} will start approximately at {2}. + + diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java new file mode 100644 index 00000000000..be88f351ec9 --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java @@ -0,0 +1,42 @@ +package com.sap.sailing.server.notification.impl; + +import java.util.Arrays; + +import com.sap.sse.common.Util.Pair; + +public class NotificationMailTemplate { + + private final String subject; + private final String title; + private final String text; + private final Iterable> labelsAndLinkUrls; + + @SafeVarargs + public NotificationMailTemplate(String subject, String text, Pair... labelsAndLinkUrls) { + this(subject, null, text, labelsAndLinkUrls); + } + + @SafeVarargs + public NotificationMailTemplate(String subject, String title, String text, Pair... labelsAndLinkUrls) { + this.subject = subject; + this.title = title; + this.text = text; + this.labelsAndLinkUrls = Arrays.asList(labelsAndLinkUrls); + } + + public String getSubject() { + return subject; + } + + public String getTitle() { + return title; + } + + public String getText() { + return text; + } + + public Iterable> getLabelsAndLinkUrls() { + return labelsAndLinkUrls; + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java index 8d051707277..91976427a2f 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -1,5 +1,9 @@ package com.sap.sailing.server.notification.impl; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; @@ -9,12 +13,31 @@ import javax.mail.Multipart; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; +import com.sap.sse.common.Util.Pair; import com.sap.sse.mail.MailService; import com.sap.sse.mail.queue.MailNotification; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; public abstract class NotificationSetNotification implements MailNotification { private static final Logger logger = Logger.getLogger(NotificationSetNotification.class.getName()); + + private static final String TEMPLATE_FILE = "notification-mail-template.html"; + private static final String TEMPLATE = loadTemplateFile(); + + private static String loadTemplateFile() { + StringBuilder content = new StringBuilder(); + try (BufferedReader in = new BufferedReader(new InputStreamReader( + NotificationSetNotification.class.getResourceAsStream(TEMPLATE_FILE), StandardCharsets.UTF_8))) { + String line; + while ((line = in.readLine()) != null) { + content.append(line).append("\n"); + } + } catch (IOException exc) { + logger.log(Level.SEVERE, "Error while loading notification mail template!", exc); + } + return content.toString(); + } + private final T objectToNotifyAbout; private final PreferenceObjectBasedNotificationSet associatedNotificationSet; @@ -33,17 +56,30 @@ public abstract class NotificationSetNotification implements MailNotification Multipart multipart = new MimeMultipart(); BodyPart bodyPart = new MimeBodyPart(); try { - bodyPart.setContent(constructBody(objectToNotifyAbout, locale), "text/html"); + NotificationMailTemplate mailTemplate = getMailTemplate(objectToNotifyAbout, locale); + bodyPart.setContent(getMailContent(mailTemplate), "text/html"); multipart.addBodyPart(bodyPart); - mailService.sendMail(user.getEmail(), constructSubject(objectToNotifyAbout, locale), multipart); + mailService.sendMail(user.getEmail(), mailTemplate.getSubject(), multipart); } catch (Exception e) { logger.log(Level.SEVERE, "Could not send mail notification for \"" + objectToNotifyAbout + "\" to user \" + user + \"", e); } }); } + + private String getMailContent(NotificationMailTemplate notificationMailTemplate) { + StringBuilder bodyContent = new StringBuilder(); + if (notificationMailTemplate.getTitle() != null) { + bodyContent.append("

        ").append(notificationMailTemplate.getTitle()).append("

        "); + } + bodyContent.append("

        ").append(notificationMailTemplate.getText()).append("

        "); + for (Pair link : notificationMailTemplate.getLabelsAndLinkUrls()) { + bodyContent.append(""); + bodyContent.append(link.getA()).append(""); + } + return TEMPLATE.replace("${title}", notificationMailTemplate.getSubject()).replace("${body}", bodyContent.toString()); + } + + protected abstract NotificationMailTemplate getMailTemplate(T objectToNotifyAbout, Locale locale); - protected abstract String constructSubject(T objectToNotifyAbout, Locale locale); - - protected abstract String constructBody(T objectToNotifyAbout, Locale locale); } \ No newline at end of file diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 2f60ce3462a..c42fcd7673d 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -173,19 +173,44 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific return messages.get(locale, "leaderboardOfEvent", leaderboardDisplayName, eventName); } - - private String createRaceBoardLink(TrackedRace trackedRace, Leaderboard leaderboard, Event event, - LeaderboardGroup leaderboardGroup) { - RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); - String link = getBaseURL(event).toString() + "/gwt/RaceBoard.html?eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() - + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" - + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" - + raceIdentifier.getRegattaName(); - return link; + + private Pair createRaceBoardShowRaceLink(TrackedRace trackedRace, Leaderboard leaderboard, + Event event, LeaderboardGroup leaderboardGroup, Locale locale) { + return createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup, "PLAYER", + "raceboardShowRaceLinkTitle", locale); } - private String createHomeRacesListLink(Leaderboard leaderboard, Event event) { - return createHomeRegattaLink("races", leaderboard, event); + private Pair createRaceBoardRaceAnalysisLink(TrackedRace trackedRace, Leaderboard leaderboard, + Event event, LeaderboardGroup leaderboardGroup, Locale locale) { + return createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup, "FULL_ANALYSIS", + "raceboardRaceAnalysisLinkTitle", locale); + } + + private Pair createRaceBoardLink(TrackedRace trackedRace, Leaderboard leaderboard, Event event, + LeaderboardGroup leaderboardGroup, String raceboardMode, String labelMessageKey, Locale locale) { + RegattaAndRaceIdentifier raceIdentifier = trackedRace.getRaceIdentifier(); + String link = getBaseURL(event).toString() + "/gwt/RaceBoard.html?locale=" + locale.toLanguageTag() + + "&eventId=" + event.getId() + "&leaderboardName=" + leaderboard.getName() + + "&leaderboardGroupName=" + leaderboardGroup.getName() + "&raceName=" + + raceIdentifier.getRaceName() + "&showMapControls=true&viewShowNavigationPanel=true®attaName=" + + raceIdentifier.getRegattaName() + "&mode=" + raceboardMode; + return new Pair(messages.get(locale, labelMessageKey), link); + } + + private Pair createHomeRacesListLink(Leaderboard leaderboard, Event event, Locale locale) { + return createHomeRegattaLink("races", "racesOverviewLinkTitle", leaderboard, event, locale); + } + + private Pair createHomeLeaderboardLink(Leaderboard leaderboard, Event event, + Locale locale) { + return createHomeRegattaLink("leaderboard", "leaderboardShowResultsLinkTitle", leaderboard, event, locale); + } + + private Pair createHomeRegattaLink(String tab, String labelMessageKey, Leaderboard leaderboard, + Event event, Locale locale) { + String link = getBaseURL(event).toString() + "/gwt/Home.html?locale=" + locale.toLanguageTag() + + "#/regatta/" + tab + "/:eventId=" + event.getId() + "®attaId=" + leaderboard.getName(); + return new Pair(messages.get(locale, labelMessageKey), link); } /** @@ -201,34 +226,21 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific } return result; } - - private String createHomeLeaderboardLink(Leaderboard leaderboard, Event event) { - return createHomeRegattaLink("leaderboard", leaderboard, event); - } - - private String createHomeRegattaLink(String tab, Leaderboard leaderboard, Event event) { - String link = getBaseURL(event).toString() + "/gwt/Home.html#/regatta/" + tab + "/:eventId=" + event.getId() + "®attaId=" - + leaderboard.getName(); - return link; - } @Override public void notifyUserOnBoatClassRaceChangesStateToFinished(BoatClass boatClass, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - String link = createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup); - mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { + @Override - protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassRaceFinishedSubject", boatClass.getDisplayName()); - } - - @Override - protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); - return messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(), - raceDescription, encodeLink(link)); + return new NotificationMailTemplate( + messages.get(locale, "boatClassRaceFinishedSubject", boatClass.getDisplayName()), + messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(), raceDescription), + createRaceBoardShowRaceLink(trackedRace, leaderboard, event, leaderboardGroup, locale), + createRaceBoardRaceAnalysisLink(trackedRace, leaderboard, event, leaderboardGroup, locale)); } }); }); @@ -238,19 +250,15 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific public void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard) { // TODO don't send notifications when a notification for the same boatClass / leaderboard has already been sent shortly before doWithEvent(leaderboard, (event, leaderboardGroup) -> { - String link = createHomeLeaderboardLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassResults) { @Override - protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassScoreCorrectionSubject", boatClass.getDisplayName()); - } - - @Override - protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) { String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); - return messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(), - leaderboardDescription, encodeLink(link)); + return new NotificationMailTemplate( + messages.get(locale, "boatClassScoreCorrectionSubject", boatClass.getDisplayName()), + messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(), leaderboardDescription), + createHomeLeaderboardLink(leaderboard, event, locale)); } }); }); @@ -259,49 +267,37 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet, TimePoint when) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - String link = createHomeRacesListLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) { @Override - protected String constructSubject(BoatClass objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName()); - } - - @Override - protected String constructBody(BoatClass objectToNotifyAbout, Locale locale) { + protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); // TODO properly format time in the user's locale String time = when.toString(); - return messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), - raceDescription, time, encodeLink(link)); + return new NotificationMailTemplate( + messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName()), + messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), + raceDescription, time), + createHomeRacesListLink(leaderboard, event, locale)); } }); }); } - - private String encodeLink(String link) { - String encodedLink = ""+link.replace("&", "&")+""; - return encodedLink; - } - @Override public void notifyUserOnCompetitorPassesFinish(Competitor competitor, TrackedRace trackedRace, Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - String link = createRaceBoardLink(trackedRace, leaderboard, event, leaderboardGroup); mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { @Override - protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) { - return messages.get(locale, "competitorPassesFinishSubject", competitor.getName()); - } - - @Override - protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { + protected NotificationMailTemplate getMailTemplate(Competitor objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); - return messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription, - encodeLink(link)); + return new NotificationMailTemplate( + messages.get(locale, "competitorPassesFinishSubject", competitor.getName()), + messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription), + createRaceBoardShowRaceLink(trackedRace, leaderboard, event, leaderboardGroup, locale), + createRaceBoardRaceAnalysisLink(trackedRace, leaderboard, event, leaderboardGroup, locale)); } }); }); @@ -310,19 +306,16 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific @Override public void notifyUserOnCompetitorScoreCorrections(Competitor competitor, Leaderboard leaderboard) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { - String link = createHomeLeaderboardLink(leaderboard, event); mailQueue.addNotification(new NotificationSetNotification(competitor, competitorResults) { @Override - protected String constructSubject(Competitor objectToNotifyAbout, Locale locale) { - return messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()); - } - - @Override - protected String constructBody(Competitor objectToNotifyAbout, Locale locale) { + protected NotificationMailTemplate getMailTemplate(Competitor objectToNotifyAbout, Locale locale) { String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); - return messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), - leaderboardDescription, encodeLink(link)); + return new NotificationMailTemplate( + messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()), + messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), leaderboardDescription), + createHomeLeaderboardLink(leaderboard, event, locale), + createHomeLeaderboardLink(leaderboard, event, locale)); } }); }); From 8c4841969a8c6b6839e133144bcb63352fa24cdb Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 18 Jul 2016 16:53:19 +0200 Subject: [PATCH 219/259] Added german translations for notification mails --- .../stringmessages/StringMessages.properties | 10 +++---- .../StringMessages_de.properties | 28 +++++++++++++++++++ .../impl/SailingNotificationServiceImpl.java | 1 - 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 62d6ddca390..77551173dee 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -1,7 +1,7 @@ -raceInRegattaOfEvent=race {0} in regatta {1} of event {2} -raceInFleetInRegattaOfEvent={0} ({3}) in regatta {1} of event {2} +raceInRegattaOfEvent=race {0} in regatta '{1}' of event '{2}' +raceInFleetInRegattaOfEvent=race {0} ({3}) in regatta '{1}' of event '{2}' +leaderboardOfEvent=leaderboard '{0}' of event '{1}' -leaderboardOfEvent=leaderboard {0} of event {1} leaderboardShowResultsLinkTitle=Show results racesOverviewLinkTitle=Show races overview raceboardShowRaceLinkTitle=Show race @@ -25,6 +25,4 @@ competitorScoreCorrectionBody=New results for competitor {0} in {1} are availabl boatClassUpcomingRaceSubject=A race for boat class {0} will start soon # 0: boatClassName, 1: raceDescription, 2: time -boatClassUpcomingRaceBody=A race for boat class {0} in {1} will start approximately at {2}. - - +boatClassUpcomingRaceBody=For boat class {0} {1} will start approximately at {2}. diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties index e69de29bb2d..ed499b011df 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties @@ -0,0 +1,28 @@ +raceInRegattaOfEvent=Wettfahrt {0} der Regatta "{1}" bei Veranstaltung "{2}" +raceInFleetInRegattaOfEvent=Wettfahrt {0} ({3}) der Regatta "{1}" bei Veranstaltung "{2}" +leaderboardOfEvent=Rangliste "{0}" bei Veranstaltung "{1}" + +leaderboardShowResultsLinkTitle=Ergebnisse anzeigen +racesOverviewLinkTitle=Wettfahrtübersicht anzeigen +raceboardShowRaceLinkTitle=Wettfahrt anzeigen +raceboardRaceAnalysisLinkTitle=Wettfahrtanalyse anzeigen + +boatClassRaceFinishedSubject=Wettfahrt für Bootsklasse {0} beendet - Neue Ergebnisse verfügbar +# 0: boatClassName, 1: raceDescription +boatClassRaceFinishedBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. + +boatClassScoreCorrectionSubject=Neue Ergebnisse für Bootsklasse {0} verfügbar +# 0: boatClassName, 1: leaderboardDescription +boatClassScoreCorrectionBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. + +competitorPassesFinishSubject=Teilnehmer {0} hat eine Wettfahrt beendet +# 0: competitorName, 1: raceDescription +competitorPassesFinishBody=Teilnehmer {0} hat bei {1} die Ziellinie überquert. + +competitorScoreCorrectionSubject=Neue Ergebnisse für Teilnehmer {0} +# 0: competitorName, 1: leaderboardDescription +competitorScoreCorrectionBody=Für Teilnehmer {0} in {1} sind neue Ergebnisse verfügbar. + +boatClassUpcomingRaceSubject=Wettfahrt in Bootsklasse {0} startet bald +# 0: boatClassName, 1: raceDescription, 2: time +boatClassUpcomingRaceBody=In Bootsklasse {0} startet {1} um etwa {2}. diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index c42fcd7673d..22e207a14b0 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -314,7 +314,6 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific return new NotificationMailTemplate( messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()), messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), leaderboardDescription), - createHomeLeaderboardLink(leaderboard, event, locale), createHomeLeaderboardLink(leaderboard, event, locale)); } }); From 862159a19bd63f2f65a8ec6b1acd331a0d9ae715 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Mon, 18 Jul 2016 16:58:32 +0200 Subject: [PATCH 220/259] Fixed typo in StringMessages --- .../sap/sse/security/ui/client/i18n/StringMessages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties index f4ebe2897bd..2fb3130c411 100644 --- a/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties +++ b/java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties @@ -45,7 +45,7 @@ errorUpdatingPermissions=Error updating permissions for user {0}: {1} enterRoleName=Enter role name... enterPermissionName=Enter permission name... errorCreatingUser=Error signing up with username {0}: {1} -signedUpSuccessfully=Successfully signed up user {0}. Please check you e-mails to validate your e-mail account. +signedUpSuccessfully=Successfully signed up user {0}. Please check your e-mails to validate your e-mail account. unknownErrorCreatingUser=Unknown error trying to sign up user with name {0}. Perhaps another user with that name already exists. userAlreadyExists=A user with name {0} already exists currentPassword=Current password From 6e103ffb68c611e5a62900c1af0fa2c66f92e8be Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 08:12:38 +0200 Subject: [PATCH 221/259] Added some release notes regarding user preferences and notifications --- .../gwt/home/solutions/SailingAnalyticsNotes.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html index 575337869d0..9c2d734a939 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html @@ -25,6 +25,15 @@ +
      • On the user profile page you now can maintain a list of you favorite boat classes and competitors. + You can also opt in for notification mails about your favorites to stay informed. + A requirement for notification mails to work for you is that you entered a valid mail address + to your user profile and verified the address by clicking the link that has been sent via email. +
      • +
      • Users now may choose their preferred language on the user profile page. + Currently only the mail notification mechanism will accept this setting to send mails in the preferred language. + The website will not automatically switch to the preferred language when logged in. +
      • The leaderboard now has a new measure value called "Ride height", which shows the ride height on foils of a competitor, if respective data is available (currently ESS only). This information can also be shown in the competitor chart on the RaceBaord page. From e064e858f24d64e21e7bed995274a18a918a63e2 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 19 Jul 2016 09:31:27 +0200 Subject: [PATCH 222/259] Slightly adjusted release notes regarding user prefs and notifications --- .../sailing/gwt/home/solutions/SailingAnalyticsNotes.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html index 9c2d734a939..4b161402ab6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html +++ b/java/com.sap.sailing.gwt.ui/src/main/resources/com/sap/sailing/gwt/home/solutions/SailingAnalyticsNotes.html @@ -31,8 +31,9 @@ to your user profile and verified the address by clicking the link that has been sent via email.
      • Users now may choose their preferred language on the user profile page. - Currently only the mail notification mechanism will accept this setting to send mails in the preferred language. - The website will not automatically switch to the preferred language when logged in. + Currently only the mail notification mechanism will accept this setting to send mails in the preferred + language. This also prepares additional language sensitive feature, e.g. automatically switching the + website to your preferred language when logged in.
      • The leaderboard now has a new measure value called "Ride height", which shows the ride height on foils of a competitor, if respective data is available (currently ESS only). This information can From 00d0a74c51b4fc96b4a4b76496823d57de48acc3 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 09:23:42 +0200 Subject: [PATCH 223/259] Removed Util.equals where we are sure that the returned collection types are equal so that a simple assertEquals will work --- .../test/PreferenceObjectBasedNotificationSetTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 1494f36f063..f53c1a5da38 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -179,7 +179,7 @@ public class PreferenceObjectBasedNotificationSetTest { UserConsumerMock mock = new UserConsumerMock(); notificationSet.forUsersWithVerifiedEmailMappedTo(A, mock); - Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); + Assert.assertEquals(users(store.getUserByName(user1)), mock.calls); } @Test @@ -206,11 +206,11 @@ public class PreferenceObjectBasedNotificationSetTest { UserConsumerMock mock = new UserConsumerMock(); notificationSet.forUsersWithVerifiedEmailMappedTo(A, mock); - Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); + Assert.assertEquals(users(store.getUserByName(user1)), mock.calls); mock = new UserConsumerMock(); notificationSet.forUsersWithVerifiedEmailMappedTo(B, mock); - Assert.assertTrue(Util.equals(users(store.getUserByName(user1), store.getUserByName(user2)), mock.calls)); + Assert.assertEquals(users(store.getUserByName(user1), store.getUserByName(user2)), mock.calls); } @Test @@ -223,7 +223,7 @@ public class PreferenceObjectBasedNotificationSetTest { UserConsumerMock mock = new UserConsumerMock(); notificationSet.forUsersWithVerifiedEmailMappedTo(B, mock); - Assert.assertTrue(Util.equals(users(store.getUserByName(user1)), mock.calls)); + Assert.assertEquals(users(store.getUserByName(user1)), mock.calls); } /** From 6e9aa7d8154320815054581e7956a5a0ff8ba3f1 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 09:24:42 +0200 Subject: [PATCH 224/259] Added missing final modifier --- .../security/test/PreferenceObjectBasedNotificationSetTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index f53c1a5da38..fff26a746c6 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -279,7 +279,7 @@ public class PreferenceObjectBasedNotificationSetTest { } private static class UserConsumerMock implements Consumer { - HashSet calls = new HashSet<>(); + final HashSet calls = new HashSet<>(); @Override public void accept(User user) { From 2db23155db20a5c5b050ad9e3a9897bacb987443 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 09:33:11 +0200 Subject: [PATCH 225/259] Using Collection.isEmpty instead of Util.isEmpty --- .../security/test/PreferenceObjectBasedNotificationSetTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index fff26a746c6..9f7a0febc91 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -192,7 +192,7 @@ public class PreferenceObjectBasedNotificationSetTest { UserConsumerMock mock = new UserConsumerMock(); notificationSet.forUsersWithVerifiedEmailMappedTo(A, mock); - Assert.assertTrue(Util.isEmpty(mock.calls)); + Assert.assertTrue(mock.calls.isEmpty()); } @Test From 623c939d13d4432eb8064c8cc402b419a8f87cea Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 09:37:52 +0200 Subject: [PATCH 226/259] Removed unnecessary duplicate drop of PREFERENCES DB collection for tests --- .../src/com/sap/sse/security/test/LoginTest.java | 1 - .../security/test/PreferenceObjectBasedNotificationSetTest.java | 1 - 2 files changed, 2 deletions(-) diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/LoginTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/LoginTest.java index 9229f35686b..951aaa8a636 100755 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/LoginTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/LoginTest.java @@ -34,7 +34,6 @@ public class LoginTest { db.getCollection(CollectionNames.USERS.name()).drop(); db.getCollection(CollectionNames.SETTINGS.name()).drop(); db.getCollection(CollectionNames.PREFERENCES.name()).drop(); - db.getCollection(CollectionNames.PREFERENCES.name()).drop(); store = new UserStoreImpl(); UsernamePasswordRealm.setTestUserStore(store); Activator.setTestUserStore(store); diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java index 9f7a0febc91..cd9ca899c9d 100644 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java @@ -51,7 +51,6 @@ public class PreferenceObjectBasedNotificationSetTest { db.getCollection(CollectionNames.USERS.name()).drop(); db.getCollection(CollectionNames.SETTINGS.name()).drop(); db.getCollection(CollectionNames.PREFERENCES.name()).drop(); - db.getCollection(CollectionNames.PREFERENCES.name()).drop(); store = new UserStoreImpl(); } From 2ea3eb678339c7ab299e98361b3ac57cec25ba3c Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 19 Jul 2016 09:42:17 +0200 Subject: [PATCH 227/259] Added sailing server i18n StringMessages to translation.json --- translation.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/translation.json b/translation.json index f93605340e1..d4abdbd2164 100644 --- a/translation.json +++ b/translation.json @@ -110,6 +110,20 @@ "pseudoLocFolderPath":"." } ] + }, + { + "collectionName":"SailingServer", + "folders":[ + { + "sourceFolderPath":"java/com.sap.sailing.server/resources/stringmessages", + "sourceFilters":[ + "StringMessages*.properties" + ], + "xlfFolderPath":"./XLF", + "targetFolderPath":".", + "pseudoLocFolderPath":"." + } + ] } ] } From fc56bd059e6f73bc5f0678b7ee3f3d1943aa895b Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 10:00:36 +0200 Subject: [PATCH 228/259] Using proper DateFormat for upcoming race notification --- .../notification/impl/SailingNotificationServiceImpl.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 22e207a14b0..9a61b47cf97 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -2,6 +2,7 @@ package com.sap.sailing.server.notification.impl; import java.net.MalformedURLException; import java.net.URL; +import java.text.DateFormat; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Locale; @@ -265,15 +266,15 @@ public class SailingNotificationServiceImpl implements Stoppable, SailingNotific } public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, Leaderboard leaderboard, RaceColumn raceColumn, - Fleet fleet, TimePoint when) { + Fleet fleet, TimePoint when) { doWithEvent(leaderboard, (event, leaderboardGroup) -> { mailQueue.addNotification(new NotificationSetNotification(boatClass, boatClassUpcomingRace) { @Override protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); - // TODO properly format time in the user's locale - String time = when.toString(); + String time = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale) + .format(when.asDate()); return new NotificationMailTemplate( messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName()), messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), From 52eea75f26f2677b529a3071de7b85a3c850d8c9 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Tue, 19 Jul 2016 11:19:36 +0200 Subject: [PATCH 229/259] Slightly adjustments to notification mail template --- .../impl/notification-mail-template.html | 44 +++++++++++-------- .../impl/NotificationSetNotification.java | 6 +-- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html index e26d3e760bb..7f23cb6f298 100644 --- a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html +++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html @@ -1,25 +1,31 @@ - ${title} - + ${title} + ${body} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java index 91976427a2f..5a5c50d4c00 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -72,10 +72,10 @@ public abstract class NotificationSetNotification implements MailNotification if (notificationMailTemplate.getTitle() != null) { bodyContent.append("

        ").append(notificationMailTemplate.getTitle()).append("

        "); } - bodyContent.append("

        ").append(notificationMailTemplate.getText()).append("

        "); + bodyContent.append("

        ").append(notificationMailTemplate.getText()).append("

        "); for (Pair link : notificationMailTemplate.getLabelsAndLinkUrls()) { - bodyContent.append(""); - bodyContent.append(link.getA()).append(""); + bodyContent.append("
        ").append("").append(link.getA()).append("").append("
        "); } return TEMPLATE.replace("${title}", notificationMailTemplate.getSubject()).replace("${body}", bodyContent.toString()); } From 8e59b48216bbc4068d0703977c4b4cdc8242476d Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 11:24:20 +0200 Subject: [PATCH 230/259] Listeners aren't cleared anymore when clearing UserStore, but all listeners are informed about removal of all preference objects. --- .../userstore/mongodb/UserStoreImpl.java | 19 +++++++++++++++++-- .../src/com/sap/sse/security/UserStore.java | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java index bc6ec42abe6..25a4d428111 100644 --- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java +++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java @@ -153,10 +153,9 @@ public class UserStoreImpl implements UserStore { @Override public void clear() { - listeners.clear(); preferences.clear(); preferenceConverters.clear(); - preferenceObjects.clear(); + clearAllPreferenceObjects(); emailForUsername.clear(); settings.clear(); settingTypes.clear(); @@ -165,6 +164,18 @@ public class UserStoreImpl implements UserStore { usersByAccessToken.clear(); } + /** + * Preference objects can't be simply removed by clearing {@link #preferenceObjects} because listeners can have a + * state depending on the current preference objects. So we need to notify all listeners about the removal of the + * notification objects. + */ + private void clearAllPreferenceObjects() { + final Set usersToProcess = new HashSet<>(preferences.keySet()); + for (String username : usersToProcess) { + removeAllPreferenceObjectsForUser(username); + } + } + @Override public void replaceContentsFrom(UserStore newUserStore) { clear(); @@ -524,6 +535,10 @@ public class UserStoreImpl implements UserStore { if (mongoObjectFactory != null) { mongoObjectFactory.storePreferences(username, Collections.emptyMap()); } + removeAllPreferenceObjectsForUser(username); + } + + private void removeAllPreferenceObjectsForUser(String username) { Map preferenceObjectsToRemove; synchronized (preferenceObjects) { preferenceObjectsToRemove = preferenceObjects.remove(username); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index 74583ff2954..c3db04ee4ca 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -130,6 +130,7 @@ public interface UserStore extends Named { /** * Removes all users and all their preferences and all settings from this store's in-memory representation. * For safety reasons and because a replica's DB state is undefined anyhow, leaves persistent content in place. + * Registered listeners will not be removed automatically. * Use with due care. */ void clear(); From afa59fd1ced3a736f8ef4de1cb3249c9b29ca220 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 11:31:49 +0200 Subject: [PATCH 231/259] SailingNotificationService is now being stopped when RacingEventService changes to replication state. In addition, an empty implementation of SailingNotificationService is used to ensure that notification mails will never be send on a replica. --- .../server/impl/RacingEventServiceImpl.java | 5 ++- .../EmptySailingNotificationService.java | 39 +++++++++++++++++++ .../SailingNotificationService.java | 3 +- .../impl/SailingNotificationServiceImpl.java | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 java/com.sap.sailing.server/src/com/sap/sailing/server/notification/EmptySailingNotificationService.java 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 1b0a2bd44f2..168564fa3d9 100644 --- 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 @@ -180,6 +180,7 @@ import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJ import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardSearchResultBaseJsonDeserializer; import com.sap.sailing.server.gateway.deserialization.impl.VenueJsonDeserializer; import com.sap.sailing.server.masterdata.DataImportLockWithProgress; +import com.sap.sailing.server.notification.EmptySailingNotificationService; import com.sap.sailing.server.notification.SailingNotificationService; import com.sap.sailing.server.operationaltransformation.AddCourseAreas; import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta; @@ -405,7 +406,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes * Replicas are expected to not notify users about anything, particularly because they usually don't * have a valid mail service, either. */ - private transient final SailingNotificationService notificationService; + private transient SailingNotificationService notificationService; /** * Allow only one master data import at a time to avoid situation where multiple Imports override each other in @@ -2863,6 +2864,8 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes mediaLibrary.clear(); competitorStore.clear(); remoteSailingServerSet.clear(); + notificationService.stop(); + notificationService = new EmptySailingNotificationService(); } // Used for TESTING only diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/EmptySailingNotificationService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/EmptySailingNotificationService.java new file mode 100644 index 00000000000..d34b6bd283d --- /dev/null +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/EmptySailingNotificationService.java @@ -0,0 +1,39 @@ +package com.sap.sailing.server.notification; + +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sse.common.TimePoint; + +public class EmptySailingNotificationService implements SailingNotificationService { + + @Override + public void stop() { + } + + @Override + public void notifyUserOnBoatClassRaceChangesStateToFinished(BoatClass boatClass, TrackedRace trackedRace, + Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { + } + + @Override + public void notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable(BoatClass boatClass, Leaderboard leaderboard) { + } + + @Override + public void notifyUserOnBoatClassUpcomingRace(BoatClass boatClass, Leaderboard leaderboard, RaceColumn raceColumn, + Fleet fleet, TimePoint when) { + } + + @Override + public void notifyUserOnCompetitorPassesFinish(Competitor competitor, TrackedRace trackedRace, + Leaderboard leaderboard, RaceColumn raceColumn, Fleet fleet) { + } + + @Override + public void notifyUserOnCompetitorScoreCorrections(Competitor competitor, Leaderboard leaderboard) { + } +} diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java index acd48c15a88..f3410aed607 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/SailingNotificationService.java @@ -7,9 +7,10 @@ import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sse.common.Stoppable; import com.sap.sse.common.TimePoint; -public interface SailingNotificationService { +public interface SailingNotificationService extends Stoppable { /** * Called when {@link RaceState} changes state to finished. diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index 9a61b47cf97..a1b6020d724 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -36,7 +36,7 @@ import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl; import com.sap.sse.mail.queue.MailQueue; import com.sap.sse.security.UserStore; -public class SailingNotificationServiceImpl implements Stoppable, SailingNotificationService { +public class SailingNotificationServiceImpl implements SailingNotificationService { private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/StringMessages"; private static final Logger logger = Logger.getLogger(SailingNotificationServiceImpl.class.getName()); From a6bb1d2d7dd1219db6c91208fc095a7fc5ee103e Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 19 Jul 2016 13:27:39 +0200 Subject: [PATCH 232/259] avoid creating threads for notifications; use existing scheduler in RacingEventServiceImpl instead Change-Id: I2e590a285139294bbeb918dbedb5cea5f2c01905 --- .../server/impl/RacingEventServiceImpl.java | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) 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 168564fa3d9..d8d01f25ef6 100644 --- 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 @@ -1675,10 +1675,9 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes private void notifyForLeaderboardIfNotAlreadyNotifiedRecently() { final TimePoint now = MillisecondsTimePoint.now(); if (notificationService != null && (lastNotificationForLeaderboard == null || - lastNotificationForLeaderboard.until(now).compareTo(HOW_LONG_BETWEEN_TWO_NOTIFICATIONS_FOR_SIMILAR_EVENT) >= 0)) { - new Thread(()->notificationService.notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable( - leaderboard.getBoatClass(), leaderboard), - "Score correction notifier for leaderboard "+leaderboard.getName()).start(); + lastNotificationForLeaderboard.until(now).compareTo(HOW_LONG_BETWEEN_TWO_NOTIFICATIONS_FOR_SIMILAR_EVENT) >= 0)) { + scheduler.execute(()->notificationService.notifyUserOnBoatClassWhenScoreCorrectionsAreAvailable( + leaderboard.getBoatClass(), leaderboard)); lastNotificationForLeaderboard = now; } } @@ -1692,9 +1691,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes final TimePoint now = MillisecondsTimePoint.now(); if (notificationService != null && (!lastNotificationForCompetitor.containsKey(competitor) || lastNotificationForCompetitor.get(competitor).until(now).compareTo(HOW_LONG_BETWEEN_TWO_NOTIFICATIONS_FOR_SIMILAR_EVENT) >= 0)) { - new Thread(()->notificationService.notifyUserOnCompetitorScoreCorrections(competitor, leaderboard), - "Score correction notifier for competitor "+competitor.getName()+" in leaderboard "+ - leaderboard.getName()).start(); + scheduler.execute(()->notificationService.notifyUserOnCompetitorScoreCorrections(competitor, leaderboard)); lastNotificationForCompetitor.put(competitor, now); } // a change to a single competitor also means a change to the leaderboard @@ -1772,11 +1769,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes // see raceTimesChanged(TimePoint, TimePoint, TimePoint). if (newStartOfRace != null && newStartOfRace.after(MillisecondsTimePoint.now())) { - new Thread(()-> - // Notify interested users if the new start time is in the future - notificationService.notifyUserOnBoatClassUpcomingRace(trackedRace.getRace().getBoatClass(), - getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet(), newStartOfRace), - "Notifier about startOfRaceChanged for "+trackedRace).start(); + scheduler.execute(()-> + // Notify interested users if the new start time is in the future + notificationService.notifyUserOnBoatClassUpcomingRace(trackedRace.getRace().getBoatClass(), + getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet(), newStartOfRace)); } } @@ -1785,11 +1781,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes // no action required; the update signaled by this call is implicit; the race log // updates that led to this change are replicated separately - new Thread(()-> - // Notify interested users: - notificationService.notifyUserOnBoatClassRaceChangesStateToFinished(trackedRace.getRace().getBoatClass(), trackedRace, - getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet()), - "Notifier about finishedTimeChanged for "+trackedRace).start(); + scheduler.execute(()-> + // Notify interested users: + notificationService.notifyUserOnBoatClassRaceChangesStateToFinished(trackedRace.getRace().getBoatClass(), trackedRace, + getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet())); } @Override @@ -1850,10 +1845,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes final MarkPassing last = Util.last(markPassings); if (last != null && last.getWaypoint() == trackedRace.getRace().getCourse().getLastWaypoint() && trackedRace.getStatus().getStatus() != TrackedRaceStatusEnum.LOADING) { - new Thread(()-> - // Notify interested users: - notificationService.notifyUserOnCompetitorPassesFinish(competitor, trackedRace, getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet()), - "Notifier about finish waypoing passed for "+trackedRace).start(); + scheduler.execute(() -> + // Notify interested users: + notificationService.notifyUserOnCompetitorPassesFinish(competitor, trackedRace, + getMostAppropriateLeaderboard(), getMostAppropriateRaceColumn(), getMostAppropriateFleet())); } } From 70d54ffaf4ed649da39b8c3ea4f7b30ef0f66560 Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Tue, 19 Jul 2016 14:14:06 +0200 Subject: [PATCH 233/259] Fixed a bug that caused the suggest box to not show all entries when logging out and logging in as another user --- .../AbstractSuggestedMultiSelectionDataProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionDataProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionDataProvider.java index fb7408df036..22ab4f5a5c2 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionDataProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/home/shared/partials/multiselection/AbstractSuggestedMultiSelectionDataProvider.java @@ -54,6 +54,7 @@ public abstract class AbstractSuggestedMultiSelectionDataProvider selectedItems) { + selectedItemsMap.clear(); for (T item : selectedItems) { selectedItemsMap.put(getKey(item), item); } From fc3138380990790b5880104502279bb77b5f8e8f Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 19 Jul 2016 16:08:37 +0200 Subject: [PATCH 234/259] renamed parameter Change-Id: I02e35cbe8c2e8ba19ecff8128f8c34bd3e94679c --- .../preferences/model/CompetitorNotificationPreferences.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java index 0f563918abf..5fa160f0490 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/preferences/model/CompetitorNotificationPreferences.java @@ -29,7 +29,7 @@ public class CompetitorNotificationPreferences extends AbstractGenericSerializab return competitors.getValues(); } - public void setCompetitors(Iterable boatClasses) { - this.competitors.setValues(boatClasses); + public void setCompetitors(Iterable competitors) { + this.competitors.setValues(competitors); } } From ee8d0bbe364deb590273098feb00951366112a4d Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 19 Jul 2016 16:09:10 +0200 Subject: [PATCH 235/259] fixed notification message for competitor score correction Change-Id: I334d470d3a4a10f793a979a5aa74e8a4d26d32e6 --- .../notification/impl/SailingNotificationServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index a1b6020d724..07036d8b1cc 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -313,8 +313,8 @@ public class SailingNotificationServiceImpl implements SailingNotificationServic protected NotificationMailTemplate getMailTemplate(Competitor objectToNotifyAbout, Locale locale) { String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); return new NotificationMailTemplate( - messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()), - messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), leaderboardDescription), + messages.get(locale, "competitorScoreCorrectionSubject", competitor.getName()), + messages.get(locale, "competitorScoreCorrectionBody", competitor.getName(), leaderboardDescription), createHomeLeaderboardLink(leaderboard, event, locale)); } }); From 1d9dd796a0bab5704f888eee94d6ff9c2b90dcf9 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 19 Jul 2016 16:09:27 +0200 Subject: [PATCH 236/259] added some Javadoc to User methods Change-Id: I10a6a550dd61cad9b6aa72f71fdf31fcc5ca00cd --- .../src/com/sap/sse/security/UserStore.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java index c3db04ee4ca..5fbe8618b17 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java @@ -11,8 +11,14 @@ import com.sap.sse.security.shared.UserManagementException; public interface UserStore extends Named { Iterable getUsers(); + /** + * The user with that {@link User#getName() name} or {@code null} if no such user exists + */ User getUserByName(String name); + /** + * The user with that {@link User#getEmail() email} or {@code null} if no such user exists + */ User getUserByEmail(String email); User getUserByAccessToken(String accessToken); From 7207e2edcb34e3528190795dac8b63a338eab688 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 19 Jul 2016 16:27:05 +0200 Subject: [PATCH 237/259] whitespace changes only Change-Id: Ied1d1f84ed21153c57f803836a6655bbf335f819 --- .../src/com/sap/sailing/server/impl/Activator.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java index 8695253dc8c..62ba19f87c4 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/Activator.java @@ -138,9 +138,7 @@ public class Activator implements BundleActivator { properties.put(TypeBasedServiceFinder.TYPE, DoubleVectorFixImpl.class.getName()); registrations.add(context.registerService(FixMongoHandler.class, new DoubleVectorFixMongoHandlerImpl( racingEventService.getMongoObjectFactory(), racingEventService.getDomainObjectFactory()), properties)); - registerPreferenceConvertersForUserStore(context); - // Add an MBean for the service to the JMX bean server: RacingEventServiceMXBean mbean = new RacingEventServiceMXBeanImpl(racingEventService); MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); From 5df840c0d4661b33739fe0124717620f3e73c0f5 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Tue, 19 Jul 2016 16:27:47 +0200 Subject: [PATCH 238/259] made user store variable final in Activator Change-Id: I0d5119b0e78809ecbfc1c22a7a942361355364e9 --- .../SailingServer (Proxy, Remote Debug SAP VM).launch | 2 +- .../src/com/sap/sse/security/impl/Activator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch index 236f0b4e8b4..c902bdcac5c 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, Remote Debug SAP VM).launch @@ -17,7 +17,7 @@ - + diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/impl/Activator.java b/java/com.sap.sse.security/src/com/sap/sse/security/impl/Activator.java index a4e6375a4e3..8d9cf45c929 100755 --- a/java/com.sap.sse.security/src/com/sap/sse/security/impl/Activator.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/impl/Activator.java @@ -88,7 +88,7 @@ public class Activator implements BundleActivator { try { Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); // ensure that classpath:... Shiro ini files are resolved properly logger.info("Waiting for UserStore service..."); - UserStore userStore = tracker.waitForService(0); + final UserStore userStore = tracker.waitForService(0); logger.info("Obtained UserStore service "+userStore); createAndRegisterSecurityService(bundleContext, userStore); } catch (InterruptedException e) { From aade87ce946f32a76e9dea18d55104077ae21539 Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Tue, 19 Jul 2016 17:55:36 +0200 Subject: [PATCH 239/259] Added sapsailing site look and feel to html mail --- .../META-INF/MANIFEST.MF | 1 + .../impl/notification-mail-template.html | 119 +++++++++++++----- .../notification/impl/sap_logo_header.png | Bin 0 -> 6388 bytes .../stringmessages/StringMessages.properties | 5 + .../StringMessages_de.properties | 21 ++-- .../impl/NotificationMailTemplate.java | 15 ++- .../impl/NotificationSetNotification.java | 66 +++++++++- .../impl/SailingNotificationServiceImpl.java | 24 ++-- 8 files changed, 198 insertions(+), 53 deletions(-) create mode 100644 java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/sap_logo_header.png diff --git a/java/com.sap.sailing.server/META-INF/MANIFEST.MF b/java/com.sap.sailing.server/META-INF/MANIFEST.MF index 49cc7c75671..29807ffc25f 100644 --- a/java/com.sap.sailing.server/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server/META-INF/MANIFEST.MF @@ -9,6 +9,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.sap.sailing.server.gateway.deserialization, javax.mail;version="1.4.0", javax.mail.internet;version="1.4.0", + javax.mail.util;version="1.4.0", org.json.simple, org.json.simple.parser, org.osgi.framework;version="1.3.0", diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html index 7f23cb6f298..71b061fcd10 100644 --- a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html +++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html @@ -1,33 +1,92 @@ - - ${title} - - - - ${body} - + + ${title} + + + +
        +
        +
        + Sailing Analytics +
        +
        + ${content} +
        +
        + +
        + \ No newline at end of file diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/sap_logo_header.png b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/sap_logo_header.png new file mode 100644 index 0000000000000000000000000000000000000000..e5d2daf91f3962deb5be2991141b8145186e982a GIT binary patch literal 6388 zcmaJ`XEFme0zU;pC9Kt>$=ujZ@KULdEWQAulL7V3FfBybkv;G004l_&_LJX;{EjE zHm9Vxc={Hz{h7Fm(X+#x|7u;@nFUSvrstewgH<2+x>9~2q z3_{Ruw?j-VT|>NGm7#(V4SuyCl?ws58^)PG2=0UMQwdTR{7YBmqWxzWD9Ha81mmqP z_^+g_P0aaqkZ3o4d1;yJt}+TBeg!#ckerONoU#-@SOz2m1c8Aviq}ChD)NddG9dnc zUxF9W&`@_33*8(4j&;#f7xctnP%1!RU|^thpsX|!?EwTSD=PzKz(6qg`UT>;UoZmW z9CRJwC-k?1uA84L8ivBakO=-iiq0-be~h}|MW+8+0vz=pS%lxex9MWTfI-eEAV^x~ z&yxNInwb3mP&oWQXg`dF+kf-@KZX4)gHdik3pYQcKic)8aPC5XLZMW2&~DBcB-#>* z^!a-i%{`GAq@O1e#jkT)UK+%2;_M1T{2BR+VPc|Ui15QWBV64Kb=3tgG^AlLsEVGf z0$2g8Cx1g3tOEk+$!aO-%IPYD!7^H4J!LK38-H_kk*@x5Hw5NyF7&@#g@5G!F#{ZR z5n0y_4GVCC-asSa{C_Q41@_Om$o`|=zq!zV&PDDYxxkBLfPYH+ze@f0(1m~gH2-7V zi_U+n?}oVWJNm-dj$Dqf001_3LtQP)pot9!sw~Tq+_RaNZ(hC(ar6u!vmw89YuJ|r zUvZ5z%3DDUlptng3fA`+*foBv5SR10A1^EFp!0l(+kI&4x#aO~m8WkB?Cy}IC zvp+L(XWGG`FaP{~&AXP6nnSPB;PZKlHp{la?CtRL--w%IW4^4K^t2%1UxK$}b4B#T zOM&*?_c<~!w>aWHxVpz^hr24!8m6Df3a=X0vsyfSAtNjTu!OD}e(j;4q%#x;*z}vz zGIC}ZbD7`iNQWrod`epa&oKfjjXfhjr9qViexLxH#-0Wla9n!qVoW#d)eHk!R1TeI zg{#hxHaXYYSQB4JdbLF#=Pbo2VJe?=rx;7HH0fY!M{0nnGr4+JR}2^6f;FZcxl^e0X$ zeqQ=yFdKU6JRwJ-U_*|O>g4J)9i2b+W=n-UzbOvQcVla?sYzC^5bnSIHw_L&-4lUXm0a0w^%vg&R5)(m51o7M*Wr?Yn< z17Fkrf@eP8nI>h1Vbn)qm^c9=5}VSVA1v?WG`qJ= zn?8BZ#J|t7RG?wryDnMpI?c^)byvkno)Ab8bhr&)BXqAJT7%1IiW#rjB-GRgT_?8W{BaN1zoL2OHnyYOOuKX_8$AIk7@cftlKk? zHi#-DsX)Y2>kKOdUsv7j%q)+AbD@ogYmVq(Q>%@o7B4{ddd=vC7XdhCge^9JD_-~mQyYJdr;!u zD0|t|@$Z8N0R_UYQ{C>}9I9YVfK*^!ZHSk<{Z`A0V7WQrmaKDL&tS~}F|5AuyCAb6 zJz2LIRG!eGcHQTJ_Pgkutap}W*rV_!n zjaS>a>92m9S+!z3k#xbY4hI%PKD2wo1a>(CFAfF{&evq48Af&%dFelTPkK|_8v@92 z4^rFDl7}@F(qcJ|*X!#S0=9jg&E)s-d>28b`fs0UJZEC0feD@MB&x~JaO%yLb_BZYpnQxo(LIy@Fgp;mJ5fuo^j1f}t-sqxUUD>w;5(z_*fu88 z4{$3uE_Wp#y6dSkFxXV-!(nn>;!Q=ypHv~XA@aKaW7B*kb6Aqi&*ADtkrKim&BK(h}oZIn)j$KdD{wJ9@UD z&R+dvg4v*amo$-3RcRp%3lmgK>EYR{ej9*}t1ejQBC6IRZmX|R#@lB(Wqjrvw(1l& zr`MzCdh+2}Z~HZ3BHI$6N&w)%L~@c1ffG$h>kPT&RPK_DeQ6Pj}i+m44~BR-aBN4{V|oP5s=# znwzFu-(*AmB4D)NeiPJ~XA1e+=71GNGL8!^rbHh=3FP`-X~rrHph0lI^}SC2aZ1ZLuflwYaA|A( z19uSC+8ghwMQc2EZsT@Tw0x&WZjaj_DA-ZbsPN)!YPbHfTpw@J=czH+cmQr&gK7$s zN1pm>HyZn>Br;!N44uC56Wh`U+%Nf>!(!H)IflE@g!pk3tH^EgP+F7Tu(a>tq`UAI zB~MZE22lK#O)rX`Jp}rty$8kk3RMwRv{n#ETq%7FUIpn%G*`n z{pP%t(nqDup$K}FP}1)Lcb*ZC7pNHX3=_6ar=KTg-*JCttz(pqW&fmPK;bO@pim3) zF0kr5v~!o(>o=q+I*66O_p#|(pP&f)(02jJgo7v|RJ$>Bsy(urW=XaGXwiY~sAgn2 z$AniQI(?H8m`A+uA;L4QiPRcdxa-bv0R}ds=(@ zc!Khq^m8GWj40#WD)*b(6^QNRRqfekIrho->O4SZ4)(jyL_t7cpt+ROHP-h%ZSiy~ zrr0+1WCyCQRd$NitipO)J0ZX5-wro`qExvhM14;G0uEXvqq!1%7;(JH= z@D;CktaSbwt3YWz&shhdwHE(Ehz8tE#xfabGqD(_e)b6$Hq=9P^$t(H{=4;u?D9Nq zzAZbCmTau9=g06c^yA!JdL(}AD2et|ecz&|RK599!d(HKezz^aw6UxmMZFUZREf>p zok=h?DfZ8>wUd`j!tp&Uc4b};3OnP618AzNKiw<%Jol4^!Ylw3h4Ak;9vd4^g7A2m z8O&wpmaoMz`-C}(DulbL@U}NHikQ{|N*+U1C-X+rk`KOYoJ?j`POC;l+| zbvBykdRI&XoI0M<);h=iG;Gq~?ND{Q{Mqafwa1xOcvjDKa|g#po>w!YH(DXURou2d zzgK~ZzXk_zxNFzGTk8*d=gzkiR6 zo-BPwo&EZ1GhqqB`pu}$kmMV_shMacxgXSBqRi@lD5CsbO9a&NuXSS-5dW+lRx7D5+rSWd05=el}f%S|71p z^{o~u$1nb02l@!N^Vi8Me!<$UsX5wP`5Ce^5?oSHn4|ehHBLLd>N`+1m-J-)NkZJf zN>qPG=yRj=46gW;0o4?lv}W%UoH<*qz@%{M+EhXa)V7^2q7|vaJ8K#3hecnsIa7MHXJ^OqPIww63{YFC&yD|3$5H|Z0}6S%pe z(StCC)`In~{8jD9+*cYSk5e9vKqAVo9KTfe64-i@_k%zAeq6>qex?joZ~-RW zUrN{EH6xKfrnUuJNmcgPbf?p83wz9U+f4A`CUo!l+$@LKm#PPG8#QBmx}I7&>%*A1lEakY zYL1Qwg;?Dl`pHFPA>kdQU?cDyiWlUhTVQ@H^}~96ap|(Z^(If%uG4m|=}Cwmk2~{C zDFL#xqCOfFA!{tj^nJuBG;7&2Vn6a_VA+!G=NTSGu9EE?5IutC%MsM zHwQkZ=(9VSCJ2cy!b<7tA2ocGR2`fr11Bk6BJ8O#UdD&$W&BPJ-Gq?5JU<%U8C}3v z^=xC$s<)S_1R$xcypx0l*6R4fRgFiIDGbP$w7ppSJiIm>GT$ALSEY}T=rX%|NA%P) zof~^KJH0I=xBJLNZnwV$2*eMtY{eWDlB{e|EeMY{UiNP5%%8pC7yPbNKdW=sxo8MC zA2YAH|0}rXb#Q|<`=m+7&ei)N6y+Ka!KB{%UW+#UK>s;Y+vWs8#Y_k5rH1%j*ds*< ztiwArU)Rc$u`6!az6pyXy6ei0HzW@$W#J`pz7`4szXxmS$ad~qcIdRax>;H+a*JjM z`I5Y_DL?GvbA7TcFzF`v0A7tkb#wViH+8-F5BiJj{Jj}CRZpUJPqf}p z6AhDYXTS*sL&j27n2xl0;|keN>HtPhpLtDcyBWEL2@p1aR6qkXa9E(>d*hw2a2cYbd?SNJHNfb7ps?nABs87TN zGQ4qF?j$vq450iX!0F7@T>TNt070^^;7@OgiBZMhT3?h{7&u`0Rb!cVe5NE=-q8NO zRZU<-rZ;UgP;o&KSxlhW9(lswmsn@dRhAYQam$$k-7CI8OXiWl;mJ)~EjGsk8I8@m z!nZaV=IOaj=x4s%e&4^AQcr|DX0g&0rY$@7gwZ4w62I;arMaTaS6U(&3CG98+FapG zi@Ac%Fv+eJvTM zV$}6ZU^uu)=uYESpgw92<1wV_+dL6{*-=Tt=+{9{T$l-EoVJb&-vk$gyCGJyLX3^w zu0V8ZAR3#&Os4JjWawxFeqenttZ{$ut&R%_<3=V&3F+DIkCSbl-&M!EfXlAHAkBqI z7ERm;HbNQ5h0!YW;ow@EQc$Dp>Jd%-0{La!YmH2=b|MJ7AK2MVQc_2C`F6>r@{hvd_p7>-%uI{%Un10#S2MYr6AQ9` z-L}uM+rrEJ)|hloSldw3SXmf;i`Y>A{D6lz@%q4kYam_UOJwdf50RcwYYQ}$!@ziP z#Sj%SZn`#X4g=fIXXo0ZP^-tx<^b_nMf$s?`um4bbtKr2hT~**-LI;w@bg(l??YA? zDO4Htl&zLpq=rx~KUN&taG1=s+V!eo(5DG3icpUXaZ8iiHr zisO(N13V?s)Zw}KGHBjG!D1Q|-0!5>rD|GQB?dh5=$7L!&H)4BHZ^rFtm$m->;kxU z74UH8kK7g@i== NVW?-STdnOB^*{MHr`-Sm literal 0 HcmV?d00001 diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 77551173dee..50bfe7289f4 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -26,3 +26,8 @@ competitorScoreCorrectionBody=New results for competitor {0} in {1} are availabl boatClassUpcomingRaceSubject=A race for boat class {0} will start soon # 0: boatClassName, 1: raceDescription, 2: time boatClassUpcomingRaceBody=For boat class {0} {1} will start approximately at {2}. + +subscriptionInformation=You are receiving notifications from SAP Sailing Analytics. To turn off notifications, please visit your profile at the link below. +userProfile=User Profile +imprint=Imprint +privacy=Privacy \ No newline at end of file diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties index ed499b011df..68e8db995f7 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties @@ -3,26 +3,31 @@ raceInFleetInRegattaOfEvent=Wettfahrt {0} ({3}) der Regatta "{1}" bei Veranstalt leaderboardOfEvent=Rangliste "{0}" bei Veranstaltung "{1}" leaderboardShowResultsLinkTitle=Ergebnisse anzeigen -racesOverviewLinkTitle=Wettfahrtübersicht anzeigen +racesOverviewLinkTitle=Wettfahrtübersicht anzeigen raceboardShowRaceLinkTitle=Wettfahrt anzeigen raceboardRaceAnalysisLinkTitle=Wettfahrtanalyse anzeigen -boatClassRaceFinishedSubject=Wettfahrt für Bootsklasse {0} beendet - Neue Ergebnisse verfügbar +boatClassRaceFinishedSubject=Wettfahrt für Bootsklasse {0} beendet - Neue Ergebnisse verfügbar # 0: boatClassName, 1: raceDescription -boatClassRaceFinishedBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. +boatClassRaceFinishedBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. -boatClassScoreCorrectionSubject=Neue Ergebnisse für Bootsklasse {0} verfügbar +boatClassScoreCorrectionSubject=Neue Ergebnisse für Bootsklasse {0} verfügbar # 0: boatClassName, 1: leaderboardDescription -boatClassScoreCorrectionBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. +boatClassScoreCorrectionBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. competitorPassesFinishSubject=Teilnehmer {0} hat eine Wettfahrt beendet # 0: competitorName, 1: raceDescription -competitorPassesFinishBody=Teilnehmer {0} hat bei {1} die Ziellinie überquert. +competitorPassesFinishBody=Teilnehmer {0} hat bei {1} die Ziellinie überquert. -competitorScoreCorrectionSubject=Neue Ergebnisse für Teilnehmer {0} +competitorScoreCorrectionSubject=Neue Ergebnisse für Teilnehmer {0} # 0: competitorName, 1: leaderboardDescription -competitorScoreCorrectionBody=Für Teilnehmer {0} in {1} sind neue Ergebnisse verfügbar. +competitorScoreCorrectionBody=Für Teilnehmer {0} in {1} sind neue Ergebnisse verfügbar. boatClassUpcomingRaceSubject=Wettfahrt in Bootsklasse {0} startet bald # 0: boatClassName, 1: raceDescription, 2: time boatClassUpcomingRaceBody=In Bootsklasse {0} startet {1} um etwa {2}. + +subscriptionInformation=Bei dieser Mail handelt es sich um eine automatisierte Benachrichtigung aus der SAP Sailing Analytics. Die Benachrichtigungen können im Benutzerprofil (s.u.) abgeschaltet werden. +userProfile=Benutzerprofil +imprint=Impressum +privacy=Datenschutzerklärung diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java index be88f351ec9..27d6b5a67ee 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationMailTemplate.java @@ -1,5 +1,6 @@ package com.sap.sailing.server.notification.impl; +import java.net.URL; import java.util.Arrays; import com.sap.sse.common.Util.Pair; @@ -9,21 +10,29 @@ public class NotificationMailTemplate { private final String subject; private final String title; private final String text; + private final String serverBaseUrl; private final Iterable> labelsAndLinkUrls; @SafeVarargs - public NotificationMailTemplate(String subject, String text, Pair... labelsAndLinkUrls) { - this(subject, null, text, labelsAndLinkUrls); + public NotificationMailTemplate(String subject, String text, URL serverBaseUrl, + Pair... labelsAndLinkUrls) { + this(subject, null, text, serverBaseUrl, labelsAndLinkUrls); } @SafeVarargs - public NotificationMailTemplate(String subject, String title, String text, Pair... labelsAndLinkUrls) { + public NotificationMailTemplate(String subject, String title, String text, URL serverBaseUrl, + Pair... labelsAndLinkUrls) { this.subject = subject; this.title = title; this.text = text; + this.serverBaseUrl = serverBaseUrl.toString(); this.labelsAndLinkUrls = Arrays.asList(labelsAndLinkUrls); } + public String getServerBaseUrl() { + return serverBaseUrl; + } + public String getSubject() { return subject; } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java index 5a5c50d4c00..cff429014fb 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -1,19 +1,25 @@ package com.sap.sailing.server.notification.impl; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; +import javax.activation.DataHandler; +import javax.activation.DataSource; import javax.mail.BodyPart; import javax.mail.Multipart; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; +import javax.mail.util.ByteArrayDataSource; import com.sap.sse.common.Util.Pair; +import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl; import com.sap.sse.mail.MailService; import com.sap.sse.mail.queue.MailNotification; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; @@ -22,7 +28,10 @@ public abstract class NotificationSetNotification implements MailNotification private static final Logger logger = Logger.getLogger(NotificationSetNotification.class.getName()); private static final String TEMPLATE_FILE = "notification-mail-template.html"; + private static final String LOGO_FILE = "sap_logo_header.png"; + private static final String TEMPLATE = loadTemplateFile(); + private static final byte[] LOGO_BYTES = loadLogoFile(); private static String loadTemplateFile() { StringBuilder content = new StringBuilder(); @@ -38,13 +47,31 @@ public abstract class NotificationSetNotification implements MailNotification return content.toString(); } + private static byte[] loadLogoFile() { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream in = NotificationSetNotification.class.getResourceAsStream(LOGO_FILE)) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(buffer)) >= 0) { + baos.write(buffer, 0, bytesRead); + } + return baos.toByteArray(); + } catch (IOException exc) { + logger.log(Level.SEVERE, "Error while loading notification mail template!", exc); + return null; + } + } private final T objectToNotifyAbout; private final PreferenceObjectBasedNotificationSet associatedNotificationSet; + private static final ResourceBundleStringMessagesImpl messages = new ResourceBundleStringMessagesImpl( + SailingNotificationServiceImpl.STRING_MESSAGES_BASE_NAME, + NotificationSetNotification.class.getClassLoader()); public NotificationSetNotification(T objectToNotifyAbout, PreferenceObjectBasedNotificationSet associatedNotificationSet) { this.objectToNotifyAbout = objectToNotifyAbout; this.associatedNotificationSet = associatedNotificationSet; + } @Override @@ -55,10 +82,19 @@ public abstract class NotificationSetNotification implements MailNotification Locale locale = user.getLocaleOrDefault(); Multipart multipart = new MimeMultipart(); BodyPart bodyPart = new MimeBodyPart(); + BodyPart messageImagePart = new MimeBodyPart(); try { + // TODO: add cid:saplogo NotificationMailTemplate mailTemplate = getMailTemplate(objectToNotifyAbout, locale); - bodyPart.setContent(getMailContent(mailTemplate), "text/html"); + bodyPart.setContent(getMailContent(mailTemplate, locale), "text/html"); multipart.addBodyPart(bodyPart); + + DataSource imageDs = new ByteArrayDataSource(LOGO_BYTES, "image/png"); + messageImagePart.setDataHandler(new DataHandler(imageDs)); + messageImagePart.setHeader("Content-ID", "saplogo"); + messageImagePart.setHeader("Content-Disposition", "inline;filename=\"saplogo.png\""); + multipart.addBodyPart(messageImagePart); + mailService.sendMail(user.getEmail(), mailTemplate.getSubject(), multipart); } catch (Exception e) { logger.log(Level.SEVERE, @@ -67,17 +103,39 @@ public abstract class NotificationSetNotification implements MailNotification }); } - private String getMailContent(NotificationMailTemplate notificationMailTemplate) { + private String getMailContent(NotificationMailTemplate notificationMailTemplate, Locale locale) { StringBuilder bodyContent = new StringBuilder(); if (notificationMailTemplate.getTitle() != null) { bodyContent.append("

        ").append(notificationMailTemplate.getTitle()).append("

        "); } - bodyContent.append("

        ").append(notificationMailTemplate.getText()).append("

        "); + bodyContent.append("

        ").append(notificationMailTemplate.getText()).append("

        "); for (Pair link : notificationMailTemplate.getLabelsAndLinkUrls()) { bodyContent.append("
        ").append("").append(link.getA()).append("").append("
        "); } - return TEMPLATE.replace("${title}", notificationMailTemplate.getSubject()).replace("${body}", bodyContent.toString()); + String siteLink = "" + + notificationMailTemplate.getServerBaseUrl() + ""; + StringBuilder footerLinks = new StringBuilder(); + footerLinks // + .append("").append(messages.get(locale, "userProfile")).append("") + .append(" | "); + footerLinks.append("") + .append(messages.get(locale, "imprint")).append("") + .append(" | "); + footerLinks.append("") + .append(messages.get(locale, "privacy")) + .append(""); + + String subscriptionInformation = messages.get(locale, "subscriptionInformation"); + return TEMPLATE // + .replace("${title}", notificationMailTemplate.getSubject()) + .replace("${content}", bodyContent.toString()) + .replace("${subscription_information}", subscriptionInformation) + .replace("${site}", siteLink) // + .replace("${footer_links}", footerLinks.toString()) + ; } protected abstract NotificationMailTemplate getMailTemplate(T objectToNotifyAbout, Locale locale); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index a1b6020d724..9fcdbbda6f0 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -37,7 +37,7 @@ import com.sap.sse.mail.queue.MailQueue; import com.sap.sse.security.UserStore; public class SailingNotificationServiceImpl implements SailingNotificationService { - private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/StringMessages"; + public static final String STRING_MESSAGES_BASE_NAME = "stringmessages/StringMessages"; private static final Logger logger = Logger.getLogger(SailingNotificationServiceImpl.class.getName()); @@ -239,7 +239,9 @@ public class SailingNotificationServiceImpl implements SailingNotificationServic String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); return new NotificationMailTemplate( messages.get(locale, "boatClassRaceFinishedSubject", boatClass.getDisplayName()), - messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(), raceDescription), + messages.get(locale, "boatClassRaceFinishedBody", boatClass.getDisplayName(), + raceDescription), + getBaseURL(event), createRaceBoardShowRaceLink(trackedRace, leaderboard, event, leaderboardGroup, locale), createRaceBoardRaceAnalysisLink(trackedRace, leaderboard, event, leaderboardGroup, locale)); } @@ -258,7 +260,9 @@ public class SailingNotificationServiceImpl implements SailingNotificationServic String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); return new NotificationMailTemplate( messages.get(locale, "boatClassScoreCorrectionSubject", boatClass.getDisplayName()), - messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(), leaderboardDescription), + messages.get(locale, "boatClassScoreCorrectionBody", boatClass.getDisplayName(), + leaderboardDescription), + getBaseURL(event), createHomeLeaderboardLink(leaderboard, event, locale)); } }); @@ -278,7 +282,8 @@ public class SailingNotificationServiceImpl implements SailingNotificationServic return new NotificationMailTemplate( messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName()), messages.get(locale, "boatClassUpcomingRaceBody", boatClass.getDisplayName(), - raceDescription, time), + raceDescription, time), + getBaseURL(event), createHomeRacesListLink(leaderboard, event, locale)); } }); @@ -295,8 +300,9 @@ public class SailingNotificationServiceImpl implements SailingNotificationServic protected NotificationMailTemplate getMailTemplate(Competitor objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); return new NotificationMailTemplate( - messages.get(locale, "competitorPassesFinishSubject", competitor.getName()), - messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription), + messages.get(locale, "competitorPassesFinishSubject", competitor.getName()), + messages.get(locale, "competitorPassesFinishBody", competitor.getName(), raceDescription), + getBaseURL(event), createRaceBoardShowRaceLink(trackedRace, leaderboard, event, leaderboardGroup, locale), createRaceBoardRaceAnalysisLink(trackedRace, leaderboard, event, leaderboardGroup, locale)); } @@ -313,8 +319,10 @@ public class SailingNotificationServiceImpl implements SailingNotificationServic protected NotificationMailTemplate getMailTemplate(Competitor objectToNotifyAbout, Locale locale) { String leaderboardDescription = calculateLeaderboardDescription(locale, event, leaderboard); return new NotificationMailTemplate( - messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()), - messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), leaderboardDescription), + messages.get(locale, "boatClassScoreCorrectionSubject", competitor.getName()), + messages.get(locale, "boatClassScoreCorrectionBody", competitor.getName(), + leaderboardDescription), + getBaseURL(event), createHomeLeaderboardLink(leaderboard, event, locale)); } }); From f0bbff8ecfe1c5463fdc46f583b4af55e01b0a64 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 20 Jul 2016 01:47:59 +0200 Subject: [PATCH 240/259] added a null check in RacingEventServiceImpl where the notificationService may be null, especially in test cases Change-Id: I508b4fc8ae083b57ab49c1c0b809a5b10df33a5c --- .../com/sap/sailing/server/impl/RacingEventServiceImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 d8d01f25ef6..c6ae569f0d6 100644 --- 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 @@ -2859,8 +2859,10 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes mediaLibrary.clear(); competitorStore.clear(); remoteSailingServerSet.clear(); - notificationService.stop(); - notificationService = new EmptySailingNotificationService(); + if (notificationService != null) { + notificationService.stop(); + notificationService = new EmptySailingNotificationService(); + } } // Used for TESTING only From f952be214f7308563fb10daffcf842ee4ac8f0d1 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 20 Jul 2016 15:12:10 +0200 Subject: [PATCH 241/259] added a "buffer" for toggleExpansion() requests; see bug 3797 comment #7 Change-Id: Ibc123564bc6fe6be9c55c443776c786adb3500f5 --- .../leaderboard/ExpandableSortableColumn.java | 104 ++++++++++++------ 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java index 55d4569c087..b7134a7903c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java @@ -26,7 +26,29 @@ import com.sap.sailing.gwt.ui.client.shared.controls.AbstractSortableColumnWithM */ public abstract class ExpandableSortableColumn extends LeaderboardSortableColumnWithMinMax { private boolean enableExpansion; + + /** + * Set when the {@link #toggleExpansion()} method begins with its work. Three things can happen: + *
          + *
        1. the column is to be collapsed. This can happen synchronously, and the flag is cleared again before the method + * returns
        2. + *
        3. the column is to be expanded and all information required for this is already available; again, this type + * of request can be handled synchronously, and the flag is cleared before the method returns
        4. + *
        5. the column is to be expanded but not all information required is available yet; it has to be requested using + * an asynchronous call; the method returns with the flag still set, and the callback will clear it when done
        6. + *
        + */ private boolean togglingInProcess; + + /** + * If {@link #togglingInProcess} is {@code true} and a call to {@link #toggleExpansion()} is received, + * instead of running the method, the request is "queued" only by incrementing this counter. When the + * asynchronous task completes the running toggle action, the counter is decremented by one and + * {@link #toggleExpansion()} is called. This way, overlapping asynchronous requests triggered by calls + * to {@link #toggleExpansion()} are avoiided. + */ + private int numberOfQueuedToggleRequests; + private boolean suppressSortingOnce; private final LeaderboardPanel leaderboardPanel; private final Map> detailColumnsMap; @@ -145,47 +167,63 @@ public abstract class ExpandableSortableColumn extends LeaderboardSortableCol *

        * * Precondition: this column must currently be contained in the {@link CellTable} showing the - * {@link #leaderboardPanel leaderboard}. + * {@link #leaderboardPanel leaderboard}.

        + * + * When the method starts to toggle the expansion state, it sets the {@link #togglingInProcess} flag. When the + * method returns the {@link #isExpanded()} method yields the new expansion state. However, when the column contents + * need to be loaded asynchronously first, the expansion will not have affected the table structure yet and is + * still "pending." This state is indicated by the {@link #isTogglingInProcess()} method returning {@code true} + * after this method has returned. Only after the asynchronous data loading has happened and the table has + * actually been updated to reflect the expanded state, the {@link #isTogglingInProcess()} will then again + * return {@code false}. */ public void toggleExpansion() { if (isExpansionEnabled()) { - final boolean oldBusyState = getLeaderboardPanel().isBusy(); - getLeaderboardPanel().setBusyState(true); - setTogglingInProcess(true); - final CellTable table = getLeaderboardPanel().getLeaderboardTable(); - if (isExpanded()) { - for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { - getLeaderboardPanel().removeColumn(column); // removes only the children currently displayed - } - getLeaderboardPanel().setBusyState(false); - setTogglingInProcess(false); - // important: toggle expanded state after asking for all visible children - setExpanded(!isExpanded()); + if (isTogglingInProcess()) { + numberOfQueuedToggleRequests++; } else { - // important: toggle expanded state before asking for all visible children - setExpanded(!isExpanded()); - ensureExpansionDataIsLoaded(new Runnable() { - public void run() { - // column may have been collapsed meanwhile, so that the columns must not be added to the table right now - if (isExpanded()) { - int insertIndex = table.getColumnIndex(ExpandableSortableColumn.this); - // The check "insertIndex != -1" is necessary, because the child-columns might be deleted - // asynchronously while toggling the columns. - if (insertIndex != -1) { - insertIndex++; - for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { - column.updateMinMax(); - if (table.getColumnIndex(column) < 0) { - getLeaderboardPanel().insertColumn(insertIndex++, column); + final boolean oldBusyState = getLeaderboardPanel().isBusy(); + getLeaderboardPanel().setBusyState(true); + setTogglingInProcess(true); + final CellTable table = getLeaderboardPanel().getLeaderboardTable(); + if (isExpanded()) { + for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { + getLeaderboardPanel().removeColumn(column); // removes only the children currently displayed + } + getLeaderboardPanel().setBusyState(false); + setTogglingInProcess(false); + // important: toggle expanded state after asking for all visible children + setExpanded(!isExpanded()); + } else { + // important: toggle expanded state before asking for all visible children + setExpanded(!isExpanded()); + ensureExpansionDataIsLoaded(new Runnable() { + public void run() { + // column may have been collapsed meanwhile, so that the columns must not be added to the table right now + if (isExpanded()) { + int insertIndex = table.getColumnIndex(ExpandableSortableColumn.this); + // The check "insertIndex != -1" is necessary, because the child-columns might be deleted + // asynchronously while toggling the columns. + if (insertIndex != -1) { + insertIndex++; + for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { + column.updateMinMax(); + if (table.getColumnIndex(column) < 0) { + getLeaderboardPanel().insertColumn(insertIndex++, column); + } } + getLeaderboardPanel().getLeaderboardTable().redraw(); } - getLeaderboardPanel().getLeaderboardTable().redraw(); + } + getLeaderboardPanel().setBusyState(oldBusyState); + setTogglingInProcess(false); + if (numberOfQueuedToggleRequests > 0) { + numberOfQueuedToggleRequests--; + toggleExpansion(); } } - getLeaderboardPanel().setBusyState(oldBusyState); - setTogglingInProcess(false); - } - }); + }); + } } } } From 708dd3b53e95546027e4d80ab7d86eab1684a613 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Jul 2016 16:28:34 +0200 Subject: [PATCH 242/259] Added alt text for SAP logo in notification mails --- .../server/notification/impl/notification-mail-template.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html index 71b061fcd10..92ed5c9a6ba 100644 --- a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html +++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html @@ -76,7 +76,7 @@

        - Sailing Analytics + Sailing Analytics
        ${content} From 3dc63602ca19b2cc077353e862d2f641158d466d Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Jul 2016 16:29:42 +0200 Subject: [PATCH 243/259] Adjusted vertical alignments of notification mail header --- .../server/notification/impl/notification-mail-template.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html index 92ed5c9a6ba..f87055492cf 100644 --- a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html +++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html @@ -64,11 +64,13 @@ .sapLogo { height: 30px; width: auto; + vertical-align: middle; } .sailingAnalytics { display: inline-block; line-height: 30px; + vertical-align: middle; } From 8df03d72d8196bb38f4a45733b153bac39cab5ad Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Jul 2016 16:31:03 +0200 Subject: [PATCH 244/259] Adjusted time format to include time zone info in notification mails --- .../notification/impl/SailingNotificationServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java index ee04447afe0..0088e0cf42f 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/SailingNotificationServiceImpl.java @@ -277,7 +277,7 @@ public class SailingNotificationServiceImpl implements SailingNotificationServic @Override protected NotificationMailTemplate getMailTemplate(BoatClass objectToNotifyAbout, Locale locale) { String raceDescription = calculateRaceDescription(locale, event, leaderboard, raceColumn, fleet); - String time = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale) + String time = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG, locale) .format(when.asDate()); return new NotificationMailTemplate( messages.get(locale, "boatClassUpcomingRaceSubject", boatClass.getDisplayName()), From 4c80959cb31f29ca8ae7ec62c455471dc212515a Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Jul 2016 16:33:00 +0200 Subject: [PATCH 245/259] Fixed umlauts in notification mail subjects --- .../resources/stringmessages/StringMessages_de.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties index 68e8db995f7..83b3f691df5 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties @@ -7,11 +7,11 @@ racesOverviewLinkTitle=Wettfahrtübersicht anzeigen raceboardShowRaceLinkTitle=Wettfahrt anzeigen raceboardRaceAnalysisLinkTitle=Wettfahrtanalyse anzeigen -boatClassRaceFinishedSubject=Wettfahrt für Bootsklasse {0} beendet - Neue Ergebnisse verfügbar +boatClassRaceFinishedSubject=Wettfahrt für Bootsklasse {0} beendet - Neue Ergebnisse verfügbar # 0: boatClassName, 1: raceDescription boatClassRaceFinishedBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. -boatClassScoreCorrectionSubject=Neue Ergebnisse für Bootsklasse {0} verfügbar +boatClassScoreCorrectionSubject=Neue Ergebnisse für Bootsklasse {0} verfügbar # 0: boatClassName, 1: leaderboardDescription boatClassScoreCorrectionBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. @@ -19,7 +19,7 @@ competitorPassesFinishSubject=Teilnehmer {0} hat eine Wettfahrt beendet # 0: competitorName, 1: raceDescription competitorPassesFinishBody=Teilnehmer {0} hat bei {1} die Ziellinie überquert. -competitorScoreCorrectionSubject=Neue Ergebnisse für Teilnehmer {0} +competitorScoreCorrectionSubject=Neue Ergebnisse für Teilnehmer {0} # 0: competitorName, 1: leaderboardDescription competitorScoreCorrectionBody=Für Teilnehmer {0} in {1} sind neue Ergebnisse verfügbar. From 48ef3f241aa158b460f681e0b0721d0cfc723206 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Jul 2016 16:33:37 +0200 Subject: [PATCH 246/259] Added salutation to notification mail content --- .../resources/stringmessages/StringMessages.properties | 3 ++- .../resources/stringmessages/StringMessages_de.properties | 1 + .../notification/impl/NotificationSetNotification.java | 7 +++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 50bfe7289f4..1cca8467120 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -30,4 +30,5 @@ boatClassUpcomingRaceBody=For boat class {0} {1} will start approximately at {2} subscriptionInformation=You are receiving notifications from SAP Sailing Analytics. To turn off notifications, please visit your profile at the link below. userProfile=User Profile imprint=Imprint -privacy=Privacy \ No newline at end of file +privacy=Privacy +salutation=Hallo {0}, \ No newline at end of file diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties index 83b3f691df5..33863a527f0 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties @@ -31,3 +31,4 @@ subscriptionInformation=Bei dieser Mail handelt es sich um eine automatisierte B userProfile=Benutzerprofil imprint=Impressum privacy=Datenschutzerklärung +salutation=Hallo {0}, \ No newline at end of file diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java index cff429014fb..696aab0aca7 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -23,6 +23,7 @@ import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl; import com.sap.sse.mail.MailService; import com.sap.sse.mail.queue.MailNotification; import com.sap.sse.security.PreferenceObjectBasedNotificationSet; +import com.sap.sse.security.User; public abstract class NotificationSetNotification implements MailNotification { private static final Logger logger = Logger.getLogger(NotificationSetNotification.class.getName()); @@ -86,7 +87,7 @@ public abstract class NotificationSetNotification implements MailNotification try { // TODO: add cid:saplogo NotificationMailTemplate mailTemplate = getMailTemplate(objectToNotifyAbout, locale); - bodyPart.setContent(getMailContent(mailTemplate, locale), "text/html"); + bodyPart.setContent(getMailContent(mailTemplate, user, locale), "text/html"); multipart.addBodyPart(bodyPart); DataSource imageDs = new ByteArrayDataSource(LOGO_BYTES, "image/png"); @@ -103,11 +104,13 @@ public abstract class NotificationSetNotification implements MailNotification }); } - private String getMailContent(NotificationMailTemplate notificationMailTemplate, Locale locale) { + private String getMailContent(NotificationMailTemplate notificationMailTemplate, User user, Locale locale) { StringBuilder bodyContent = new StringBuilder(); if (notificationMailTemplate.getTitle() != null) { bodyContent.append("

        ").append(notificationMailTemplate.getTitle()).append("

        "); } + String name = user.getFullName() == null || user.getFullName().isEmpty() ? user.getName() : user.getFullName(); + bodyContent.append("

        ").append(messages.get(locale, "salutation", name)).append("

        "); bodyContent.append("

        ").append(notificationMailTemplate.getText()).append("

        "); for (Pair link : notificationMailTemplate.getLabelsAndLinkUrls()) { bodyContent.append("
        ").append(" Date: Wed, 20 Jul 2016 16:58:42 +0200 Subject: [PATCH 247/259] Implemented the toogle feature of show/hide the wind streamlets by clicking on the combinedWIndPanelIcon But so far for some strange reason the clickhandler is not triggered --- .../sailing/gwt/ui/client/StringMessages.java | 4 +++- .../gwt/ui/client/StringMessages.properties | 4 +++- .../ui/client/StringMessages_de.properties | 4 +++- .../ui/client/StringMessages_ja.properties | 4 +++- .../ui/client/StringMessages_ru.properties | 4 +++- .../ui/client/StringMessages_zh.properties | 4 +++- .../ui/client/StringMessages_zh_CN.properties | 4 +++- .../shared/racemap/CombinedWindPanel.java | 24 +++++++++++++++++-- .../gwt/ui/client/shared/racemap/RaceMap.java | 2 +- .../racemap/TrueNorthIndicatorPanel.java | 3 ++- 10 files changed, 46 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 21415470eee..f173e16fab7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -1326,7 +1326,9 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, String currentFilterSelection(); String notCapableOfGeneratingACodeForIdentifier(); String serverUrl(); - String rotatedFromTrueNorthClickToToggleWindUp(double mappedTrueNorthDeg); + String rotatedFromTrueNorth(double mappedTrueNorthDeg); + String clickToToggleWindUp(); + String clickToToggleWindStreamlets(); String startLineToFirstMarkTriangle(String distanceInMeters); String dataMiningComponentsHaveBeenUpdated(); String dataMiningComponentsNeedReloadDialogMessage(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 0e2fa6f23dc..49c0942ea44 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -1287,7 +1287,9 @@ filterBy=Filter by currentFilterSelection=Current filter selection notCapableOfGeneratingACodeForIdentifier=I''m not capable of generating a code for this identifier. serverUrl=Server URL -rotatedFromTrueNorthClickToToggleWindUp=Rotated {0} degrees from true north.\nTap/click to toggle between wind-up and north-up map display +rotatedFromTrueNorth=Rotated {0} degrees from true north. +clickToToggleWindUp=Tap/click to toggle between wind-up and north-up map display +clickToToggleWindStreamlets=Tap/click to show or hide the wind streamlets startLineToFirstMarkTriangle=Start to first mark ({0}m) dataMiningComponentsHaveBeenUpdated=The Data-Mining components have been updated dataMiningComponentsNeedReloadDialogMessage=Click Reload to reload the components now. This will discard the current displayed data and run a default query.\nClick Close to do nothing. The Data-Mining won''t work correctly, until the components have been reloaded. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 909c50d8bf2..14059d1614e 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -1275,7 +1275,9 @@ filterBy=Gefiltert nach currentFilterSelection=Aktuelle Filter-Selektion notCapableOfGeneratingACodeForIdentifier=Für diesen Identifier kann kein Barcode generiert werden. serverUrl=Server URL -rotatedFromTrueNorthClickToToggleWindUp={0}° gegenüber rechtweisend Nord rotiert.\nKlick wechselt zwischen Kartenanzeige "Wind oben" und "Nord oben" +rotatedFromTrueNorth={0}° gegenüber rechtweisend Nord rotiert. +clickToToggleWindUp=Klick wechselt zwischen Kartenanzeige "Wind oben" und "Nord oben" +clickToToggleWindStreamlets=Klick wechselt der Anzeige der Windstreamlets startLineToFirstMarkTriangle=Vom Start zur nächsten Bahnmarke ({0}m) dataMiningComponentsHaveBeenUpdated=Die Data-Mining Komponenten wurden aktualisiert dataMiningComponentsNeedReloadDialogMessage=Klicke auf Neu Laden, um die Komponenten jetzt neu zu laden. Die aktuell angezeigten Daten gehen dabei verloren und eine Standard-Query wird ausgeführt.\nKlicke auf Schließen, um nichts zu tun. Das Data-Mining wird nicht korrekt funktionieren, bis die Komponenten neu geladen wurden. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties index c944a16b192..5eeaabb85b1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ja.properties @@ -1283,7 +1283,9 @@ filterBy=フィルタキー currentFilterSelection=現在のフィルタ選択 notCapableOfGeneratingACodeForIdentifier=この ID のコードを生成することができません。 serverUrl=サーバ URL -rotatedFromTrueNorthClickToToggleWindUp=真北から {0} 度を回転。\nタップ/クリックしてウィンドアップとノースアップの間のマップ表示を切替 +rotatedFromTrueNorth=真北から {0} 度を回転。 +clickToToggleWindUp=タップ/クリックしてウィンドアップとノースアップの間のマップ表示を切替 +clickToToggleWindStreamlets=Tap/click to show or hide the wind streamlets startLineToFirstMarkTriangle=スタートから第一マークまで ({0}m) dataMiningComponentsHaveBeenUpdated=データマイニングコンポーネントが更新されました dataMiningComponentsNeedReloadDialogMessage=リロードをクリックして、コンポーネントをリロードします。これにより、現在表示されているデータが破棄され、デフォルトクエリが実行されます。\n何も行わない場合は閉じるをクリックします。データマイニングは、コンポーネントがリロードされるまでは正しく機能しません。 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties index 3cd1c33c2a5..245bf1ca9eb 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_ru.properties @@ -1283,7 +1283,9 @@ filterBy=Фильтровать по currentFilterSelection=Текущий выбор фильтра notCapableOfGeneratingACodeForIdentifier=Я не могу сгенерировать код для этого идентификатора. serverUrl=URL-адрес сервера -rotatedFromTrueNorthClickToToggleWindUp=Повернуто на {0} град. от истинного севера.\nКоснитесь/щелкните для переключения между отображением карты с ветром или севером вверху +rotatedFromTrueNorth=Повернуто на {0} град. от истинного севера. +clickToToggleWindUp=Коснитесь/щелкните для переключения между отображением карты с ветром или севером вверху +clickToToggleWindStreamlets=Tap/click to show or hide the wind streamlets startLineToFirstMarkTriangle=От старта до первой отметки ({0} м) dataMiningComponentsHaveBeenUpdated=Компоненты добычи данных обновлены. dataMiningComponentsNeedReloadDialogMessage=Щелкните "Перезагрузить", чтобы перезагрузить компоненты сейчас. Текущее отображение данных будет с##рошено с выполнением запроса по умолчанию. Добыча данных не будет работать правильно до перезагрузки компонентов. diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties index eb068601f84..6797c085fa4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh.properties @@ -1283,7 +1283,9 @@ filterBy=筛选方式 currentFilterSelection=当前筛选器选择 notCapableOfGeneratingACodeForIdentifier=无法为此标识符生成代码。 serverUrl=服务器 URL -rotatedFromTrueNorthClickToToggleWindUp=自真北方向旋转{0}度。\n点按/点击在风向向上和北向上地图显示之间切换 +rotatedFromTrueNorth=自真北方向旋转{0}度。 +clickToToggleWindUp=点按/点击在风向向上和北向上地图显示之间切换 +clickToToggleWindStreamlets=Tap/click to show or hide the wind streamlets startLineToFirstMarkTriangle=开始经过第一个标志 ({0}m) dataMiningComponentsHaveBeenUpdated=数据挖掘组件已更新 dataMiningComponentsNeedReloadDialogMessage=点击“重新加载”,立即重新加载组件。 这将放弃当前显示的数据,并运行默认查询。\n点击“关闭”不执行任何操作。 在重新加载组件前,数据挖掘不能正常工作。 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties index eb068601f84..6797c085fa4 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_zh_CN.properties @@ -1283,7 +1283,9 @@ filterBy=筛选方式 currentFilterSelection=当前筛选器选择 notCapableOfGeneratingACodeForIdentifier=无法为此标识符生成代码。 serverUrl=服务器 URL -rotatedFromTrueNorthClickToToggleWindUp=自真北方向旋转{0}度。\n点按/点击在风向向上和北向上地图显示之间切换 +rotatedFromTrueNorth=自真北方向旋转{0}度。 +clickToToggleWindUp=点按/点击在风向向上和北向上地图显示之间切换 +clickToToggleWindStreamlets=Tap/click to show or hide the wind streamlets startLineToFirstMarkTriangle=开始经过第一个标志 ({0}m) dataMiningComponentsHaveBeenUpdated=数据挖掘组件已更新 dataMiningComponentsNeedReloadDialogMessage=点击“重新加载”,立即重新加载组件。 这将放弃当前显示的数据,并运行默认查询。\n点击“关闭”不执行任何操作。 在重新加载组件前,数据挖掘不能正常工作。 diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java index aa92c3f2602..62646d403c7 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java @@ -1,6 +1,8 @@ package com.sap.sailing.gwt.ui.client.shared.racemap; import com.google.gwt.canvas.client.Canvas; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Label; @@ -26,7 +28,7 @@ public class CombinedWindPanel extends FlowPanel { private RaceMapStyle raceMapStyle; private final CoordinateSystem coordinateSystem; - public CombinedWindPanel(RaceMapImageManager theRaceMapResources, RaceMapStyle raceMapStyle, + public CombinedWindPanel(final RaceMap map, RaceMapImageManager theRaceMapResources, RaceMapStyle raceMapStyle, StringMessages stringMessages, CoordinateSystem coordinateSystem) { raceMapStyle.ensureInjected(); this.stringMessages = stringMessages; @@ -38,6 +40,23 @@ public class CombinedWindPanel extends FlowPanel { canvas = transformer.getCanvas(); canvas.addStyleName(this.raceMapStyle.raceMapIndicatorPanelCanvas()); add(canvas); + canvas.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + RaceMapSettings oldRaceMapSettings = map.getSettings(); + boolean newShowStreamletsOverlaySetting = !oldRaceMapSettings.isShowWindStreamletOverlay(); + + final RaceMapSettings newRaceMapSettings = new RaceMapSettings(oldRaceMapSettings.getZoomSettings(), + oldRaceMapSettings.getHelpLinesSettings(), oldRaceMapSettings.getTransparentHoverlines(), + oldRaceMapSettings.getHoverlineStrokeWeight(), oldRaceMapSettings.getTailLengthInMilliseconds(), oldRaceMapSettings.isWindUp(), + oldRaceMapSettings.getBuoyZoneRadiusInMeters(), oldRaceMapSettings.isShowOnlySelectedCompetitors(), + oldRaceMapSettings.isShowSelectedCompetitorsInfo(), oldRaceMapSettings.isShowWindStreamletColors(), + newShowStreamletsOverlaySetting, oldRaceMapSettings.isShowSimulationOverlay(), + oldRaceMapSettings.isShowMapControls(), oldRaceMapSettings.getManeuverTypesToShow(), + oldRaceMapSettings.isShowDouglasPeuckerPoints()); + map.updateSettings(newRaceMapSettings); + } + }); textLabel = new Label(""); textLabel.addStyleName(this.raceMapStyle.raceMapIndicatorPanelTextLabel()); add(textLabel); @@ -53,7 +72,8 @@ public class CombinedWindPanel extends FlowPanel { double rotationDegOfWindSymbol = windDTO.dampenedTrueWindBearingDeg; transformer.drawTransformedImage(coordinateSystem.mapDegreeBearing(rotationDegOfWindSymbol), 1.0); String title = stringMessages.wind() + ": " + Math.round(windFromDeg) + " " - + stringMessages.degreesShort() + " (" + WindSourceTypeFormatter.format(windSource, stringMessages) + ")"; + + stringMessages.degreesShort() + " (" + WindSourceTypeFormatter.format(windSource, stringMessages) + ")" + + + '\n'+ stringMessages.clickToToggleWindStreamlets(); canvas.setTitle(title); textLabel.setText(numberFormat.format(speedInKnots) + " " + stringMessages.knotsUnit()); if (!isVisible()) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index 8fc640588bc..e4b925227a1 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -447,7 +447,7 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe panelForLeftHeaderLabels = new AbsolutePanel(); panelForRightHeaderLabels = new AbsolutePanel(); initializeData(settings.isShowMapControls(), showHeaderPanel); - combinedWindPanel = new CombinedWindPanel(raceMapImageManager, raceMapResources.raceMapStyle(), stringMessages, coordinateSystem); + combinedWindPanel = new CombinedWindPanel(this, raceMapImageManager, raceMapResources.raceMapStyle(), stringMessages, coordinateSystem); combinedWindPanel.setVisible(false); trueNorthIndicatorPanel = new TrueNorthIndicatorPanel(this, raceMapImageManager, raceMapResources.raceMapStyle(), stringMessages, coordinateSystem); trueNorthIndicatorPanel.setVisible(true); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java index 099cc503058..6465508ad61 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java @@ -65,7 +65,8 @@ public class TrueNorthIndicatorPanel extends FlowPanel { protected void redraw() { final double mappedTrueNorthDeg = coordinateSystem.mapDegreeBearing(0); transformer.drawTransformedImage(mappedTrueNorthDeg, 1.0); - String title = stringMessages.rotatedFromTrueNorthClickToToggleWindUp(Math.round(mappedTrueNorthDeg)); + String title = stringMessages.rotatedFromTrueNorth(Math.round(mappedTrueNorthDeg)) + '\n' + + stringMessages.clickToToggleWindUp(); canvas.setTitle(title); NumberFormat numberFormat = NumberFormat.getFormat("0.0"); textLabel.setText(mappedTrueNorthDeg == 0 ? "N" : numberFormat.format(mappedTrueNorthDeg)); From 23348dd338dadb3868d3500fb249dd13a3c8ccc8 Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Jul 2016 17:21:37 +0200 Subject: [PATCH 248/259] Adjusted subscription information in notification mails --- .../resources/stringmessages/StringMessages.properties | 2 +- .../resources/stringmessages/StringMessages_de.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 1cca8467120..20daf51e466 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -27,7 +27,7 @@ boatClassUpcomingRaceSubject=A race for boat class {0} will start soon # 0: boatClassName, 1: raceDescription, 2: time boatClassUpcomingRaceBody=For boat class {0} {1} will start approximately at {2}. -subscriptionInformation=You are receiving notifications from SAP Sailing Analytics. To turn off notifications, please visit your profile at the link below. +subscriptionInformation=You are receiving notifications from SAP Sailing Analytics. To turn off notifications, please visit user your profile at the link below. userProfile=User Profile imprint=Imprint privacy=Privacy diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties index 33863a527f0..2ce5ae96bc8 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties @@ -27,7 +27,7 @@ boatClassUpcomingRaceSubject=Wettfahrt in Bootsklasse {0} startet bald # 0: boatClassName, 1: raceDescription, 2: time boatClassUpcomingRaceBody=In Bootsklasse {0} startet {1} um etwa {2}. -subscriptionInformation=Bei dieser Mail handelt es sich um eine automatisierte Benachrichtigung aus der SAP Sailing Analytics. Die Benachrichtigungen können im Benutzerprofil (s.u.) abgeschaltet werden. +subscriptionInformation=Bei dieser Mail handelt es sich um eine automatisierte Benachrichtigung von SAP Sailing Analytics. Die Benachrichtigungen können im Benutzerprofil (s.u.) abgeschaltet werden. userProfile=Benutzerprofil imprint=Impressum privacy=Datenschutzerklärung From 77a3bd56b39b6bf94f39966927ffecb543dd538b Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Wed, 20 Jul 2016 17:22:08 +0200 Subject: [PATCH 249/259] Generically solve HTML encoding issues in notification mails --- .../StringMessages_de.properties | 14 +++--- .../impl/NotificationSetNotification.java | 45 ++++++++++++++----- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties index 2ce5ae96bc8..17c634fa2e8 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages_de.properties @@ -3,32 +3,32 @@ raceInFleetInRegattaOfEvent=Wettfahrt {0} ({3}) der Regatta "{1}" bei Veranstalt leaderboardOfEvent=Rangliste "{0}" bei Veranstaltung "{1}" leaderboardShowResultsLinkTitle=Ergebnisse anzeigen -racesOverviewLinkTitle=Wettfahrtübersicht anzeigen +racesOverviewLinkTitle=Wettfahrtübersicht anzeigen raceboardShowRaceLinkTitle=Wettfahrt anzeigen raceboardRaceAnalysisLinkTitle=Wettfahrtanalyse anzeigen boatClassRaceFinishedSubject=Wettfahrt für Bootsklasse {0} beendet - Neue Ergebnisse verfügbar # 0: boatClassName, 1: raceDescription -boatClassRaceFinishedBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. +boatClassRaceFinishedBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. boatClassScoreCorrectionSubject=Neue Ergebnisse für Bootsklasse {0} verfügbar # 0: boatClassName, 1: leaderboardDescription -boatClassScoreCorrectionBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. +boatClassScoreCorrectionBody=Neue Ergebnisse für Bootsklasse {0} in {1} sind verfügbar. competitorPassesFinishSubject=Teilnehmer {0} hat eine Wettfahrt beendet # 0: competitorName, 1: raceDescription -competitorPassesFinishBody=Teilnehmer {0} hat bei {1} die Ziellinie überquert. +competitorPassesFinishBody=Teilnehmer {0} hat bei {1} die Ziellinie überquert. competitorScoreCorrectionSubject=Neue Ergebnisse für Teilnehmer {0} # 0: competitorName, 1: leaderboardDescription -competitorScoreCorrectionBody=Für Teilnehmer {0} in {1} sind neue Ergebnisse verfügbar. +competitorScoreCorrectionBody=Für Teilnehmer {0} in {1} sind neue Ergebnisse verfügbar. boatClassUpcomingRaceSubject=Wettfahrt in Bootsklasse {0} startet bald # 0: boatClassName, 1: raceDescription, 2: time boatClassUpcomingRaceBody=In Bootsklasse {0} startet {1} um etwa {2}. -subscriptionInformation=Bei dieser Mail handelt es sich um eine automatisierte Benachrichtigung von SAP Sailing Analytics. Die Benachrichtigungen können im Benutzerprofil (s.u.) abgeschaltet werden. +subscriptionInformation=Bei dieser Mail handelt es sich um eine automatisierte Benachrichtigung von SAP Sailing Analytics. Die Benachrichtigungen können im Benutzerprofil (s.u.) abgeschaltet werden. userProfile=Benutzerprofil imprint=Impressum -privacy=Datenschutzerklärung +privacy=Datenschutzerklärung salutation=Hallo {0}, \ No newline at end of file diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java index 696aab0aca7..cffac440ac8 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -107,32 +107,45 @@ public abstract class NotificationSetNotification implements MailNotification private String getMailContent(NotificationMailTemplate notificationMailTemplate, User user, Locale locale) { StringBuilder bodyContent = new StringBuilder(); if (notificationMailTemplate.getTitle() != null) { - bodyContent.append("

        ").append(notificationMailTemplate.getTitle()).append("

        "); + bodyContent.append("

        ") + .append(notificationMailTemplate.getTitle()) + .append("

        "); } String name = user.getFullName() == null || user.getFullName().isEmpty() ? user.getName() : user.getFullName(); - bodyContent.append("

        ").append(messages.get(locale, "salutation", name)).append("

        "); - bodyContent.append("

        ").append(notificationMailTemplate.getText()).append("

        "); + bodyContent.append("

        ") + .append(htmlify(messages.get(locale, "salutation", name))) + .append("

        "); + bodyContent.append("

        ") + .append(htmlify(notificationMailTemplate.getText())) + .append("

        "); for (Pair link : notificationMailTemplate.getLabelsAndLinkUrls()) { - bodyContent.append("
        "); + bodyContent.append(""); } String siteLink = "" + notificationMailTemplate.getServerBaseUrl() + ""; StringBuilder footerLinks = new StringBuilder(); - footerLinks // - .append("").append(messages.get(locale, "userProfile")).append("") + .append("/gwt/Home.html#/user/profile/:\">") + .append(htmlify(messages.get(locale, "userProfile"))) + .append("") .append(" | "); footerLinks.append("") - .append(messages.get(locale, "imprint")).append("") + .append(htmlify(messages.get(locale, "imprint"))) + .append("") .append(" | "); footerLinks.append("") - .append(messages.get(locale, "privacy")) + .append(htmlify(messages.get(locale, "privacy"))) .append(""); - String subscriptionInformation = messages.get(locale, "subscriptionInformation"); - return TEMPLATE // + String subscriptionInformation = htmlify(messages.get(locale, "subscriptionInformation")); + return TEMPLATE .replace("${title}", notificationMailTemplate.getSubject()) .replace("${content}", bodyContent.toString()) .replace("${subscription_information}", subscriptionInformation) @@ -141,6 +154,14 @@ public abstract class NotificationSetNotification implements MailNotification ; } + private String htmlify(String source) { + StringBuilder result = new StringBuilder(); + for (char c : source.toCharArray()) { + result.append(("\"<>&".indexOf(c) >= 0 || c > 127) ? ( "&#" + (int) c + ";") : Character.toString(c)); + } + return result.toString(); + } + protected abstract NotificationMailTemplate getMailTemplate(T objectToNotifyAbout, Locale locale); } \ No newline at end of file From 382428bd3d083380a7ea062679405dcef0fbbcc3 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 20 Jul 2016 18:42:06 +0200 Subject: [PATCH 250/259] fixed notification message text Change-Id: I54f34f6886c7bb76246790d7343fe72a2abc7e34 --- .../resources/stringmessages/StringMessages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties index 20daf51e466..17c2bfeaa76 100644 --- a/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties +++ b/java/com.sap.sailing.server/resources/stringmessages/StringMessages.properties @@ -27,7 +27,7 @@ boatClassUpcomingRaceSubject=A race for boat class {0} will start soon # 0: boatClassName, 1: raceDescription, 2: time boatClassUpcomingRaceBody=For boat class {0} {1} will start approximately at {2}. -subscriptionInformation=You are receiving notifications from SAP Sailing Analytics. To turn off notifications, please visit user your profile at the link below. +subscriptionInformation=You are receiving notifications from SAP Sailing Analytics. To turn off notifications, please visit your user profile at the link below. userProfile=User Profile imprint=Imprint privacy=Privacy From 90d9ea47de2ce9035b021dad5dd8e7b37b2c8538 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Wed, 20 Jul 2016 22:45:05 +0200 Subject: [PATCH 251/259] handle QUERY_STRING better in apache 000-macros.conf; locale is now properly put before fragment in rewrite rules Change-Id: Ied02e5c7d7cedfc0707209dfaa48c8dc7fb952e0 --- configuration/000-macros.conf | 38 ++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/configuration/000-macros.conf b/configuration/000-macros.conf index cee541ab0eb..926d3f5a2f7 100755 --- a/configuration/000-macros.conf +++ b/configuration/000-macros.conf @@ -155,7 +155,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "http://$HOSTNAME/dashboards/RibDashboard.html?leaderboardName=$LEADERBOARD_NAME&%{QUERY_STRING}" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "http://$HOSTNAME/dashboards/RibDashboard.html?leaderboardName=$LEADERBOARD_NAME&%1" [L,NE] Use Rewrite $IP $PORT @@ -216,7 +218,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html?%{QUERY_STRING}#/event/:eventId=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html?%1#/event/:eventId=$EVENTUUID" [L,NE] Use Rewrite $IP $PORT @@ -236,7 +240,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html?%{QUERY_STRING}#/event/:eventId=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html?%1#event/:eventId=$EVENTUUID" [L,NE] Use Rewrite $IP $PORT @@ -251,7 +257,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html?%{QUERY_STRING}#/series/:seriesId=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html?%1#/series/:seriesId=$EVENTUUID" [L,NE] Use Rewrite $IP $PORT @@ -271,7 +279,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html?%{QUERY_STRING}#/series/:seriesId=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html?%1#/series/:seriesId=$EVENTUUID" [L,NE] Use Rewrite $IP $PORT @@ -286,7 +296,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html#/regatta/overview/:eventId=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html?%1#/regatta/overview/:eventId=$EVENTUUID" [L,NE] Use Rewrite $IP $PORT @@ -316,7 +328,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html#/event/:eventId=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/Home.html?%1#/event/:eventId=$EVENTUUID" [L,NE] Use Rewrite 172.31.30.89 8888 @@ -336,7 +350,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html#/event/:eventId=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html?%1#/event/:eventId=$EVENTUUID" [L,NE] Use Rewrite 172.31.30.89 8888 @@ -352,7 +368,9 @@ RewriteEngine on RewriteCond %{REQUEST_URI} "^(/)?$" - RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/RegattaOverview.html?event=$EVENTUUID" [L,NE] + # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment + RewriteCond %{QUERY_STRING} "^(.*)$" + RewriteRule ^(/)?$ "http://$HOSTNAME/gwt/RegattaOverview.html?event=$EVENTUUID&%1" [L,NE] Use Rewrite $IP $PORT @@ -556,4 +574,4 @@ Use Rewrite 172.31.18.218 8888 - \ No newline at end of file + From 34c89fd4b6fa57172620f8f1e409b690fae42d0f Mon Sep 17 00:00:00 2001 From: EC2 Server Date: Wed, 20 Jul 2016 21:12:46 +0000 Subject: [PATCH 252/259] fixed Event-SSL macro --- configuration/000-macros.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configuration/000-macros.conf b/configuration/000-macros.conf index 926d3f5a2f7..0d7421cac38 100755 --- a/configuration/000-macros.conf +++ b/configuration/000-macros.conf @@ -242,7 +242,7 @@ RewriteCond %{REQUEST_URI} "^(/)?$" # The following matches the query string and captures it in group %1 for the RewriteRule to use before the fragment RewriteCond %{QUERY_STRING} "^(.*)$" - RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html?%1#event/:eventId=$EVENTUUID" [L,NE] + RewriteRule ^(/)?$ "https://$HOSTNAME/gwt/Home.html?%1#/event/:eventId=$EVENTUUID" [L,NE] Use Rewrite $IP $PORT From 180a2243913813ec63b081fde24fddafbbd50ccc Mon Sep 17 00:00:00 2001 From: Papick Garcia Taboada Date: Wed, 20 Jul 2016 23:13:25 +0200 Subject: [PATCH 253/259] Inlined CSS style in HTML template, reduced logo size to fit size expected in email, added new lines for last item in message bundles --- .../notification-mail-template.original.html | 100 ++++++++++++++++++ .../notification/impl/sap_logo_header.png | Bin 6388 -> 3446 bytes .../stringmessages/StringMessages.properties | 2 +- .../StringMessages_de.properties | 2 +- 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.original.html diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.original.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.original.html new file mode 100644 index 00000000000..3747718bfac --- /dev/null +++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.original.html @@ -0,0 +1,100 @@ + + + + + ${title} + + + + +
        +
        +
        + Sailing Analytics +
        +
        + ${content} +
        +
        + +
        + + \ No newline at end of file diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/sap_logo_header.png b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/sap_logo_header.png index e5d2daf91f3962deb5be2991141b8145186e982a..cac9fd66d0730f102f398e4ba7f131db86723300 100644 GIT binary patch literal 3446 zcmai1dpy(YAD?cR97IQntVOwGV_2CHu|?*tTxv2itjySkt&|R;$)y~eLX+eYl1oHL zY~j7jRxbAQCO)dw(IbGI7U_4qji8s2Jrw{D5?>p9fcV560Kg`3qKzHR z&J=^dlSvSq3)z_fp_9CL-T(lSj^Hgx1R4%RCwX{M5p*5!x(9-{UNb|%pmi78Ssk#Q zsRhV@Od)_YAsP@>ur3e;0wF0bt_Ukb^cOg9rvrAU(Yz2)sGpx7#7`YUrno`Xw6wIK zsxT-Fro!`3p)x#aIJ$}_b?;}AuRMkXDxO00q7liSpfz5cGuelx0|u`N{r!B2ljLP; z`nQxP^-Es7454(K7gP3-7q7E*`dXr6rPwNg|) zeQCMN+mCZZVVjZK%Ai3Jjy{=i-!hh^!yWf=jB-blWV`W$DRRrpcUy(OV9}x@R(ehUh z&V+GxBjQnSJibprQ3>o7^Bb~ew0>f5g^`2`N>A0M;|$PBdRvW;%gz>U50`B-feGW8 z8Z`Nnw9Ty z?)Ig>f+O}PaC`c<8Mbeg(Z`}%D5|VHFYl)6RGcuo z0uPEt?KTlH&pv7^=5L!WpKnubTK3X1!iTh*j(F`mbc3!Ii<`~GHud~vb}J;V?^4!% zz2O6BeRrym@G;9G?4_FdCWoQ(OJ&&Hx0w$*@={WM3E(=*hcHv0JSDMxl)4q;NFV2O zljUk(neA%WB2t!;EZ{hj`6|OrPQcMSZRfs3>I6t++oEHQX@-@h`sFOSWhY-W-e0z#QBo%iu6}?OzsuTN3Tk;L!j30U+vG z#U~5RzGq61R8t%8Th0z?Y{?EWS?!$-E?q-2aoGuQY}h!%RzbFpbMtXR#Skj?*cMOM znO2h(NAQV!h4(<;rYzA=O3({cdx^Wq!bib6JGl~|V`A>s5weF#zYLD054TFCM#d6j z-sO9|x(9S(m)3P#cWNcuJ4YrdliBEKKZ<+^R(%jVbW(OHyYwn46i%vRS^7Nisfl z2PRJ>pProZgO}4o>M-^vka$GE)RW1wPm{uKgRZr23a-xCx3?Vr_@WU!K9W;@ffD|7 z^J(T9{~ z*NCb&Q04*BGFQ*+KfBVv?>cA{z){(H#~x@HJHj}>A}4we0}gUwO|r)W-pNe%7Cb&P z&_cS(VU3a5OZ7E1k>=+|>c`?YW=^psqv?6)C6e7kh$A40*8b77I1jJ1u6}#{haLQu zjrj*^97aDaOyQ&_n9n%U9$17p-?M@z(N0j|eXV)9TOPBOEnSk(H9*v~{fbEd{Q-Y> zbe0Hm)o3>S{!LFJm-M?P`v%YZ;p#dnG+lJ5%j&s{cmu zu4%B*u45;As-uf8oE2ZFP!F_arw=T%YpjjA_$~!FluUVm&N;!r@IjLbk6(Ob91tDG z@;q%Jj8)z(nkZp#GQhjG^mHCLMX#~R@Kw~WA>HNE$Lg>_k{6`tl1q~*rah1E2#(9L zE+_RH;S>2|YvUK6_FoZtLPHk=$i^G}CgP4VQzL5yW4js;u}y=8R99kg*aD6lyyd~W z{&KuA*HdQ-IBM{s_)u`O@}yryP}6eJ=sQ2jIN+l$p&)=*bYId)?2tJ>#Jine^q$7k zhRY(1s*66Ty$(`JCH0NzxsQ&)^Mhjk91*@>mCIqSR!3Bw35>enFdc}Z-nd#W8|hrn zmAb`Qg><{fd&&}a`!Wjs(rd$%- z%#DB79*D+)y^BiFC#i(RhVvVsu)-kQ{a({0x*iu)gF8i9o(5{g3d{k)2^!7q4;PPY zW$!L!CaEMbOUf9oj9b$MoU%Fnt?r$9F}9=9B6=kg5!p5~eQmhAcAkU>F-WKk*0$+w za84+UNo6LMzptKbQD9xPAFIJ!gz9Q4&K0dHOHM1+E?Zr8E_0YWMZxZK99{)%07^}@ zduz66y?imCRdQ+O?uzu(G4YA3q4K3$rDpQDgZ-ei`sg>#>d9@&zM~lYt)h?bUl!sQ zqv6)~k52}0y&{Ruo9wtNnJIr|*inu@*V!mXCJIE*_!`1{_C0O)cq28;I2E4ZqO~Ab zT$bh>OzXs4Xzi6+ntk9`81`GecszCY>{Btj&xNFTG> zF#ZL(((w8Z^zi1r>9^nSDZhqc$>#rgTqjA5-j>`pz*ro4ZE&#ydp7KS`V$xK@1qU= zj{aem*YC^d>0UTt{m_T*^XGG`QEq9{^)VB~s*ri3c3Qa^HgxT0$QWg2m~+G_@PEV_ B>O24d delta 6007 zcmYjVcQhQpw_b$ky+z;Eq6Dk=Rl|xF5z*@^i(RZQGxvOF&i&*5;yMDOQ_M{b=%~4<0RR9U)KJgjuYLA+ znp0BzT?5M5{sA|F^sR&L`FR9|x}e+v+Au#?cL6BE#nauw-31mNFzBuh0FVj6EvQZl#PWE8;yit$qRFMuMu z`G0_(pIb1(9U1iB05{o9Qjlg2DJyeekcGR4D*XSmj7k5o{sX}NKdXxLCK@EIDWEQm zf_bRwxd*zT;Qm2yKjig}sn5l&taWH#j2?v4kL;A(D?#`!3Uf>T6|Ol1u`M-GgiC?=r` zz6|5!M7%xZGe&pJ{UChpHWI1CkEeQ0>!5z%nsT^WA0 zY|&-e6`D_sx%z{=Gc^^!szpx=7WxgkD_1D2FIFjS-yg-96Lgm|>7$!Rf=-N^A}uug zTux{c+RSS4=%tL1Fu)SF3H>%eK}m;(iUDkf&1o6Aa*Vmn@AqUw6bn9Qt;sGi0&0!D zVn1iWRDeJI0bIsjhB*jqcH(M6KkJPgLplEfIxe5zYXu< zdfsJB%@wpi$3BdfQyAdp+ROMB5Ut2cE!e<-kaf-$+9F%3UX*x78Pqhue1(orabog} z9mB^xduZ}hzuj!EB}Vxv?(LcDf>6mMcc`(bkcY@x=%2VFbXKfKw)v)vi$^PY8g*U4 zmTbjm%G<= za{0`MEfezMju@=iovpL+1`*v7&N|bgCEb;(LQf}f@Ab$h-lO=nTIt=B*BS6xJbji^QgK;3vy_d98k;Y1?O?h2#%;mWnjYhqok}-R5~X ztRAR3E8s&Z!cK^YEqwnLvNODjrkwGnO}bsmm*-tU_Pun9 z0aQ@!8-@h_MevPglq8zUVP1+C?^unH7f$kRacg#X;`$#vjosT7JS|11rqI7Z^_gx%2XV-u+38e z%Z{Z|U;nwwT*&_nOyro((zzeToBn%#LilvyT+&t!RTpP8evzU3>bX>1CWc>{hAYL( zk#uQsG-UaAWg^V)#mFDTCe?~)hb-XsA zRFl;LNQM?QMtFPJ?{#c|s?G6ty0iR`WxRDHmw-XC0ucv zm2DEsH&`Cx`eO9(mkVP^Mb`nZ;2RwC!wc60Me z2+{ZXLh%sq4`KhzVB)3b3noSyxZve}s=C4g7g~Q&;q5gN8DAEZw+Yk2_t5Wz%Tw@m z2bD9diQc8c$HkGbgPBHp<#)P3_u+nD1&PTxe87UTQ`eO6Fu=X!tlEuy?17i=$Y@)w zFQ>^>g%1^(Kw6FHj_{k|Pi@P!%+YB!vp2A>3{>BARnZ(T06K?33BV4h$b=M-fYd1* zLdTKoE85@N!b<*hMF{FWd&i%N@L_Jn@R0W%jp;4Qs>4muB z%%M{*V}aitg6G4o>hd?VtoS>grmZn^hpu$b+r~k z@Mw@y#sKeO{ksrUQhmubH$kltc~4^tO_^+;=bZC}f8459%$#1IqVMU)=Y!oh38`#r zfI1++fr;ciAA%s5k~SHVXOQVEJe49now;#E~-?|(yB7Th1g6mn8F_rw6x0!y=SD0uhYtfw3nv7eZuJKtHU=r~m=d%W#k$u3z z0QPo_;s}cL=Nze>j)=!`5XYsvL2hzadS2tEr#7z^t1Z?jw%Jfnh$?RCw#eWUY4!H< z;fn8mg>{8I9ywKoC2(f0kF^r$Pn9*aH%0kkFN_B`#X`JJq_*K%>16;O4;62+QlhZ9 zgBO#|QDLZQ#GBtO9J#Weyg;4_=xV)yTlAmiw2g~u%*XK8_O?Irgkh|Ga9-N9##2`| z?x$tz_Xp$;c?`qCog|D({}!ok>#yt0$tFWynxn19vRzv+Eg|yQivS&TtFfe%r|D15PLd94FP1(CZ&%a2`zwhzfTGuEW!|_?!kitdmVW~FceQ4beSnmO0FmOyu zWE7*|_^IvY5J;F~><3UHyE9bSyLN6U3FkPZJ1auFyT{-&)(${&MQdP zFnjWtwy9xcXo4N!ceq@6@w!O!o{n!*i+Zl&gPYy&+)P&Ko;BV(L(fotmwF+{k`rfK zSm$v^rv^z(-_%)bm*<%MpusE6%*pWpmI?xdhMG${-(>wT(3MQLG5x09!VW(i(xg_t zI5AGFG>|wM83HzIr&snXxG@J;k-j(jkr2#ggb)#mAP8M!s`2nsuyP^0jQJV#Znu83 zca|_8b||Nmp>(z+f(}{xjIm{_Lw5ue?Tw^054w$e`1=Vm@*#ipRFAWJCu5|Fw^)Id z&AgXA_|8V$OF6SK=OusO$$_A*QWW-Tu`3@n~t)#N3006jPJ(;2c{! z1&K5)|D$p@=Jl}XO92FcroR5OW677LUo;eEA>cS<@UZdJ)N~qz*W1i+DZj9KD~Z`R z+F3*~#!Z#4yOmMcv>8zG1g17yG?|sI*k)+w;c158s2vnp3!B|wL4LA5qDOTW^cYwT zM(E1BWhyXQqV-%31Si>mv-KKLA+-~t*76Sb_nk#pd%WLD?Y60Le;H#locd%<|U?|65T*zWF5J?udk-RJ}M*+IbR)vLN{a6 zJ|7I^xXzi16Th_89-uL^%PoU_7VbRp_A&4>N-B6ZS+Ij^piLjX(O2|9W3NNf>1*(} zksLX0fzjX6xR&@pws1AbuP4>e*Jxzx@&g2!7M&$WFv04C-Q|+ zb`E!P#)w*mOjf(kIo6!55jZQ9xiyy(0kiFg*<-R8zT-A?qyLRuTS7Q=U0xikjV=E{i|$}cxWk+&Ei(oFSbA`KyY)368k zl@%N^%@n3$n(o!CbRRUPdi$Ta&Wg2dT+ZJyo2~u{5W>#Z!dSwMH#05VQ0YFQ;EtA$R`tR=jh1m7IO+ z`4NPb-m3aKqtpC+!eXaWrsSA2dXqIdV+@=E>b|ZZOz@kJ=p?f<3v#~gLSf~QgR%R* zwuEY$kgPf-wkjMR$|TaB-al+cD-e|MUSmZ2u>Vg^f7a*p zym-u&32g>A$3UWioQ_sxyx!t_>MBmA-z?OzYL7-Wmi>Dpr9&!v8w8Gh`Ho}=%bYKVQMMi`G#dysG6GbTd2!QX;zp(oO3b|HMCz6ub zL%Xfv^`QB0ctT6?*{S0ePS9zkTY$@fK}s@SIjnBE#$9HS#LvRBjF&I{wG?u>lO zFyL@DO%W7Zg;&xwKW_OXp*FfqCYz>w4S%T4cpVp^pYta(au-7K>gsfIe{uy^H$cQ( z))Uw2fRM~izFGVVYkl&`rsiXb3aIm9(^#}AuWv?VcAPKE+yI6qgoM~ZoTf))myxHJ23oxr9ocrflJvKb~#~L z>*#m*z?<+EYmQlyp8Xq95fs&$5K!7+l=rI5uypW}scm}-NGaFBdaWh-0RC7B0`KvO zEY`E~V(d#Aw{OE>2_AZK(=F-a%6T{mY=DI#@Xu%?nvQHg%Cbkd)6Lz|YL!PMKP-Uc zrA_t85Wm|~B5>9n^w8g^n|ElSc>^W!8ug|>?LnIoRz-)eleiybYV$L2t~VyV#fD8U zLRU=M(1eq6I_tv=Nfv3ekK*N<4kl^DE5f@BM_AUyGf~#QO{LZzk)k<8h*^H*FhRg` z3U*fp&5hql4@qnJL{6y7_-&_Y?m6FNVJz_xn`vdWvi*Q#HSuJ7KR^1G^4B>!o02T) zv{Kb4rG%o|_;Ko4Sm-VB5`TeCII=7vB7egn#rkW^vUfoWu&*G?#{X_5jgJ)f&8j+~ zi9=i|$MSOV(80z-kMmuB?q4|(h+kQR8|FA&^bXlay^ErBPtB>~>6O8bYTzim&|e@Z zCDpT(#OH#+$b^&P5ny?V-ye1Pj9VnrTGD)}X{k8vj-HRe@o<@4unz;5+Iif;x%OLX z0yOPj4gy~?W-M73)RVPrTqE~c1L%uo8gCpkbM=Ku7p?Tp+~i4yUXw*?wUUT`dM2rl zM$8oKcb>!%Jase!a|(7Mm7ZiTOL7}Rdz>%FAL5+Rgdfm|-!?e(893=lt#4cx^YQBkVoyW6YcD1&dq0}a{J$F@BDEh7o1!_=ig_g`Sh0}|NwqA6J7c!Yx z#LmAp8|~#q#1AuH?~V#?q|_HCPgt#WgX_pGJ!Le>gd}f!z-ZW2_$wqRl ztORyc5tnWB>5nkX{#@mowgnT;|AuDcTwb4$r#?E_LnqOt z|1H(;LZ`A*%bB>SEQ@^UgcaXiHn~W%cL7Q2!3N6B&h(yKEz|@9rCcL3WlC^;Xq2{$ zbGiSmYqAL0GQs<;d!YvYOF^DvY60yt@z*I0FsKa-hKz|nA$T>J8Y2F_KsiX9GV zFHN&(<3Y0FtH7>|R=JNxx4M+WTIDuRX_{BauVdes)MS*g-6#)d23=oIpZ}ihzy*#( ziC9UAGjDC?P;=~jJFVIFZt7Cp@#~ea^A1R`{;WfL^x0(nef`^V%K)^(OIPlEMZEPB zkxO&shY^Q8?Di@e0SBYq1Tf|(w6~w6qKWGIy^3qqpM+wf>iW~nOv`a!(HiNSxjgNu zCHcSa*%#RD;pG2l&bp**?Wk*Rtc<@y?r3~@$V-@cb8N^xl5OBEy!3{bK#y;#A0h>nc_cB z^p4qo`$zp8vg-S~2ViJuAUz00IuTC4GzmQ=^dI)NzIc|Vuc^weNVpQ+p*_jK#AvK8j= zals2&L`piFc)a*?Y2Po$ghzP(7@&D+!^2(qY??8u8+b5S1jq)k6e5dd%1C+G`$F#N zvp9@$UlOPI6yTX3iIy(!-xi{I4+V>9SopBBR-c+_Wu2(>sb{}Dr*VNSAZb@i_wWC7 zF?VqV+`IvJwD9k~JwP5U#dvMTt-nFy%J?nL^zrk4OPo-hSs6`aZ<1Hu6^Anb6l8vH T(R_9PUl$yzZ>m?X;~e*2 Date: Thu, 21 Jul 2016 09:08:55 +0200 Subject: [PATCH 254/259] Inlined CSS style in HTML template, reduced logo size to fit size expected in email, added new lines for last item in message bundles --- .../impl/notification-mail-template.html | 104 ++++-------------- 1 file changed, 20 insertions(+), 84 deletions(-) diff --git a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html index f87055492cf..c9dba3e0a9d 100644 --- a/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html +++ b/java/com.sap.sailing.server/resources/com/sap/sailing/server/notification/impl/notification-mail-template.html @@ -1,94 +1,30 @@ - + - + ${title} - - - -
        -
        -
        - Sailing Analytics + + + +
        +
        +
        + Sailing Analytics
        -
        - ${content} +
        + ${content}
        -
        - +
        -
        - + \ No newline at end of file From a448907f7379d4a08aca97633fc9fb7f519e116e Mon Sep 17 00:00:00 2001 From: Steffen Schaefer Date: Thu, 21 Jul 2016 09:20:44 +0200 Subject: [PATCH 255/259] Added inline style to buttons in notification mails to improve compatibility with mail clients --- .../server/notification/impl/NotificationSetNotification.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java index cffac440ac8..0938e6e679e 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/notification/impl/NotificationSetNotification.java @@ -122,7 +122,7 @@ public abstract class NotificationSetNotification implements MailNotification bodyContent.append(""); From 62ef60f866fa6b35d81231ed76dee57e8684322b Mon Sep 17 00:00:00 2001 From: Benjamin Barth Date: Thu, 21 Jul 2016 10:11:08 +0200 Subject: [PATCH 256/259] Fixed REPLICATE_ON_START arguments of replica run configs --- ...gServer (No Proxy, Jetty on 8889, auto-replicate dev).launch | 2 +- ...ilingServer (No Proxy, Jetty on 8889, auto-replicate).launch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch index 8626d607ce6..cc3000cf396 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch @@ -19,7 +19,7 @@ - + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch index 35cda4030e8..71b2a9a98dd 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch @@ -21,7 +21,7 @@ - + From eaf5d32cf62d8b8a32854585aecbf11b8697e6bc Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 21 Jul 2016 11:13:07 +0200 Subject: [PATCH 257/259] changed toggleExpansion() to changeExpansionState(boolean), queueing not toggles but desired expansion states; see bug 3797 Change-Id: I2da4ce90f48c5eecb5fea7c41c0a5756bd59bb16 --- .../ui/test/GwtTestCaseColumnToggling.java | 4 +- .../leaderboard/ExpandableSortableColumn.java | 110 ++++++++++-------- .../gwt/ui/leaderboard/LeaderboardPanel.java | 14 +-- .../SortableExpandableColumnHeader.java | 2 +- 4 files changed, 72 insertions(+), 58 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java index e6383c266c8..3a3c4a156a0 100644 --- a/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java +++ b/java/com.sap.sailing.gwt.ui.test/src/com/sap/sailing/gwt/ui/test/GwtTestCaseColumnToggling.java @@ -206,7 +206,7 @@ public class GwtTestCaseColumnToggling extends GWTTestCase { }); } - private void removeColumnAndAssert(){ + private void removeColumnAndAssert() { service.removeLeaderboardColumn(LEADERBOARD_NAME, COLUMN1_NAME, new AsyncCallback() { @Override @@ -220,7 +220,7 @@ public class GwtTestCaseColumnToggling extends GWTTestCase { leaderboardPanel.updateLeaderboard(leaderboard); assertNotNull(rc); try { - rc.toggleExpansion(); + rc.changeExpansionState(/* expand */ !rc.isExpanded()); leaderboardPanel.updateLeaderboard(leaderboard); } catch (Exception e) { fail("Toggle column failed." + e.getLocalizedMessage()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java index b7134a7903c..48b0a599fa9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/ExpandableSortableColumn.java @@ -3,11 +3,13 @@ package com.sap.sailing.gwt.ui.leaderboard; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.Map; import com.google.gwt.cell.client.Cell; import com.google.gwt.cell.client.Cell.Context; +import com.google.gwt.core.client.GWT; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; import com.google.gwt.user.cellview.client.CellTable; @@ -28,7 +30,7 @@ public abstract class ExpandableSortableColumn extends LeaderboardSortableCol private boolean enableExpansion; /** - * Set when the {@link #toggleExpansion()} method begins with its work. Three things can happen: + * Set when the {@link #changeExpansionState(boolean)} method begins with its work. Three things can happen: *
          *
        1. the column is to be collapsed. This can happen synchronously, and the flag is cleared again before the method * returns
        2. @@ -41,13 +43,13 @@ public abstract class ExpandableSortableColumn extends LeaderboardSortableCol private boolean togglingInProcess; /** - * If {@link #togglingInProcess} is {@code true} and a call to {@link #toggleExpansion()} is received, - * instead of running the method, the request is "queued" only by incrementing this counter. When the - * asynchronous task completes the running toggle action, the counter is decremented by one and - * {@link #toggleExpansion()} is called. This way, overlapping asynchronous requests triggered by calls - * to {@link #toggleExpansion()} are avoiided. + * If {@link #togglingInProcess} is {@code true} and a call to {@link #changeExpansionState(boolean)} is received, + * instead of running the method, the request is "queued" only by appending the desired expansion state. When the + * asynchronous task completes the running toggle action, the first request is picked from the list and + * {@link #changeExpansionState(boolean)} is called. This way, overlapping asynchronous requests triggered by calls + * to {@link #changeExpansionState(boolean)} are avoided. */ - private int numberOfQueuedToggleRequests; + private final LinkedList queuedToggleRequests; private boolean suppressSortingOnce; private final LeaderboardPanel leaderboardPanel; @@ -73,6 +75,7 @@ public abstract class ExpandableSortableColumn extends LeaderboardSortableCol SortingOrder preferredSortingOrder, StringMessages stringConstants, String detailHeaderStyle, String detailColumnStyle, List detailSelection, DisplayedLeaderboardRowsProvider displayedLeaderboardRowsProvider) { super(cell, preferredSortingOrder, displayedLeaderboardRowsProvider); + this.queuedToggleRequests = new LinkedList<>(); this.enableExpansion = enableExpansion; this.leaderboardPanel = leaderboardPanel; this.detailSelection = detailSelection; @@ -141,7 +144,7 @@ public abstract class ExpandableSortableColumn extends LeaderboardSortableCol /** * Determines the direct and transitive child columns that due to the current expansion state should be - * visible. Note that for columns not currently visible or currently being expanded (see {@link #toggleExpansion()}), + * visible. Note that for columns not currently visible or currently being expanded (see {@link #changeExpansionState(boolean)}), * the column collection returned does not necessarily contain only columns really part of the {@link CellTable} * used to display this column. */ @@ -167,62 +170,73 @@ public abstract class ExpandableSortableColumn extends LeaderboardSortableCol *

          * * Precondition: this column must currently be contained in the {@link CellTable} showing the - * {@link #leaderboardPanel leaderboard}.

          + * {@link #leaderboardPanel leaderboard}. + *

          * * When the method starts to toggle the expansion state, it sets the {@link #togglingInProcess} flag. When the * method returns the {@link #isExpanded()} method yields the new expansion state. However, when the column contents - * need to be loaded asynchronously first, the expansion will not have affected the table structure yet and is - * still "pending." This state is indicated by the {@link #isTogglingInProcess()} method returning {@code true} - * after this method has returned. Only after the asynchronous data loading has happened and the table has - * actually been updated to reflect the expanded state, the {@link #isTogglingInProcess()} will then again - * return {@code false}. + * need to be loaded asynchronously first, the expansion will not have affected the table structure yet and is still + * "pending." This state is indicated by the {@link #isTogglingInProcess()} method returning {@code true} after this + * method has returned. Only after the asynchronous data loading has happened and the table has actually been + * updated to reflect the expanded state, the {@link #isTogglingInProcess()} will then again return {@code false}. + * + * @param expand + * if {@code true} the column will be expanded if not already expanded, if {@code false} the column will + * be collapsed if not already collapsed */ - public void toggleExpansion() { + public void changeExpansionState(boolean expand) { if (isExpansionEnabled()) { if (isTogglingInProcess()) { - numberOfQueuedToggleRequests++; + queuedToggleRequests.add(expand); } else { final boolean oldBusyState = getLeaderboardPanel().isBusy(); getLeaderboardPanel().setBusyState(true); setTogglingInProcess(true); final CellTable table = getLeaderboardPanel().getLeaderboardTable(); - if (isExpanded()) { - for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { - getLeaderboardPanel().removeColumn(column); // removes only the children currently displayed - } - getLeaderboardPanel().setBusyState(false); - setTogglingInProcess(false); - // important: toggle expanded state after asking for all visible children - setExpanded(!isExpanded()); + if (table == null) { + GWT.log("WARNING: leaderborad table is null"); } else { - // important: toggle expanded state before asking for all visible children - setExpanded(!isExpanded()); - ensureExpansionDataIsLoaded(new Runnable() { - public void run() { - // column may have been collapsed meanwhile, so that the columns must not be added to the table right now - if (isExpanded()) { - int insertIndex = table.getColumnIndex(ExpandableSortableColumn.this); - // The check "insertIndex != -1" is necessary, because the child-columns might be deleted - // asynchronously while toggling the columns. - if (insertIndex != -1) { - insertIndex++; - for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { - column.updateMinMax(); - if (table.getColumnIndex(column) < 0) { - getLeaderboardPanel().insertColumn(insertIndex++, column); + if (!expand) { // collapse + if (isExpanded()) { // but only if currently expanded + for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { + getLeaderboardPanel().removeColumn(column); // removes only the children currently displayed + } + getLeaderboardPanel().setBusyState(false); + setTogglingInProcess(false); + // important: toggle expanded state after asking for all visible children + setExpanded(!isExpanded()); + } + } else { // expand + if (!isExpanded()) { // but only if not expanded yet + // important: toggle expanded state before asking for all visible children + setExpanded(!isExpanded()); + ensureExpansionDataIsLoaded(new Runnable() { + public void run() { + // column may have been collapsed meanwhile, so that the columns must not be added to the table right now + if (isExpanded()) { + int insertIndex = table.getColumnIndex(ExpandableSortableColumn.this); + // The check "insertIndex != -1" is necessary, because the child-columns might be deleted + // asynchronously while toggling the columns. + if (insertIndex != -1) { + insertIndex++; + for (AbstractSortableColumnWithMinMax column : getAllVisibleChildren()) { + column.updateMinMax(); + if (table.getColumnIndex(column) < 0) { + getLeaderboardPanel().insertColumn(insertIndex++, column); + } + } + getLeaderboardPanel().getLeaderboardTable().redraw(); } } - getLeaderboardPanel().getLeaderboardTable().redraw(); + getLeaderboardPanel().setBusyState(oldBusyState); + setTogglingInProcess(false); + if (!queuedToggleRequests.isEmpty()) { + changeExpansionState(queuedToggleRequests.remove(0)); + } } - } - getLeaderboardPanel().setBusyState(oldBusyState); - setTogglingInProcess(false); - if (numberOfQueuedToggleRequests > 0) { - numberOfQueuedToggleRequests--; - toggleExpansion(); - } + }); } - }); + } } } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java index ccc153dd378..2ba5d3184ee 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/leaderboard/LeaderboardPanel.java @@ -423,7 +423,7 @@ public class LeaderboardPanel extends SimplePanel implements Component expandableSortableColumn : columnsToExpandAgain) { - expandableSortableColumn.toggleExpansion(); + expandableSortableColumn.changeExpansionState(/* expand */ true); } if (newSettings.getNameOfRaceToSort() != null) { final RaceColumn raceColumnByRaceName = getRaceColumnByRaceName(newSettings @@ -2254,7 +2254,7 @@ public class LeaderboardPanel extends SimplePanel implements Component expandableColumn = (ExpandableSortableColumn) c; if (expandableColumn.isExpanded()) { // remove expanded child columns from the leaderboard... - expandableColumn.toggleExpansion(); + expandableColumn.changeExpansionState(/* expand */ false); // them remember that column c was expanded: expandableColumn.setExpanded(true); } @@ -2361,7 +2361,7 @@ public class LeaderboardPanel extends SimplePanel implements Component> columnsToCollapseAndExpandAgain = getExpandedRaceColumnsWhoseDisplayedLegCountChanged(leaderboard); for (RaceColumn columnToCollapseAndExpandAgain : columnsToCollapseAndExpandAgain) { - columnToCollapseAndExpandAgain.toggleExpansion(); + columnToCollapseAndExpandAgain.changeExpansionState(/* expand */ false); } competitorSelectionProvider.setCompetitors(leaderboard.competitors, /* listenersNotToNotify */this); if (!initialCompetitorFilterHasBeenApplied) { @@ -2373,7 +2373,7 @@ public class LeaderboardPanel extends SimplePanel implements Component columnToCollapseAndExpandAgain : columnsToCollapseAndExpandAgain) { - columnToCollapseAndExpandAgain.toggleExpansion(); + columnToCollapseAndExpandAgain.changeExpansionState(/* expand */ true); } adjustDelayToLive(); final Map rowsToDisplay = getRowsToDisplay(); @@ -2417,7 +2417,7 @@ public class LeaderboardPanel extends SimplePanel implements Component expandableSortableColumn = (ExpandableSortableColumn) c; if (!expandableSortableColumn.isExpanded()) { - expandableSortableColumn.toggleExpansion(); + expandableSortableColumn.changeExpansionState(/* expand */ true); autoExpandPerformedOnce = true; } } @@ -2683,7 +2683,7 @@ public class LeaderboardPanel extends SimplePanel implements Component { @Override public void execute(SafeHtml object) { - column.toggleExpansion(); + column.changeExpansionState(/* expand */ !column.isExpanded()); } } From d64b2e9a82de328418993158d034fa0c804aefd8 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 21 Jul 2016 11:20:09 +0200 Subject: [PATCH 258/259] push the leaderboard received for a specific time point into the LeaderboardPanel to ensure consistency; see bug 3797 Change-Id: Id2854f6246a491c604658c9254bb7a7114bae9d3 --- .../com/sap/sailing/gwt/ui/raceboard/AbstractRaceBoardMode.java | 1 + 1 file changed, 1 insertion(+) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/AbstractRaceBoardMode.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/AbstractRaceBoardMode.java index 8fd25bf9484..ef621e840e3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/AbstractRaceBoardMode.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/raceboard/AbstractRaceBoardMode.java @@ -148,6 +148,7 @@ public abstract class AbstractRaceBoardMode implements RaceBoardMode, RaceTimesI @Override public void onSuccess(LeaderboardDTO result) { leaderboardForSpecificTimePoint = result; + getLeaderboardPanel().updateLeaderboard(result); trigger(); } }; From f1d4bf541f837d59592592651d0674aa4e475cb4 Mon Sep 17 00:00:00 2001 From: fmittag Date: Thu, 21 Jul 2016 12:40:01 +0200 Subject: [PATCH 259/259] Wrapped CombinedWindPanel and TrueNorthIndicatorPanel into a flowpanel to avoid having 2 controls at the TOP_LEFT position of the google map which is not supported by the GWT Wrapper lib. Adjusted styles accordingly --- .../EmbeddedMapAndWindChart.css | 7 +----- java/com.sap.sailing.gwt.ui/RaceBoard.css | 12 +++------- java/com.sap.sailing.gwt.ui/Simulator.css | 7 +----- .../shared/racemap/CombinedWindPanel.java | 2 +- .../gwt/ui/client/shared/racemap/RaceMap.css | 4 +++- .../gwt/ui/client/shared/racemap/RaceMap.java | 23 +++++++++++-------- .../client/shared/racemap/RaceMapStyle.java | 2 +- .../racemap/TrueNorthIndicatorPanel.java | 2 +- 8 files changed, 24 insertions(+), 35 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.css b/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.css index 6376c253b35..e5a55d6ef7a 100644 --- a/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.css +++ b/java/com.sap.sailing.gwt.ui/EmbeddedMapAndWindChart.css @@ -78,16 +78,11 @@ table { border-collapse: separate; } -.CombinedWindPanelParentDiv { +.TopLeftControlsWrapperPanelParentDiv { padding-top: 34px; padding-left: 10px; } -.TrueNorthIndicatorPanelParentDiv { - padding-top: 10px; - padding-left: 10px; -} - .MapSimulationLegendParentDiv { padding-bottom: 10px; padding-right: 10px; diff --git a/java/com.sap.sailing.gwt.ui/RaceBoard.css b/java/com.sap.sailing.gwt.ui/RaceBoard.css index 4842be0c7c1..bf79c662db7 100755 --- a/java/com.sap.sailing.gwt.ui/RaceBoard.css +++ b/java/com.sap.sailing.gwt.ui/RaceBoard.css @@ -85,21 +85,15 @@ table { border-collapse: separate; } -.CombinedWindPanelParentDiv { +.TopLeftControlsWrapperPanelParentDiv { padding-top: 34px; padding-left: 10px; } -.TrueNorthIndicatorPanelParentDiv { - padding-top: 10px; - padding-left: 10px; -} -.CombinedWindPanelParentDiv.indentsmall, -.TrueNorthIndicatorPanelParentDiv.indentsmall { +.TopLeftControlsWrapperPanel.indentsmall { padding-left: 30px; } -.CombinedWindPanelParentDiv.indentbig, -.TrueNorthIndicatorPanelParentDiv.indentbig { +.TopLeftControlsWrapperPanel.indentbig { padding-left: 45px; } diff --git a/java/com.sap.sailing.gwt.ui/Simulator.css b/java/com.sap.sailing.gwt.ui/Simulator.css index 14581efa50f..8b45204abf0 100644 --- a/java/com.sap.sailing.gwt.ui/Simulator.css +++ b/java/com.sap.sailing.gwt.ui/Simulator.css @@ -494,16 +494,11 @@ table { border-collapse: separate; } -.CombinedWindPanelParentDiv { +.TopLeftControlsWrapperPanelParentDiv { padding-top: 34px; padding-left: 10px; } -.TrueNorthIndicatorPanelParentDiv { - padding-top: 10px; - padding-left: 10px; -} - .MapSimulationLegendParentDiv { padding-bottom: 10px; padding-right: 10px; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java index 62646d403c7..ebc0d0e9371 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/CombinedWindPanel.java @@ -30,12 +30,12 @@ public class CombinedWindPanel extends FlowPanel { public CombinedWindPanel(final RaceMap map, RaceMapImageManager theRaceMapResources, RaceMapStyle raceMapStyle, StringMessages stringMessages, CoordinateSystem coordinateSystem) { - raceMapStyle.ensureInjected(); this.stringMessages = stringMessages; this.coordinateSystem = coordinateSystem; this.raceMapResources = theRaceMapResources; this.raceMapStyle = raceMapStyle; addStyleName(raceMapStyle.raceMapIndicatorPanel()); + addStyleName(raceMapStyle.combinedWindPanel()); transformer = raceMapResources.getCombinedWindIconTransformer(); canvas = transformer.getCanvas(); canvas.addStyleName(this.raceMapStyle.raceMapIndicatorPanelCanvas()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.css b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.css index 9c8056bcd53..21e42e365db 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.css +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.css @@ -26,4 +26,6 @@ .combinedWindPanel {} -.trueNorthIndicator {} \ No newline at end of file +.trueNorthIndicatorPanel { + margin-top: 10px; +} \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java index e4b925227a1..031347fa9ff 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMap.java @@ -355,8 +355,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe private final CombinedWindPanel combinedWindPanel; - private final TrueNorthIndicatorPanel trueNorthIndicatorPanel; + private final FlowPanel topLeftControlsWrapperPanel; private final AsyncActionsExecutor asyncActionsExecutor; @@ -447,10 +447,15 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe panelForLeftHeaderLabels = new AbsolutePanel(); panelForRightHeaderLabels = new AbsolutePanel(); initializeData(settings.isShowMapControls(), showHeaderPanel); - combinedWindPanel = new CombinedWindPanel(this, raceMapImageManager, raceMapResources.raceMapStyle(), stringMessages, coordinateSystem); + RaceMapStyle raceMapStyle = raceMapResources.raceMapStyle(); + raceMapStyle.ensureInjected(); + combinedWindPanel = new CombinedWindPanel(this, raceMapImageManager, raceMapStyle, stringMessages, coordinateSystem); combinedWindPanel.setVisible(false); - trueNorthIndicatorPanel = new TrueNorthIndicatorPanel(this, raceMapImageManager, raceMapResources.raceMapStyle(), stringMessages, coordinateSystem); + trueNorthIndicatorPanel = new TrueNorthIndicatorPanel(this, raceMapImageManager, raceMapStyle, stringMessages, coordinateSystem); trueNorthIndicatorPanel.setVisible(true); + topLeftControlsWrapperPanel = new FlowPanel(); + topLeftControlsWrapperPanel.add(combinedWindPanel); + topLeftControlsWrapperPanel.add(trueNorthIndicatorPanel); orientationChangeInProgress = false; mapFirstZoomDone = false; // TODO bug 494: reset zoom settings to user preferences @@ -552,8 +557,8 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe Image sapLogo = createSAPLogo(); RaceMap.this.add(sapLogo); } - map.setControls(ControlPosition.LEFT_TOP, combinedWindPanel); - map.setControls(ControlPosition.LEFT_TOP, trueNorthIndicatorPanel); + + map.setControls(ControlPosition.LEFT_TOP, topLeftControlsWrapperPanel); adjustLeftControlsIndent(); RaceMap.this.raceMapImageManager.loadMapIcons(map); @@ -2656,18 +2661,16 @@ public class RaceMap extends AbsolutePanel implements TimeListener, CompetitorSe getRightHeaderPanel().setStyleName(COMPACT_HEADER_STYLE, isCompactHeader); // Adjust combined wind and true north indicator panel indent, based on the RaceMap height - if (combinedWindPanel.getParent() != null && trueNorthIndicatorPanel.getParent() != null) { + if (topLeftControlsWrapperPanel.getParent() != null) { this.adjustLeftControlsIndent(); } } private void adjustLeftControlsIndent() { - combinedWindPanel.getParent().setStyleName("CombinedWindPanelParentDiv"); - trueNorthIndicatorPanel.getParent().setStyleName("TrueNorthIndicatorPanelParentDiv"); + topLeftControlsWrapperPanel.getParent().setStyleName("TopLeftControlsWrapperPanelParentDiv"); String leftControlsIndentStyle = getLeftControlsIndentStyle(); if (leftControlsIndentStyle != null) { - combinedWindPanel.getParent().addStyleName(leftControlsIndentStyle); - trueNorthIndicatorPanel.getParent().addStyleName(leftControlsIndentStyle); + topLeftControlsWrapperPanel.getParent().addStyleName(leftControlsIndentStyle); } } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapStyle.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapStyle.java index 4a2179a296b..b8417bd9206 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapStyle.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/RaceMapStyle.java @@ -17,5 +17,5 @@ public interface RaceMapStyle extends CssResource { public String raceMapIndicatorPanelTextLabel(); public String raceMapIndicatorPanelCanvas(); public String combinedWindPanel(); - public String trueNorthIndicator(); + public String trueNorthIndicatorPanel(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java index 6465508ad61..48cd14e3424 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/shared/racemap/TrueNorthIndicatorPanel.java @@ -35,7 +35,7 @@ public class TrueNorthIndicatorPanel extends FlowPanel { this.raceMapResources = theRaceMapResources; this.raceMapStyle = raceMapStyle; addStyleName(raceMapStyle.raceMapIndicatorPanel()); - addStyleName(raceMapStyle.trueNorthIndicator()); + addStyleName(raceMapStyle.trueNorthIndicatorPanel()); transformer = raceMapResources.getTrueNorthIndicatorIconTransformer(); canvas = transformer.getCanvas(); canvas.addStyleName(this.raceMapStyle.raceMapIndicatorPanelCanvas());