Merge branch 'master' into bug4627

This commit is contained in:
Axel Uhl committed 2020-05-15 00:23:49 +02:00
commit db3fc89f69
15 files changed
+263 -140

No files matched your search

@@ -337,10 +337,12 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
}
public static TimePoint loadTimePoint(Document object, String fieldName) {
TimePoint result = null;
final TimePoint result;
Number timePointAsNumber = (Number) object.get(fieldName);
if (timePointAsNumber != null) {
result = new MillisecondsTimePoint(timePointAsNumber.longValue());
} else {
result = null;
}
return result;
}
@@ -351,12 +353,15 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
public static TimeRange loadTimeRange(Document object, FieldNames field) {
Document timeRangeObj = (Document) object.get(field.name());
final TimeRange result;
if (timeRangeObj == null) {
return null;
result = null;
} else {
TimePoint from = loadTimePoint(timeRangeObj, FieldNames.FROM_MILLIS);
TimePoint to = loadTimePoint(timeRangeObj, FieldNames.TO_MILLIS);
result = new TimeRangeImpl(from, to);
}
TimePoint from = loadTimePoint(timeRangeObj, FieldNames.FROM_MILLIS);
TimePoint to = loadTimePoint(timeRangeObj, FieldNames.TO_MILLIS);
return new TimeRangeImpl(from, to);
return result;
}
/**
@@ -1165,7 +1170,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
UUID id = (UUID) eventDBObject.get(FieldNames.EVENT_ID.name());
TimePoint startDate = loadTimePoint(eventDBObject, FieldNames.EVENT_START_DATE);
TimePoint endDate = loadTimePoint(eventDBObject, FieldNames.EVENT_END_DATE);
if (endDate.before(startDate)) {
if (endDate != null && startDate != null && endDate.before(startDate)) {
logger.warning("End date "+endDate+" of event "+name+" with ID "+id+" is before its start date "+
startDate+"; adjusting such that end date equals start date.");
endDate = startDate;
@@ -0,0 +1,3 @@
{"rms":[
{"NatAuth":"UKR","BIN":"UKR0267_Karina","CertNo":"0267_4","RefNo":"03600000HUH","SailNo":"UKR 267","YachtName":"Karina","Class":"Teliga 89","Builder":"im. L Teligi","Designer":"L. Teliga","Address3":"YC Obolon","C_Type":"CLUB","Family":"ORC","Division":"C","IssueDate":"2020-05-07T11:48:07.143Z","Age_Year":1975,"CrewWT":460,"LOA":8.95,"IMSL":7.354,"Draft":1.562,"MB":3.092,"Dspl_Measurement":3790,"Stability_Index":107.3,"Dynamic_Allowance":0.328,"GPH":725.4,"TMF_Inshore":0.8568,"ILCWA":787.8,"TMF_Offshore":0.849,"OSN":706.7,"CDL":6.694,"TN_Offshore_Low":0.8193,"TN_Offshore_Medium":1.0478,"TN_Offshore_High":1.1557,"TN_Inshore_Low":0.6372,"TN_Inshore_Medium":0.8543,"TN_Inshore_High":0.9652,"TND_Offshore_Low":823.9,"TND_Offshore_Medium":644.2,"TND_Offshore_High":584.1,"TND_Inshore_Low":1059.3,"TND_Inshore_Medium":790.1,"TND_Inshore_High":699.3,"OSN_Jibs":735.4,"TMF_Jibs":0.8158,"Pred_Up_TOD":708.3,"Pred_Down_TOD":650.3,"Pred_Up_TOT":0.8471,"Pred_Down_TOT":0.9227,"Dspl_Sailing":4377,"WSS":18.58,"Area_Main":17.88,"Area_Jib":33.38,"Area_Sym":71.46,"Area_ASym":56.06,"GPH_Jibs":757.5,"GPH_Jibs_TOT":0.7921,"Allowances":{"WindSpeeds":[6,8,10,12,14,16,20],"WindAngles":[52,60,75,90,110,120,135,150],"Beat":[1215.6,1032.2,921.7,859.4,840,835.1,853.2],"Run":[1102.9,886.5,746.4,655.8,596.9,564.7,518.9],"BeatAngle":[42.8,42,42.8,41.4,40.9,40.7,41.8],"GybeAngle":[148,152,150.5,162,180,180,180],"WL":[1159.2,959.4,834.1,757.6,718.4,699.9,686],"CR":[989.5,803.2,704.2,647.7,614.3,594,572.2],"OC":[1153.6,900.2,752.5,666.7,624.4,593.1,543.1],"NS":[1044.7,843.1,734.6,671.9,634.2,611.1,586],"OL":[1116.2,923.6,815.1,753.8,722.7,706.6,697.2],"R52":[796.9,680.2,617.6,591.6,581.2,577.6,579],"R60":[753.3,644.5,598.1,576.8,565.2,560.4,559.4],"R75":[723,622.2,584.2,564,549,537.5,528],"R90":[729.8,623.6,577.4,552.9,539.1,527.4,503.9],"R110":[729.1,608.7,564.9,538.7,516.9,499.7,477.8],"R120":[750.3,617.8,568.6,540.6,515,493.4,466],"R135":[817.4,671.3,588.5,556.1,530.2,505,465.1],"R150":[955.2,767.9,647,584.3,555.6,531.9,487.7]}}
]}
@@ -13,6 +13,11 @@ public class TestORCCertificateImporterJSON extends AbstractORCCertificateImport
testSimpleLocalFileRead("GER2019.json", "GER20041179");
}
@Test
public void testReadingJSONWithSpecificBins() throws IOException, ParseException {
testSimpleLocalFileRead("03600000HUH.json", "03600000HUH");
}
@FailIfNoValidOrcCertificates
@Test
public void testSimpleOnlineJSONFileRead() throws IOException, ParseException, InterruptedException {
@@ -63,6 +63,7 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
private static final String CIRCULAR_RANDOM = "CR";
private static final String NON_SPINNAKER = "NS";
private static final String WIND_SPEEDS = "WindSpeeds";
private static final String WIND_ANGLES = "WindAngles";
/**
* Pattern to recognize a true wind angle in the allowances section. Group 1 contains
@@ -189,27 +190,28 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec
}
// Now read the various allowances, assuming we find values for the TWS "bins" identified above
for (final Object aKey : allowances.keySet()) {
final JSONArray array = (JSONArray) allowances.get(aKey);
final JSONArray twaArray = (JSONArray) allowances.get(aKey);
if (((String) aKey).equals(BEAT_ANGLE)) {
for (int i = 0; i < array.size(); i++) {
for (int i = 0; i < twaArray.size(); i++) {
beatAngles.put(new KnotSpeedImpl(trueWindSpeedArray[i]),
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
new DegreeBearingImpl(((Number) twaArray.get(i)).doubleValue()));
}
continue;
}
if (((String) aKey).equals(GYBE_ANGLE)) {
for (int i = 0; i < array.size(); i++) {
for (int i = 0; i < twaArray.size(); i++) {
gybeAngles.put(new KnotSpeedImpl(trueWindSpeedArray[i]),
new DegreeBearingImpl(((Number) array.get(i)).doubleValue()));
new DegreeBearingImpl(((Number) twaArray.get(i)).doubleValue()));
}
continue;
}
Map<Speed, Duration> twsMap = new HashMap<>();
// ignore true wind angles key
if (!twaPattern.matcher((String) aKey).lookingAt()) {
for (int i = 0; i < array.size(); i++) {
if (!aKey.equals(WIND_SPEEDS) && !aKey.equals(WIND_ANGLES) &&
!twaPattern.matcher((String) aKey).lookingAt()) {
for (int i = 0; i < twaArray.size(); i++) {
twsMap.put(new KnotSpeedImpl(trueWindSpeedArray[i]),
new SecondsDurationImpl(((Number) array.get(i)).doubleValue()));
new SecondsDurationImpl(((Number) twaArray.get(i)).doubleValue()));
}
}
switch ((String) aKey) {
@@ -7,7 +7,6 @@ public class TrackedEventPreferences extends AbstractGenericSerializableSettings
private static final long serialVersionUID = -290209497308646446L;
// TODO: setting preference title
public static final String PREF_NAME = SailingPreferences.TRACKED_EVENTS_PREFERENCES;
private transient SettingsList<TrackedEventPreference> trackedEvents;
@@ -91,7 +91,7 @@ public abstract class AbstractGenericSerializableSettings extends AbstractSettin
public AbstractGenericSerializableSettings(String name, AbstractGenericSerializableSettings settings) {
super(name, settings);
value = (SettingsValue) settings.getValue(name);
if(value == null) {
if (value == null) {
value = new SettingsValue();
settings.setValue(name, value);
}
@@ -103,18 +103,18 @@ public abstract class AbstractGenericSerializableSettings extends AbstractSettin
*/
protected void adoptValue(SettingsValue value) {
this.value = value;
if(childSettings != null) {
for(Map.Entry<String, Setting> entry : childSettings.entrySet()) {
if (childSettings != null) {
for (Map.Entry<String, Setting> entry : childSettings.entrySet()) {
Setting childSetting = entry.getValue();
if(childSetting instanceof AbstractGenericSerializableSettings) {
if (childSetting instanceof AbstractGenericSerializableSettings) {
Value childValue = value.getValue(entry.getKey());
if(childValue != null) {
if (childValue != null) {
((AbstractGenericSerializableSettings) childSetting).adoptValue((SettingsValue) childValue);
}
}
if(childSetting instanceof SettingsList<?>) {
if (childSetting instanceof SettingsList<?>) {
Value childValue = value.getValue(entry.getKey());
if(childValue != null) {
if (childValue != null) {
((SettingsList<?>) childSetting).adoptValue();
}
}
@@ -5,6 +5,10 @@ public interface CollectionSetting<T> extends Setting {
void setValues(Iterable<T> values);
/**
* Obtains a non-live copy of the values in this collection setting. Changes to this setting
* will not reflect in the iterable returned.
*/
Iterable<T> getValues();
void addValue(T value);
@@ -13,6 +13,13 @@ import com.sap.sse.common.settings.value.ValueListValue;
public class SettingsList<T extends AbstractGenericSerializableSettings> extends AbstractSetting implements SettingsListSetting<T> {
private SettingsFactory<T> settingsFactory;
/**
* All access to this list must be {@code synchronized}. Unfortunately, GWT does not offer
* {@link Collections#synchronizedList(List)} in its JRE emulation, so we have to
* make sure to consistently wrap all methods that access this list with a {@code synchronized}
* block that obtains this list's monitor.
*/
private final List<T> values = new ArrayList<>();
public SettingsList(String name, AbstractGenericSerializableSettings settings, SettingsFactory<T> settingsFactory) {
@@ -22,13 +29,15 @@ public class SettingsList<T extends AbstractGenericSerializableSettings> extends
}
protected void adoptValue() {
values.clear();
ValueListValue value = getValue();
if(value != null) {
for(Value val : value.getValueObjects()) {
T childSettingsInstance = settingsFactory.newInstance();
childSettingsInstance.adoptValue((SettingsValue)val);
values.add(childSettingsInstance);
synchronized (values) {
values.clear();
ValueListValue value = getValue();
if(value != null) {
for(Value val : value.getValueObjects()) {
T childSettingsInstance = settingsFactory.newInstance();
childSettingsInstance.adoptValue((SettingsValue)val);
values.add(childSettingsInstance);
}
}
}
}
@@ -58,65 +67,80 @@ public class SettingsList<T extends AbstractGenericSerializableSettings> extends
@Override
public boolean isDefaultValue() {
// explicit default values are possible to implement
// currently, empty is always default
return values.isEmpty();
synchronized (values) {
// 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);
synchronized (values) {
this.values.clear();
settings.setValue(settingName, null);
}
}
@Override
public Iterable<T> getValues() {
return Collections.unmodifiableCollection(values);
synchronized (values) {
final List<T> result = new ArrayList<>(values);
return result;
}
}
@Override
public void setValues(Iterable<T> values) {
this.values.clear();
ValueCollectionValue<List<Value>> valueObject = ensureValue();
valueObject.clear();
if (values != null) {
for (T value : values) {
this.values.add(value);
valueObject.addValue(value.getInnerValueObject());
synchronized (values) {
this.values.clear();
ValueCollectionValue<List<Value>> valueObject = ensureValue();
valueObject.clear();
if (values != null) {
for (T value : values) {
this.values.add(value);
valueObject.addValue(value.getInnerValueObject());
}
}
}
}
@Override
public void addValue(T value) {
ValueCollectionValue<List<Value>> valueObject = ensureValue();
this.values.add(value);
valueObject.addValue(value.getInnerValueObject());
synchronized (values) {
ValueCollectionValue<List<Value>> valueObject = ensureValue();
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;
synchronized (values) {
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)
synchronized (values) {
if (this == obj)
return true;
if (obj == null)
return false;
} else if (!values.equals(other.values))
return false;
return true;
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;
}
}
}
@@ -3,6 +3,11 @@ package com.sap.sse.common.settings.generic;
public interface ValueCollectionSetting<T> extends HasValueSetting<T>, CollectionSetting<T> {
void setDefaultValues(Iterable<T> defaultValues);
/**
* Obtains a non-live copy of the default values. Modification to this object's default values hence will
* not reflect into the iterable returned.
*/
Iterable<T> getDefaultValues();
boolean isValuesEmpty();
void setDiff(Iterable<T> removedValues, Iterable<T> addedValues);
@@ -21,7 +21,7 @@ public abstract class AbstractValueCollectionSetting<T, C extends Collection<Val
}
private D getDefaultValuesCollectionInternal() {
if(defaultValues == null) {
if (defaultValues == null) {
defaultValues = createDefaultValuesCollection();
}
return defaultValues;
@@ -36,7 +36,7 @@ public abstract class AbstractValueCollectionSetting<T, C extends Collection<Val
private ValueCollectionValue<C> ensureValue() {
ValueCollectionValue<C> result = getValue();
if(result == null) {
if (result == null) {
result = createValue();
settings.setValue(settingName, result);
}
@@ -48,10 +48,15 @@ public abstract class AbstractValueCollectionSetting<T, C extends Collection<Val
@Override
public Iterable<T> getValues() {
ValueCollectionValue<C> value = getValue();
if(emptyIsDefault && (value == null || value.isEmpty())) {
return Collections.unmodifiableCollection(getDefaultValuesCollectionInternal());
if (emptyIsDefault && (value == null || value.isEmpty())) {
final D defaultVal = getDefaultValuesCollectionInternal();
synchronized (defaultVal) {
final D result = createDefaultValuesCollection();
result.addAll(defaultVal);
return result;
}
}
if(value == null) {
if (value == null) {
return Collections.emptyList();
}
return value.getValues(getValueConverter());
@@ -78,33 +83,45 @@ public abstract class AbstractValueCollectionSetting<T, C extends Collection<Val
}
@Override
public void resetToDefault() {
setValues(getDefaultValuesCollectionInternal());
final D defaultVal = getDefaultValuesCollectionInternal();
synchronized (defaultVal) {
setValues(defaultVal);
}
}
@Override
public final boolean isDefaultValue() {
final ValueCollectionValue<C> value = getValue();
final D defaultVal = getDefaultValuesCollectionInternal();
return ((emptyIsDefault || defaultVal.isEmpty()) && (value == null || value.isEmpty()))
|| (value != null && value.size() == defaultVal.size() && defaultVal.containsAll(value.getValues(getValueConverter())));
synchronized (defaultVal) {
return ((emptyIsDefault || defaultVal.isEmpty()) && (value == null || value.isEmpty()))
|| (value != null && value.size() == defaultVal.size() && defaultVal.containsAll(value.getValues(getValueConverter())));
}
}
@Override
public final void setDefaultValues(Iterable<T> defaultValues) {
final boolean wasDefault = isDefaultValue();
final D defaultVal = getDefaultValuesCollectionInternal();
defaultVal.clear();
if(defaultValues != null) {
Util.addAll(defaultValues, defaultVal);
}
if(wasDefault) {
resetToDefault();
synchronized (defaultVal) {
defaultVal.clear();
if (defaultValues != null) {
Util.addAll(defaultValues, defaultVal);
}
if (wasDefault) {
resetToDefault();
}
}
}
@Override
public Iterable<T> getDefaultValues() {
return Collections.unmodifiableCollection(getDefaultValuesCollectionInternal());
final D result = createDefaultValuesCollection();
final D localDefaultValues = getDefaultValuesCollectionInternal();
synchronized (localDefaultValues) {
result.addAll(localDefaultValues);
return result;
}
}
@Override
@@ -135,7 +152,7 @@ public abstract class AbstractValueCollectionSetting<T, C extends Collection<Val
@Override
public String toString() {
ValueCollectionValue<C> value = getValue();
if(value == null) {
if (value == null) {
return "[]";
}
return value.toString();
@@ -3,21 +3,24 @@ package com.sap.sse.common.settings.value;
import java.util.HashMap;
public class SettingsListValue {
private HashMap<String, Value> values = new HashMap<>();
public SettingsListValue() {
}
public Value getValue(String name) {
return values.get(name);
synchronized (values) {
return values.get(name);
}
}
public void setValue(String name, Value value) {
if(value == null) {
values.remove(name);
} else {
values.put(name, value);
synchronized (values) {
if (value == null) {
values.remove(name);
} else {
values.put(name, value);
}
}
}
}
@@ -1,53 +1,71 @@
package com.sap.sse.common.settings.value;
import java.util.Collections;
import java.util.HashMap;
public class SettingsValue implements Value {
private static final long serialVersionUID = -3407605464729611500L;
/**
* All access to this map must be {@code synchronized}. Unfortunately, GWT does not offer
* {@link Collections#synchronizedMap(java.util.Map)} in its JRE emulation, so we have to
* make sure to consistently wrap all methods that access this map with a {@code synchronized}
* block that obtains this map's monitor.
*/
private HashMap<String, Value> values = new HashMap<>();
public SettingsValue() {
}
public Value getValue(String name) {
return values.get(name);
synchronized (values) {
return values.get(name);
}
}
public void setValue(String name, Value value) {
if(value == null) {
values.remove(name);
} else {
values.put(name, value);
synchronized (values) {
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;
synchronized (values) {
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)
synchronized (values) {
if (this == obj)
return true;
if (obj == null)
return false;
} else if (!values.equals(other.values))
return false;
return true;
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();
synchronized (values) {
return values.toString();
}
}
}
@@ -3,6 +3,10 @@ package com.sap.sse.common.settings.value;
import com.sap.sse.common.settings.generic.ValueConverter;
public interface ValueCollection extends Value {
/**
* Obtains a non-live copy of the values in this collection. Modifications to this value collection
* will not reflect in the result of this method, and vice versa.
*/
<T> Iterable<T> getValues(ValueConverter<T> converter);
<T> void setValues(Iterable<T> values, ValueConverter<T> converter);
@@ -7,6 +7,13 @@ import com.sap.sse.common.settings.generic.ValueConverter;
public abstract class ValueCollectionValue<C extends Collection<Value>> implements ValueCollection {
private static final long serialVersionUID = -5820765644801217519L;
/**
* All access to this collection must be {@code synchronized}. Unfortunately, GWT does not offer
* {@link Collections#synchronizedCollection(Collection)} in its JRE emulation, so we have to
* make sure to consistently wrap all methods that access this collection with a {@code synchronized}
* block that obtains this collection's monitor.
*/
private C values;
protected ValueCollectionValue(C values) {
@@ -17,75 +24,99 @@ public abstract class ValueCollectionValue<C extends Collection<Value>> implemen
@Override
public <T> Collection<T> getValues(ValueConverter<T> converter) {
Collection<T> result = emptyCollection();
for (Value value : values) {
result.add(converter.fromValue(value));
final Collection<T> result = emptyCollection();
synchronized (values) {
for (Value value : values) {
result.add(converter.fromValue(value));
}
return result;
}
}
public Iterable<Value> getValueObjects() {
final Collection<Value> result = emptyCollection();
synchronized (values) {
result.addAll(values);
}
return result;
}
public Iterable<Value> getValueObjects() {
return Collections.unmodifiableCollection(values);
}
@Override
public <T> void setValues(Iterable<T> values, ValueConverter<T> converter) {
clear();
if(values != null) {
for (T value : values) {
addValue(value, converter);
synchronized (this.values) {
clear();
if (values != null) {
for (T value : values) {
addValue(value, converter);
}
}
}
}
@Override
public void clear() {
this.values.clear();
synchronized (values) {
this.values.clear();
}
}
public <T> void addValue(T value, ValueConverter<T> converter) {
this.values.add(converter.toValue(value));
synchronized (values) {
addValue(converter.toValue(value));
}
}
public <T> void addValue(Value value) {
this.values.add(value);
synchronized (values) {
this.values.add(value);
}
}
public boolean isEmpty() {
return values.isEmpty();
synchronized (values) {
return values.isEmpty();
}
}
public int size() {
return values.size();
synchronized (values) {
return values.size();
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((values == null) ? 0 : values.hashCode());
return result;
synchronized (values) {
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)
synchronized (values) {
if (this == obj)
return true;
if (obj == null)
return false;
} else if (!values.equals(other.values))
return false;
return true;
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();
synchronized (values) {
return values.toString();
}
}
}
@@ -12,7 +12,10 @@ import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
/**
* Groups settings for multiple {@link Component}s. This can be of particular interest when working with
* {@link Perspective}s and the perspective's {@link PerspectiveCompositeSettings composite settings}.
* {@link Perspective}s and the perspective's {@link PerspectiveCompositeSettings composite settings}.<p>
*
* No synchronization is required here because when the constructor returns, the map used internally
* will no longer be modified.
*/
public class CompositeSettings extends AbstractSettings implements SettingsMap {
private final Map<String, Settings> settingsPerComponentId;