Merge branch 'main' into bug6113

This commit is contained in:
masha.kashirina
2026-04-18 17:42:55 +02:00
118 changed files with 3199 additions and 2198 deletions
-400
View File
@@ -1,400 +0,0 @@
# LeaderboardPanel Selection State Refactoring Analysis
## Current Architecture
### Three Selection Models in Play
1. **`leaderboardSelectionModel`** (LeaderboardPanel:239)
- Type: `MultiSelectionModel<LeaderboardRowDTO>`
- Created at line 527
- Attached to the CellTable at line 547
- Has a `selectionChangeHandler` that syncs TO CompetitorSelectionProvider (lines 530-544)
2. **`SelectionCheckboxColumn.selectionModel`** (SelectionCheckboxColumn:51)
- Type: `RefreshableMultiSelectionModel<T>`
- Created by SelectionCheckboxColumn constructor
- **Currently NOT used by the LeaderboardPanel's CellTable**
- Has display.flush() callbacks for UI updates
3. **`CompetitorSelectionProvider`**
- Application-level selection state
- Both LeaderboardPanel and SelectionCheckboxColumn listen to it
- Notifies listeners via `addedToSelection()` / `removedFromSelection()`
### Current Selection Flow Problems
#### Flow 1: User clicks checkbox in UI
```
User clicks checkbox
SelectionCheckboxColumn handles click event
leaderboardSelectionModel.setSelected() called ← Uses WRONG selection model!
selectionChangeHandler fires (lines 530-544)
competitorSelectionProvider.setSelection() called
CompetitorSelectionProvider fires addedToSelection/removedFromSelection
BOTH LeaderboardPanel AND SelectionCheckboxColumn receive callback:
- LeaderboardPanel.addedToSelection() (line 3393)
→ calls leaderboardSelectionModel.setSelected()
- SelectionCheckboxColumn.addedToSelection() (line 2160)
→ calls getSelectionModel().setSelected() ← Different model!
```
**Problem**: Two selection models exist but only one (leaderboardSelectionModel) is attached to the table. The SelectionCheckboxColumn's RefreshableMultiSelectionModel is created but orphaned.
#### Flow 2: CompetitorSelectionProvider changes externally
```
External change to CompetitorSelectionProvider
Fires addedToSelection/removedFromSelection
BOTH listeners receive callback:
- LeaderboardPanel.addedToSelection() (line 3393)
→ leaderboardSelectionModel.setSelected(row, true)
→ Could trigger selectionChangeHandler → infinite loop potential!
- SelectionCheckboxColumn.addedToSelection() (line 2160)
→ getSelectionModel().setSelected(row, true) ← Orphaned model!
```
**Problem**: LeaderboardPanel guards against recursion by temporarily removing the handler (line 2712), but this is complex. SelectionCheckboxColumn updates an unused selection model.
### Inconsistencies Found
1. **Line 527**: LeaderboardPanel creates its own `MultiSelectionModel`
2. **Line 547**: Attaches that model to the table, ignoring SelectionCheckboxColumn's model
3. **Line 2163/2174**: SelectionCheckboxColumn callbacks update its own orphaned model
4. **Line 3396/3404**: LeaderboardPanel callbacks update the table's model
5. **SelectionCheckboxColumn.getValue()** (line 2140): Checks CompetitorSelectionProvider directly, NOT its own selection model!
## Proposed Refactoring
### Goal
Use **ONLY** the `RefreshableMultiSelectionModel` from SelectionCheckboxColumn as the single source of truth, synchronized bidirectionally with CompetitorSelectionProvider.
### Step-by-Step Plan
#### Step 1: Use SelectionCheckboxColumn's Model as Table's Model
**File**: `LeaderboardPanel.java`
**Current code** (lines 525-547):
```java
selectionCheckboxColumn = new LeaderboardSelectionCheckboxColumn(competitorSelectionProvider);
leaderboardTable.setWidth("100%");
leaderboardSelectionModel = new MultiSelectionModel<LeaderboardRowDTO>(); // ← REMOVE THIS
selectionChangeHandler = new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
List<CompetitorDTO> selection = new ArrayList<>();
for (LeaderboardRowDTO row : getSelectedRows()) {
selection.add(row.competitor);
}
LeaderboardPanel.this.competitorSelectionProvider.setSelection(selection,
/* listenersNotToNotify */LeaderboardPanel.this);
if (blurInOnSelectionChanged > 0) {
blurInOnSelectionChanged--;
blurFocusedElementAfterSelectionChange();
}
}
};
leaderboardAsTableSelectionModelRegistration = leaderboardSelectionModel
.addSelectionChangeHandler(selectionChangeHandler);
leaderboardTable.setSelectionModel(leaderboardSelectionModel, selectionCheckboxColumn.getSelectionManager());
```
**Refactored**:
```java
selectionCheckboxColumn = new LeaderboardSelectionCheckboxColumn(competitorSelectionProvider);
leaderboardTable.setWidth("100%");
// Use the SelectionCheckboxColumn's model as THE selection model
leaderboardSelectionModel = selectionCheckboxColumn.getSelectionModel();
selectionChangeHandler = new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
if (updatingSelectionFromProvider) {
// Guard: don't sync back to provider if we're currently syncing FROM provider
return;
}
List<CompetitorDTO> selection = new ArrayList<>();
for (LeaderboardRowDTO row : getSelectedRows()) {
selection.add(row.competitor);
}
LeaderboardPanel.this.competitorSelectionProvider.setSelection(selection,
/* listenersNotToNotify */LeaderboardPanel.this);
if (blurInOnSelectionChanged > 0) {
blurInOnSelectionChanged--;
blurFocusedElementAfterSelectionChange();
}
}
};
leaderboardAsTableSelectionModelRegistration = leaderboardSelectionModel
.addSelectionChangeHandler(selectionChangeHandler);
leaderboardTable.setSelectionModel(leaderboardSelectionModel, selectionCheckboxColumn.getSelectionManager());
```
**Changes**:
- Line 527: Change from `new MultiSelectionModel<>()` to `selectionCheckboxColumn.getSelectionModel()`
- Add guard flag `updatingSelectionFromProvider` to prevent recursion
- Declare field: `private boolean updatingSelectionFromProvider = false;`
#### Step 2: Update Field Declaration
**Current** (line 239):
```java
private final MultiSelectionModel<LeaderboardRowDTO> leaderboardSelectionModel;
```
**Refactored**:
```java
private final RefreshableMultiSelectionModel<LeaderboardRowDTO> leaderboardSelectionModel;
```
Add import:
```java
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
```
#### Step 3: Fix LeaderboardPanel's Selection Callbacks
**Current** (lines 3393-3406):
```java
@Override
public void addedToSelection(CompetitorDTO competitor) {
LeaderboardRowDTO row = getRow(competitor.getIdAsString());
if (row != null) {
leaderboardSelectionModel.setSelected(row, true);
}
}
@Override
public void removedFromSelection(CompetitorDTO competitor) {
LeaderboardRowDTO row = getRow(competitor.getIdAsString());
if (row != null) {
leaderboardSelectionModel.setSelected(row, false);
}
}
```
**Refactored**:
```java
@Override
public void addedToSelection(CompetitorDTO competitor) {
LeaderboardRowDTO row = getRow(competitor.getIdAsString());
if (row != null) {
updatingSelectionFromProvider = true;
try {
leaderboardSelectionModel.setSelected(row, true);
} finally {
updatingSelectionFromProvider = false;
}
}
}
@Override
public void removedFromSelection(CompetitorDTO competitor) {
LeaderboardRowDTO row = getRow(competitor.getIdAsString());
if (row != null) {
updatingSelectionFromProvider = true;
try {
leaderboardSelectionModel.setSelected(row, false);
} finally {
updatingSelectionFromProvider = false;
}
}
}
```
**Changes**:
- Set guard flag before updating selection model
- Ensures selectionChangeHandler won't sync back to CompetitorSelectionProvider
#### Step 4: Remove SelectionCheckboxColumn's Redundant Listener
**File**: `LeaderboardPanel.java`, inner class `LeaderboardSelectionCheckboxColumn`
**Current** (lines 2120-2136):
```java
protected LeaderboardSelectionCheckboxColumn(final CompetitorSelectionProvider competitorSelectionProvider) {
super(style.getTableresources().cellTableStyle().cellTableCheckboxSelected(),
style.getTableresources().cellTableStyle().cellTableCheckboxDeselected(),
style.getTableresources().cellTableStyle().cellTableCheckboxColumnCell(),
new EntityIdentityComparator<LeaderboardRowDTO>() {
@Override
public boolean representSameEntity(LeaderboardRowDTO dto1, LeaderboardRowDTO dto2) {
return dto1.competitor.getIdAsString().equals(dto2.competitor.getIdAsString());
}
@Override
public int hashCode(LeaderboardRowDTO t) {
return t.competitor.getIdAsString().hashCode();
}
}, getData(), leaderboardTable);
competitorSelectionProvider.addCompetitorSelectionChangeListener(this); // ← REMOVE THIS
}
```
**Refactored**:
```java
protected LeaderboardSelectionCheckboxColumn(final CompetitorSelectionProvider competitorSelectionProvider) {
super(style.getTableresources().cellTableStyle().cellTableCheckboxSelected(),
style.getTableresources().cellTableStyle().cellTableCheckboxDeselected(),
style.getTableresources().cellTableStyle().cellTableCheckboxColumnCell(),
new EntityIdentityComparator<LeaderboardRowDTO>() {
@Override
public boolean representSameEntity(LeaderboardRowDTO dto1, LeaderboardRowDTO dto2) {
return dto1.competitor.getIdAsString().equals(dto2.competitor.getIdAsString());
}
@Override
public int hashCode(LeaderboardRowDTO t) {
return t.competitor.getIdAsString().hashCode();
}
}, getData(), leaderboardTable);
// REMOVED: competitorSelectionProvider.addCompetitorSelectionChangeListener(this);
// LeaderboardPanel is now the ONLY listener that syncs selection state
}
```
**Current** (lines 2160-2176, now unnecessary):
```java
@Override
public void addedToSelection(CompetitorDTO competitor) {
final LeaderboardRowDTO row = getRow(competitor.getIdAsString());
if (row != null) {
getSelectionModel().setSelected(row, true);
}
}
@Override
public void removedFromSelection(CompetitorDTO competitor) {
final LeaderboardRowDTO row = getRow(competitor.getIdAsString());
if (row != null) {
getSelectionModel().setSelected(row, false);
}
}
```
**Refactored**: Remove these methods entirely. The SelectionCheckboxColumn no longer needs to implement `CompetitorSelectionChangeListener`.
**Also remove** (line 2119):
```java
// FROM:
private class LeaderboardSelectionCheckboxColumn
extends com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn<LeaderboardRowDTO>
implements CompetitorSelectionChangeListener {
// TO:
private class LeaderboardSelectionCheckboxColumn
extends com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn<LeaderboardRowDTO> {
```
Remove the empty listener method implementations at lines 2144-2154.
#### Step 5: Simplify updateSelection()
**Current** (lines 2707-2721):
```java
private void updateSelection(LeaderboardRowDTO row) {
final boolean shallBeSelected = competitorSelectionProvider.isSelected(row.competitor);
if (leaderboardAsTableSelectionModelRegistration != null) {
// suspend selection events while actively adjusting the leaderboardSelectionModel to match the
// competitorSelectionProvider
leaderboardAsTableSelectionModelRegistration.removeHandler();
leaderboardAsTableSelectionModelRegistration = null;
}
if (leaderboardSelectionModel.isSelected(row) != shallBeSelected) {
leaderboardSelectionModel.setSelected(row, shallBeSelected);
}
// register the selection change handler again
leaderboardAsTableSelectionModelRegistration = leaderboardTable.getSelectionModel()
.addSelectionChangeHandler(selectionChangeHandler);
}
```
**Refactored**:
```java
private void updateSelection(LeaderboardRowDTO row) {
final boolean shallBeSelected = competitorSelectionProvider.isSelected(row.competitor);
updatingSelectionFromProvider = true;
try {
if (leaderboardSelectionModel.isSelected(row) != shallBeSelected) {
leaderboardSelectionModel.setSelected(row, shallBeSelected);
}
} finally {
updatingSelectionFromProvider = false;
}
}
```
**Changes**:
- Removed handler removal/re-registration complexity
- Use guard flag instead
- Much simpler and clearer
#### Step 6: Fix getValue() in LeaderboardSelectionCheckboxColumn
**Current** (lines 2139-2141):
```java
@Override
public Boolean getValue(LeaderboardRowDTO row) {
return competitorSelectionProvider.isSelected(row.competitor);
}
```
**Refactored**:
```java
@Override
public Boolean getValue(LeaderboardRowDTO row) {
// Use the selection model as the source of truth, not CompetitorSelectionProvider
return getSelectionModel().isSelected(row);
}
```
**Rationale**: The selection model should be the single source of truth for rendering. It stays synchronized with CompetitorSelectionProvider via the LeaderboardPanel's listeners.
### Summary of Changes
1. **LeaderboardPanel.java line 527**: Change to use `selectionCheckboxColumn.getSelectionModel()`
2. **LeaderboardPanel.java line 239**: Change type to `RefreshableMultiSelectionModel`
3. **LeaderboardPanel.java**: Add field `private boolean updatingSelectionFromProvider = false;`
4. **LeaderboardPanel.java lines 530-544**: Add guard check in selectionChangeHandler
5. **LeaderboardPanel.java lines 3393-3406**: Add guard flag around setSelected calls
6. **LeaderboardPanel.java lines 2707-2721**: Simplify updateSelection() using guard flag
7. **LeaderboardPanel.LeaderboardSelectionCheckboxColumn line 2135**: Remove listener registration
8. **LeaderboardPanel.LeaderboardSelectionCheckboxColumn line 2119**: Remove `implements CompetitorSelectionChangeListener`
9. **LeaderboardPanel.LeaderboardSelectionCheckboxColumn lines 2144-2176**: Remove listener methods
10. **LeaderboardPanel.LeaderboardSelectionCheckboxColumn line 2140**: Use selection model instead of provider
## Benefits
1. **Single Selection Model**: RefreshableMultiSelectionModel is the only selection model
2. **No Orphaned State**: Eliminates the unused selection model in SelectionCheckboxColumn
3. **Simpler Synchronization**: Single bidirectional sync point between model and provider
4. **No Handler Removal**: Guard flag is simpler than removing/re-adding handlers
5. **Clearer Ownership**: LeaderboardPanel owns synchronization, SelectionCheckboxColumn just renders
## Testing Strategy
1. Test user clicking checkboxes - selection should sync to CompetitorSelectionProvider
2. Test external CompetitorSelectionProvider changes - should update checkboxes
3. Test rapid clicking - no infinite loops or race conditions
4. Test with filtering - filtered rows should maintain correct selection state
5. Test leaderboard updates - selection should persist across data refreshes
## Potential Risks
1. **GWT Selection Model Flush Timing**: GWT selection models flush changes at end of event loop. The guard flag approach should handle this correctly since the flag is set synchronously.
2. **Multiple LeaderboardPanels**: If multiple LeaderboardPanels share the same CompetitorSelectionProvider, each will receive callbacks. This should work fine as each has its own guard flag.
3. **RefreshableMultiSelectionModel.refreshSelectionModel()**: This method has its own `dontCheckSelectionState` guard (RefreshableMultiSelectionModel.java line 131). Verify this doesn't interfere with our guard flag.
## Future Improvements
Consider enhancing RefreshableMultiSelectionModel to accept a callback for selection changes, eliminating the need for the external SelectionChangeHandler and making the synchronization more encapsulated within the model itself.
@@ -153,11 +153,11 @@ install_environment ()
load_from_release_file ()
{
if [[ ${INSTALL_FROM_RELEASE} == "" ]]; then
GITHUB_RELEASE=$( curl -L "https://api.github.com/repos/SAP/sailing-analytics/releases?per_page=100" 2>/dev/null | jq -r 'sort_by(.created_at) | reverse | map(select(.name | startswith("main-")))[0].assets[] | select(.content_type=="application/x-tar")' )
GITHUB_RELEASE=$( curl -L "https://api.github.com/repos/SAP/sailing-analytics/releases?per_page=100" 2>/dev/null | jq -r 'map(select(.name | startswith("main-")) | .assets[] | select(.content_type=="application/x-tar")) | sort_by(.created_at) | reverse | first' )
INSTALL_FROM_RELEASE=$( echo "${GITHUB_RELEASE}" | jq -r '.name' | sed -e 's/\.tar\.gz$//' )
echo "You didn't provide a release. Defaulting to latest main branch build ${INSTALL_FROM_RELEASE}"
else
GITHUB_RELEASE=$( curl -L "https://api.github.com/repos/SAP/sailing-analytics/releases?per_page=100" 2>/dev/null | jq -r 'sort_by(.created_at) | reverse | map(select(.name=="'${INSTALL_FROM_RELEASE}'"))[0].assets[] | select(.content_type=="application/x-tar")' )
GITHUB_RELEASE=$( curl -L "https://api.github.com/repos/SAP/sailing-analytics/releases?per_page=100" 2>/dev/null | jq -r 'map(select(.name=="'${INSTALL_FROM_RELEASE}'") | .assets[] | select(.content_type=="application/x-tar")) | sort_by(.created_at) | reverse | first' )
fi
if which mail; then
if [ -n "${BUILD_COMPLETE_NOTIFY}" ]; then
+1 -1
View File
@@ -266,7 +266,7 @@
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"license": "MIT",
@@ -2107,7 +2107,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
final Document fingerprintDoc = Document.parse(fingerprintjson.toString());
result.put(FieldNames.MANEUVER_FINGERPRINT.name(), fingerprintDoc);
storeRaceIdentifier(result, raceIdentifier);
final List<Document> maneuverDoc = storeManeuvers( maneuvers , raceIdentifier, course);
final List<Document> maneuverDoc = storeManeuvers(maneuvers , raceIdentifier, course);
result.put(FieldNames.MANEUVERS.name(), maneuverDoc);
maneuverCollection.replaceOne(query, result, new ReplaceOptions().upsert(true));
}
@@ -39,10 +39,10 @@ public class GPSFixStoreListenerTest extends AbstractGPSFixStoreTest {
Thread thread = new Thread() {
public void run() {
try {
barrier.await(100, TimeUnit.MILLISECONDS);
barrier.await(1000, TimeUnit.MILLISECONDS);
// During iteration in the main thread this causes a modification that makes the iterator throw a
// ConcurrentModificationException on next()
store.addListener((DeviceIdentifier device, GPSFixMoving fix, boolean returnManeuverChanges, boolean returnLiveDelay) -> {
store.addListener((DeviceIdentifier device, Iterable<GPSFixMoving> fixes, boolean returnManeuverChanges, boolean returnLiveDelay) -> {
return null;
}, device);
barrier.await(100, TimeUnit.MILLISECONDS);
@@ -71,9 +71,9 @@ public class GPSFixStoreListenerTest extends AbstractGPSFixStoreTest {
}
@Override
public Iterable<Triple<RegattaAndRaceIdentifier, Boolean, Duration>> fixReceived(DeviceIdentifier device, GPSFixMoving fix, boolean returnManeuverChanges, boolean returnLiveDelay) {
public Iterable<Triple<RegattaAndRaceIdentifier, Boolean, Duration>> fixesReceived(DeviceIdentifier device, Iterable<GPSFixMoving> fixes, boolean returnManeuverChanges, boolean returnLiveDelay) {
try {
barrier.await(100, TimeUnit.MILLISECONDS);
barrier.await(1000, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
throw new TimoutRuntimeException(e);
} catch (Exception e) {
@@ -139,7 +139,6 @@ public class SensorFixStoreTest {
for (int i = 0; i < fixes; i++) {
addBravoFix(device, FIX_TIMESTAMP + 1, FIX_RIDE_HEIGHT);
}
List<Double> progressData = new ArrayList<>();
store.loadFixes((fix) -> {
}, device, new MillisecondsTimePoint(FIX_TIMESTAMP - 1), new MillisecondsTimePoint(FIX_TIMESTAMP + fixes + 1),
@@ -206,161 +206,163 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
private final FixReceivedListener<Timed> listener = new FixReceivedListener<Timed>() {
@Override
public Iterable<Triple<RegattaAndRaceIdentifier, Boolean, Duration>> fixReceived(DeviceIdentifier device,
Timed fix, boolean returnManeuverChanges, boolean returnLiveDelay) {
public Iterable<Triple<RegattaAndRaceIdentifier, Boolean, Duration>> fixesReceived(DeviceIdentifier device,
Iterable<Timed> fixes, boolean returnManeuverChanges, boolean returnLiveDelay) {
final Set<RegattaAndRaceIdentifier> maneuverChanged = new HashSet<>();
final Map<RegattaAndRaceIdentifier, Duration> delayToLive = new HashMap<>();
if (!preemptiveStopRequested.get() && trackedRace.getStartOfTracking() != null) {
final TimePoint timePoint = fix.getTimePoint();
deviceMappings.forEachMappingOfDeviceIncludingTimePoint(device, fix.getTimePoint(),
new Consumer<DeviceMappingWithRegattaLogEvent<WithID>>() {
@Override
public void accept(DeviceMappingWithRegattaLogEvent<WithID> mapping) {
mapping.getRegattaLogEvent().accept(new MappingEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
recordSensorFixForCompetitor(event.getMappedTo(), event);
}
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor competitor = trackedRace.getCompetitorOfBoat(boat);
if (competitor != null) {
recordSensorFixForCompetitor(competitor, event);
} else {
logger.log(Level.FINE, ()->"Could not record fix for boat because no competitor could be determined. Boat: " + boat);
for (final Timed fix : fixes) {
final TimePoint timePoint = fix.getTimePoint();
deviceMappings.forEachMappingOfDeviceIncludingTimePoint(device, fix.getTimePoint(),
new Consumer<DeviceMappingWithRegattaLogEvent<WithID>>() {
@Override
public void accept(DeviceMappingWithRegattaLogEvent<WithID> mapping) {
mapping.getRegattaLogEvent().accept(new MappingEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
recordSensorFixForCompetitor(event.getMappedTo(), event);
}
}
private void recordSensorFixForCompetitor(Competitor competitor, RegattaLogDeviceMappingEvent<?> event) {
if (!preemptiveStopRequested.get()) {
@SuppressWarnings("unchecked")
SensorFixMapper<SensorFix, DynamicSensorFixTrack<Competitor, SensorFix>, Competitor> mapper = sensorFixMapperFactory
.createCompetitorMapper((Class<? extends RegattaLogDeviceMappingEvent<?>>) event.getClass());
DynamicSensorFixTrack<Competitor, SensorFix> track = mapper.getTrack(trackedRace, competitor);
if (track != null && trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
mapper.addFix(track, (DoubleVectorFix) fix);
@Override
public void visit(RegattaLogDeviceBoatSensorDataMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor competitor = trackedRace.getCompetitorOfBoat(boat);
if (competitor != null) {
recordSensorFixForCompetitor(competitor, event);
} else {
logger.log(Level.FINE, ()->"Could not record fix for boat because no competitor could be determined. Boat: " + boat);
}
}
private void recordSensorFixForCompetitor(Competitor competitor, RegattaLogDeviceMappingEvent<?> event) {
if (!preemptiveStopRequested.get()) {
@SuppressWarnings("unchecked")
SensorFixMapper<SensorFix, DynamicSensorFixTrack<Competitor, SensorFix>, Competitor> mapper = sensorFixMapperFactory
.createCompetitorMapper((Class<? extends RegattaLogDeviceMappingEvent<?>>) event.getClass());
DynamicSensorFixTrack<Competitor, SensorFix> track = mapper.getTrack(trackedRace, competitor);
if (track != null && trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
mapper.addFix(track, (DoubleVectorFix) fix);
if (returnLiveDelay) {
delayToLive.put(trackedRace.getRaceIdentifier(), new MillisecondsDurationImpl(trackedRace.getDelayToLiveInMillis()));
}
}
}
}
@Override
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
recordForCompetitor(event.getMappedTo());
}
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor comp = trackedRace.getCompetitorOfBoat(boat);
if (comp != null) {
recordForCompetitor(comp);
} else {
// this is not necessarily something to warn of; while a boat tracker may continuously track
logger.log(Level.FINE,
()->"Could not record fix for boat because no competitor could be determined. Boat: " + boat);
}
}
private void recordForCompetitor(Competitor comp) {
if (!preemptiveStopRequested.get()) {
if (fix instanceof GPSFixMoving) {
// try to record the fix, and only if it was really to the track,
// check for maneuvers; otherwise, the fix may not have been accepted
// by the race or the track, e.g., because the race's end-of-tracking
// comes before the fix's time point
if (trackedRace.recordFix(comp, (GPSFixMoving) fix)) { // TOOD bug6229: this checks the TrackedRace's tracking interval, but for an MDI we'd also want to intersect with Event/Regatta end date if set
if (returnManeuverChanges) {
RegattaAndRaceIdentifier maneuverChangedAnswer = detectIfManeuverChanged(comp);
if (maneuverChangedAnswer != null) {
maneuverChanged.add(maneuverChangedAnswer);
}
}
if (returnLiveDelay) {
delayToLive.put(trackedRace.getRaceIdentifier(), new MillisecondsDurationImpl(trackedRace.getDelayToLiveInMillis()));
}
}
} else {
logger.log(Level.WARNING,
String.format(
"Could not add fix for competitor (%s) in race (%s), as it"
+ " is no GPSFixMoving, meaning it is missing COG/SOG values",
comp, trackedRace.getRace().getName()));
}
}
}
@Override
public void visit(RegattaLogDeviceMarkMappingEvent event) {
if (!preemptiveStopRequested.get()) {
Mark mark = event.getMappedTo();
final DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
final GPSFix firstFixAtOrAfter;
final boolean forceFix;
if (trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
forceFix = false;
} else {
markTrack.lockForRead();
try {
if (Util.isEmpty(markTrack.getRawFixes())
|| (firstFixAtOrAfter = markTrack.getFirstFixAtOrAfter(timePoint)) != null
&& firstFixAtOrAfter.getTimePoint().equals(timePoint)) {
// either the first fix or overwriting an existing one
forceFix = true;
} else {
// checking if the given fix is "better" than an existing one
TimePoint startOfTracking = trackedRace.getStartOfTracking();
TimePoint endOfTracking = trackedRace.getEndOfTracking();
if (startOfTracking != null) {
GPSFix fixAfterStartOfTracking = markTrack
.getFirstFixAtOrAfter(startOfTracking);
if (fixAfterStartOfTracking == null
|| !trackedRace.isWithinStartAndEndOfTracking(
fixAfterStartOfTracking.getTimePoint())) {
// There is no fix in the tracking interval, so this fix could be "better"
// than ones already available in the track
// Better means closer before/after the beginning/end of the tracking
// interval
if (timePoint.before(startOfTracking)) {
// check if it is closer to the beginning of the tracking interval
GPSFix fixBeforeStartOfTracking = markTrack
.getLastFixAtOrBefore(startOfTracking);
forceFix = (fixBeforeStartOfTracking == null
|| fixBeforeStartOfTracking.getTimePoint().before(timePoint));
} else if (endOfTracking != null && timePoint.after(endOfTracking)) {
// check if it is closer to the end of the tracking interval
GPSFix fixAfterEndOfTracking = markTrack
.getFirstFixAtOrAfter(endOfTracking);
forceFix = (fixAfterEndOfTracking == null
|| fixAfterEndOfTracking.getTimePoint().after(timePoint));
} else {
forceFix = false;
}
} else {
// there is already a fix in the tracking interval
forceFix = false;
}
} else {
forceFix = false;
}
}
} finally {
markTrack.unlockAfterRead();
}
}
trackedRace.recordFix(mark, (GPSFix) fix, /* only when in tracking interval */ !forceFix);
if (returnLiveDelay) {
delayToLive.put(trackedRace.getRaceIdentifier(), new MillisecondsDurationImpl(trackedRace.getDelayToLiveInMillis()));
}
}
}
}
@Override
public void visit(RegattaLogDeviceCompetitorMappingEvent event) {
recordForCompetitor(event.getMappedTo());
}
@Override
public void visit(RegattaLogDeviceBoatMappingEvent event) {
final Boat boat = event.getMappedTo();
final Competitor comp = trackedRace.getCompetitorOfBoat(boat);
if (comp != null) {
recordForCompetitor(comp);
} else {
// this is not necessarily something to warn of; while a boat tracker may continuously track
logger.log(Level.FINE,
()->"Could not record fix for boat because no competitor could be determined. Boat: " + boat);
}
}
private void recordForCompetitor(Competitor comp) {
if (!preemptiveStopRequested.get()) {
if (fix instanceof GPSFixMoving) {
// try to record the fix, and only if it was really to the track,
// check for maneuvers; otherwise, the fix may not have been accepted
// by the race or the track, e.g., because the race's end-of-tracking
// comes before the fix's time point
if (trackedRace.recordFix(comp, (GPSFixMoving) fix)) { // TOOD bug6229: this checks the TrackedRace's tracking interval, but for an MDI we'd also want to intersect with Event/Regatta end date if set
if (returnManeuverChanges) {
RegattaAndRaceIdentifier maneuverChangedAnswer = detectIfManeuverChanged(comp);
if (maneuverChangedAnswer != null) {
maneuverChanged.add(maneuverChangedAnswer);
}
}
if (returnLiveDelay) {
delayToLive.put(trackedRace.getRaceIdentifier(), new MillisecondsDurationImpl(trackedRace.getDelayToLiveInMillis()));
}
}
} else {
logger.log(Level.WARNING,
String.format(
"Could not add fix for competitor (%s) in race (%s), as it"
+ " is no GPSFixMoving, meaning it is missing COG/SOG values",
comp, trackedRace.getRace().getName()));
}
}
}
@Override
public void visit(RegattaLogDeviceMarkMappingEvent event) {
if (!preemptiveStopRequested.get()) {
Mark mark = event.getMappedTo();
final DynamicGPSFixTrack<Mark, GPSFix> markTrack = trackedRace.getOrCreateTrack(mark);
final GPSFix firstFixAtOrAfter;
final boolean forceFix;
if (trackedRace.isWithinStartAndEndOfTracking(fix.getTimePoint())) {
forceFix = false;
} else {
markTrack.lockForRead();
try {
if (Util.isEmpty(markTrack.getRawFixes())
|| (firstFixAtOrAfter = markTrack.getFirstFixAtOrAfter(timePoint)) != null
&& firstFixAtOrAfter.getTimePoint().equals(timePoint)) {
// either the first fix or overwriting an existing one
forceFix = true;
} else {
// checking if the given fix is "better" than an existing one
TimePoint startOfTracking = trackedRace.getStartOfTracking();
TimePoint endOfTracking = trackedRace.getEndOfTracking();
if (startOfTracking != null) {
GPSFix fixAfterStartOfTracking = markTrack
.getFirstFixAtOrAfter(startOfTracking);
if (fixAfterStartOfTracking == null
|| !trackedRace.isWithinStartAndEndOfTracking(
fixAfterStartOfTracking.getTimePoint())) {
// There is no fix in the tracking interval, so this fix could be "better"
// than ones already available in the track
// Better means closer before/after the beginning/end of the tracking
// interval
if (timePoint.before(startOfTracking)) {
// check if it is closer to the beginning of the tracking interval
GPSFix fixBeforeStartOfTracking = markTrack
.getLastFixAtOrBefore(startOfTracking);
forceFix = (fixBeforeStartOfTracking == null
|| fixBeforeStartOfTracking.getTimePoint().before(timePoint));
} else if (endOfTracking != null && timePoint.after(endOfTracking)) {
// check if it is closer to the end of the tracking interval
GPSFix fixAfterEndOfTracking = markTrack
.getFirstFixAtOrAfter(endOfTracking);
forceFix = (fixAfterEndOfTracking == null
|| fixAfterEndOfTracking.getTimePoint().after(timePoint));
} else {
forceFix = false;
}
} else {
// there is already a fix in the tracking interval
forceFix = false;
}
} else {
forceFix = false;
}
}
} finally {
markTrack.unlockAfterRead();
}
}
trackedRace.recordFix(mark, (GPSFix) fix, /* only when in tracking interval */ !forceFix);
if (returnLiveDelay) {
delayToLive.put(trackedRace.getRaceIdentifier(), new MillisecondsDurationImpl(trackedRace.getDelayToLiveInMillis()));
}
}
}
});
}
});
});
}
});
}
}
return mergeManeuverChangedAndLiveDelayResult(maneuverChanged, delayToLive);
}
@@ -878,6 +880,11 @@ public class FixLoaderAndTracker implements TrackingDataLoader {
addLoadingJob(new LoadFixesForNewlyCoveredTimeRangesJob(item, newlyCoveredTimeRanges));
}
}
@Override
public String toString() {
return "FixLoaderDeviceMappings for race "+trackedRace.getRaceIdentifier();
}
}
/**
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -69,6 +70,39 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
private final Map<ItemT, List<DeviceMappingWithRegattaLogEvent<ItemT>>> mappings = new HashMap<>();
private final Map<DeviceIdentifier, List<DeviceMappingWithRegattaLogEvent<ItemT>>> mappingsByDevice = new HashMap<>();
/**
* A cache that holds the device mappings as the {@link Pair#getB() second} component of the values in this map,
* such that exactly these device mappings apply for any time point {@link TimeRange#includes(TimePoint) included}
* by the {@link TimeRange} that is the {@link Pair#getA() first} component of a value in this map. This map's keys
* match with the {@link DeviceMapping#getDevice() device identifiers} of the {@link Pair#getB() second} components
* of their corresponding values.
* <p>
*
* This cache is designed to work well for cases where mappings change at a frequency orders of magnitude less than
* the frequency with which fixes arrive and are to be mapped to items. Furthermore, the cache hit rates benefit
* from mappings covering large time ranges.
* <p>
*
* Any change to the mappings for a device will remove the mapping for the device's {@link DeviceIdentifier
* identifier} from this map.
* <p>
*
* Access to this map has to undergo the same locking drill as any access to {@link #mappings}, using the
* {@link #mappingsLock}.
*/
private final Map<DeviceIdentifier, Pair<TimeRange, List<DeviceMappingWithRegattaLogEvent<ItemT>>>> cachedMappings = new HashMap<>();
/**
* When the {@link #cachedMappings} are to be updated, the corresponding update job is stored in this field. It must be executed
* under the {@link #mappingsLock}'s write lock. However, when other updates to {@link #mappings} or {@link #mappingsByDevice}
* are performed (usually by the {@link #updateMappingsInternal()} method), this field will be cleared because the cache update
* will most likely be obsolete.
*/
private Runnable cacheUpdateJob;
private int cacheHits;
private int cacheMisses;
private final RegattaLogEventVisitor regattaLogEventVisitor = new BaseRegattaLogEventVisitor() {
@Override
public void visit(RegattaLogDeviceCompetitorSensorDataMappingEvent event) {
@@ -156,7 +190,13 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
/**
* Calls the given callback for every DeviceMapping that is known for the given {@link DeviceIdentifier} that
* includes the given {@link TimePoint}.
* includes the given {@link TimePoint}.<p>
*
* Searches the {@link #cachedMappings} for a match for the {@code device}; if found, checks whether {@code timePoint}
* is within the time range for which device mappings were cached, and if so, uses those device mappings. Otherwise,
* the device mappings are calculated and a cache update is carried out after releasing the read-lock of
* {@link #mappingsLock} and after obtaining its write-lock. Should an update have been squeezed in between releasing
* the read-lock and obtaining the write-lock, the cache update is not carried out.
*
* @param device
* the device to get the mappings for
@@ -169,15 +209,51 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
public void forEachMappingOfDeviceIncludingTimePoint(DeviceIdentifier device, TimePoint timePoint,
Consumer<DeviceMappingWithRegattaLogEvent<ItemT>> callback) {
LockUtil.executeWithReadLock(mappingsLock, () -> {
List<DeviceMappingWithRegattaLogEvent<ItemT>> mappingsForDevice = mappingsByDevice.get(device);
if (mappingsForDevice != null) {
for (DeviceMappingWithRegattaLogEvent<ItemT> mapping : mappingsForDevice) {
if (mapping.getTimeRange().includes(timePoint)) {
callback.accept(mapping);
final Pair<TimeRange, List<DeviceMappingWithRegattaLogEvent<ItemT>>> cachedTimeRangeForDevice = cachedMappings.get(device);
if (cachedTimeRangeForDevice != null && cachedTimeRangeForDevice.getA().includes(timePoint)) {
cacheHits++;
logger.fine(() -> "Device mapping cache hit for mapper " + this + " for device " + device
+ " and time point " + timePoint + ", included in cached range "
+ cachedTimeRangeForDevice.getA() + "; " + cacheHits + " hits, " + cacheMisses + " misses");
cachedTimeRangeForDevice.getB().forEach(mapping->callback.accept(mapping));
} else {
final List<DeviceMappingWithRegattaLogEvent<ItemT>> mappingsForDevice = mappingsByDevice.get(device);
TimeRange timeRangeForCache = null;
final List<DeviceMappingWithRegattaLogEvent<ItemT>> deviceMappingsForCache = new LinkedList<>();
cacheMisses++;
if (mappingsForDevice != null) {
for (final DeviceMappingWithRegattaLogEvent<ItemT> mapping : mappingsForDevice) {
if (mapping.getTimeRange().includes(timePoint)) {
if (timeRangeForCache == null) {
timeRangeForCache = mapping.getTimeRange();
} else {
timeRangeForCache = timeRangeForCache.intersection(mapping.getTimeRange());
}
deviceMappingsForCache.add(mapping);
callback.accept(mapping);
}
}
}
final TimeRange finalTimeRangeForCache = timeRangeForCache;
logger.fine(() -> "Device mapping cache miss for mapper " + this + " for device " + device
+ " and time point " + timePoint + ", determined cachable range "
+ finalTimeRangeForCache + "; " + cacheHits + " hits, " + cacheMisses + " misses");
if (timeRangeForCache != null) {
cacheUpdateJob = ()->cachedMappings.put(device, new Pair<>(finalTimeRangeForCache, deviceMappingsForCache));
}
}
});
if (cacheUpdateJob != null) {
LockUtil.executeWithWriteLock(mappingsLock, ()->{
if (cacheUpdateJob != null) {
logger.fine(()-> "Device mapping cache miss for mapper " + this + " performs cache update.");
cacheUpdateJob.run();
} else {
logger.fine(() -> "Device mapping cache miss for mapper " + this
+ " does not update the cache because the mappings were updated in between");
}
});
}
}
public void forEachItemAndCoveredTimeRanges(final BiConsumer<ItemT, Map<RegattaLogDeviceMappingEvent<ItemT>, MultiTimeRange>> consumer) {
@@ -245,8 +321,10 @@ public abstract class RegattaLogDeviceMappings<ItemT extends WithID> {
oldMappings.putAll(mappings);
oldDeviceIds.addAll(mappingsByDevice.keySet());
mappings.clear();
cachedMappings.clear();
mappings.putAll(newMappings);
mappingsByDevice.clear();
cacheUpdateJob = null;
for (ItemT item : newMappings.keySet()) {
for (DeviceMappingWithRegattaLogEvent<ItemT> mapping : newMappings.get(item)) {
List<DeviceMappingWithRegattaLogEvent<ItemT>> list = mappingsByDevice.get(mapping.getDevice());
@@ -59,10 +59,12 @@ public class SmartFutureCacheTest {
@Override
public String computeCacheUpdate(String key, EmptyUpdateInterval updateInterval) {
synchronized (SmartFutureCacheTest.this) { // make sure we see the latest change to throwException
if (throwException[0]) {
throw new NullPointerException("Humba");
} else {
return "Humba";
synchronized (SmartFutureCacheTest.this) { // force sync of throwException
if (throwException[0]) {
throw new NullPointerException("Humba");
} else {
return "Humba";
}
}
}
}
@@ -1,5 +1,7 @@
package com.sap.sailing.domain.racelog.tracking;
import java.util.Collections;
import com.sap.sailing.domain.common.DeviceIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sse.common.Duration;
@@ -12,6 +14,7 @@ import com.sap.sse.common.Util.Triple;
* @param <FixT>
* the type of fixes this listener can consume.
*/
@FunctionalInterface
public interface FixReceivedListener<FixT extends Timed> {
/**
*
@@ -34,6 +37,32 @@ public interface FixReceivedListener<FixT extends Timed> {
* returned can be empty but is never {@code null}. It can also contain multiple identifiers if the device
* mapping is currently ambiguous.
*/
Iterable<Triple<RegattaAndRaceIdentifier, Boolean, Duration>> fixReceived(DeviceIdentifier device, FixT fix,
default Iterable<Triple<RegattaAndRaceIdentifier, Boolean, Duration>> fixReceived(DeviceIdentifier device, FixT fix,
boolean returnManeuverChanges, boolean returnLiveDelay) {
return fixesReceived(device, Collections.singleton(fix), returnManeuverChanges, returnLiveDelay);
}
/**
*
* @param device
* the device that recorded the fix. Cannot be <code>null</code>.
* @param fixes
* The fixes that were stored. Must not be <code>null</code> but may be empty
* @param returnLiveDelay
* if {@code true} then all listeners to which the fixes are forwarded shall check to which races the fix
* maps and report the live delay for the newest of those {@code fixes} for all those races as the third
* component of the resulting {@link Triple}s.
* @param returnManeuverUpdate
* if {@code true}, all listeners to which this fixes are forwarded shall check whether the fixes feed
* into a competitor's track in the scope of a race where for that competitor the maneuver list has
* changed since the last call of this type; if so, the race identifier will be part of the result, with
* the {@link Boolean} component being {@code true} for that race. Otherwise, the {@link Boolean}
* component is {@code false} or the race is not listed in the result.
* @return An {@link Iterable} with {@link RegattaAndRaceIdentifier}s is returned that will contain races with new
* maneuvers which were not available at the last time the given device stored a fix. The {@link Iterable}
* returned can be empty but is never {@code null}. It can also contain multiple identifiers if the device
* mapping is currently ambiguous.
*/
Iterable<Triple<RegattaAndRaceIdentifier, Boolean, Duration>> fixesReceived(DeviceIdentifier device, Iterable<FixT> fixes,
boolean returnManeuverChanges, boolean returnLiveDelay);
}
@@ -6,10 +6,11 @@ public class FavoritesResult implements Result {
private FavoriteBoatClassesDTO favoriteBoatClasses;
private FavoriteCompetitorsDTO favoriteCompetitors;
private boolean isSubscribedToFeatureAndCommunityUpdates;
protected FavoritesResult() {}
public FavoritesResult(FavoriteBoatClassesDTO favoriteBoatClasses, FavoriteCompetitorsDTO favoriteCompetitors) {
public FavoritesResult(FavoriteBoatClassesDTO favoriteBoatClasses, FavoriteCompetitorsDTO favoriteCompetitors, boolean isSubscribedToFeatureAndCommunityUpdates) {
this.favoriteBoatClasses = favoriteBoatClasses;
this.favoriteCompetitors = favoriteCompetitors;
}
@@ -22,4 +23,8 @@ public class FavoritesResult implements Result {
return favoriteCompetitors;
}
public boolean getIsSubscribedToFeatureAndCommunityUpdates() {
return isSubscribedToFeatureAndCommunityUpdates;
}
}
@@ -25,7 +25,13 @@ public class GetFavoritesAction implements SailingAction<FavoritesResult> {
@Override
@GwtIncompatible
public FavoritesResult execute(SailingDispatchContext ctx) throws DispatchException {
return new FavoritesResult(getFavoriteBoatClasses(ctx), getFavoriteCompetitors(ctx));
return new FavoritesResult(getFavoriteBoatClasses(ctx), getFavoriteCompetitors(ctx),
getDidOptOutOfFeatureAndCommunityEmails(ctx));
}
@GwtIncompatible
private boolean getDidOptOutOfFeatureAndCommunityEmails(SailingDispatchContext ctx) {
return ctx.getSecurityService().getCurrentUser().getDidOptOutOfFeatureAndCommunityEmails();
}
@GwtIncompatible
@@ -0,0 +1,33 @@
package com.sap.sailing.gwt.home.communication.user.profile;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sse.gwt.dispatch.shared.commands.HasWriteAction;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
import com.sap.sse.security.shared.UserManagementException;
public class SaveMiscEmailPreferences implements SailingAction<VoidResult>, HasWriteAction {
private Boolean subscribeToFeatureAndCommunityUpdates;
protected SaveMiscEmailPreferences() {
}
public SaveMiscEmailPreferences(final Boolean subscribeToFeatureAndCommunityUpdates) {
this.subscribeToFeatureAndCommunityUpdates = subscribeToFeatureAndCommunityUpdates;
}
@Override
@GwtIncompatible
public VoidResult execute(SailingDispatchContext ctx) throws DispatchException {
try {
final String username = ctx.getSecurityService().getCurrentUser().getName();
ctx.getSecurityService().updateUserProperties(username, null, null, null,
!subscribeToFeatureAndCommunityUpdates);
} catch (UserManagementException e) {
throw new DispatchException(e.getMessage());
}
return new VoidResult();
}
}
@@ -68,7 +68,7 @@
line-height: normal;
width: 100%;
position: relative;
z-index: 1000;
z-index: 1;
}
.dfooter_row {
display: flex;
@@ -10,6 +10,11 @@
<ul class="bulletList">
<li>Tables with multi-selection support now have a select/de-select all checkbox in the table header.
This comes with general improvements in table selection/de-selection handling.</li>
<li>Adding the "Race Rank" column to the leaderboard now consistently adds it after the selection
checkbox column and displays it immediately when the settings dialog is confirmed.</li>
<li>Users can now opt out of e-mail communication regarding features and community
information. This will be honored when sending out such general information about
the Sailing Analytics solution.</li>
</ul>
<h5 class="articleSubheadline">March 2026</h5>
<ul class="bulletList">
@@ -0,0 +1,59 @@
.container {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5em;
padding: 0.333333333333333em;
}
.checkbox {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 2em;
height: 2em;
}
.checkbox input {
width: 1.333333333333333em;
height: 2em;
}
.label {
flex: auto;
font-weight: 600;
padding-right: 2.666666666666667em;
line-height: 2em;
min-width: 0;
text-align: left;
}
.loadingOverlay {
position: absolute;
inset: 0;
pointer-events: all;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.3);
z-index: 10;
}
.spinner {
width: 60%;
aspect-ratio: 1/1;
border: 2px solid #ccc;
border-top-color: #1976d2;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes
spin {
from {
transform:rotate(0deg);
} to {
transform: rotate(360deg);
}
}
@@ -0,0 +1,120 @@
package com.sap.sailing.gwt.home.shared.partials.checkboxtile;
import java.util.function.BiConsumer;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
/**
* @param onToggle
* if null, toggle will be disabled
*/
public final class CheckBoxTile extends Composite implements HasValue<Boolean> {
private static CheckBoxTileUiBinder uiBinder = GWT.create(CheckBoxTileUiBinder.class);
interface CheckBoxTileUiBinder extends UiBinder<Widget, CheckBoxTile> {
}
@UiField
CheckBoxTileResources res;
@UiField
Label labelUi;
@UiField
CheckBox toggleButtonUi;
private DivElement loadingOverlay;
public CheckBoxTile(final String label, final boolean initialState,
final BiConsumer<Boolean, AsyncCallback<VoidResult>> onToggle) {
super();
CheckBoxTileResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
labelUi.setText(label);
initToggleButtonUi(initialState, onToggle);
}
private void initToggleButtonUi(final boolean initialState,
final BiConsumer<Boolean, AsyncCallback<VoidResult>> onToggle) {
toggleButtonUi.setValue(initialState);
if (onToggle == null) {
toggleButtonUi.setEnabled(false);
}
toggleButtonUi.getElement().getStyle().setProperty("position", "relative");
final ValueChangeHandler<Boolean> loadingHandler = value -> {
final Boolean newlyToggledValue = value.getValue();
overlayLoadingSpinner();
final AsyncCallback<VoidResult> callback = new AsyncCallback<VoidResult>() {
@Override
public void onFailure(Throwable caught) {
// undo failed toggle, false arg enforces silence of change handlers on this call
toggleButtonUi.setValue(!newlyToggledValue, false);
hideLoadingSpinner();
}
@Override
public void onSuccess(VoidResult result) {
hideLoadingSpinner();
}
};
onToggle.accept(newlyToggledValue, callback);
};
toggleButtonUi.addValueChangeHandler(loadingHandler);
}
private void overlayLoadingSpinner() {
toggleButtonUi.setEnabled(false);
if (loadingOverlay == null) {
initLoadingOverlay();
}
loadingOverlay.getStyle().setProperty("display", "flex");
}
private void initLoadingOverlay() {
// add elements
loadingOverlay = Document.get().createDivElement();
loadingOverlay.addClassName(res.css().loadingOverlay());
final DivElement spinner = Document.get().createDivElement();
spinner.addClassName(res.css().spinner());
// add to canvas
loadingOverlay.appendChild(spinner);
toggleButtonUi.getElement().appendChild(loadingOverlay);
}
private void hideLoadingSpinner() {
if (loadingOverlay != null) {
loadingOverlay.getStyle().setProperty("display", "none");
toggleButtonUi.setEnabled(true);
}
}
@Override
public void setValue(Boolean b) {
toggleButtonUi.setValue(b);
}
@Override
public Boolean getValue() {
return toggleButtonUi.getValue();
}
@Override
public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Boolean> handler) {
return toggleButtonUi.addValueChangeHandler(handler);
}
@Override
public void setValue(Boolean value, boolean fireEvents) {
toggleButtonUi.setValue(value, fireEvents);
}
}
@@ -0,0 +1,9 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.home.shared.partials.checkboxtile.CheckBoxTileResources" />
<g:HTMLPanel addStyleNames="{res.css.container}">
<g:Label addStyleNames="{res.css.label}" ui:field="labelUi"/>
<g:CheckBox addStyleNames="{res.css.checkbox}" ui:field="toggleButtonUi" />
</g:HTMLPanel>
</ui:UiBinder>
@@ -0,0 +1,21 @@
package com.sap.sailing.gwt.home.shared.partials.checkboxtile;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
public interface CheckBoxTileResources extends ClientBundle {
public static final CheckBoxTileResources INSTANCE = GWT.create(CheckBoxTileResources.class);
@Source("CheckBoxTile.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String container();
String label();
String checkbox();
String loadingOverlay();
String spinner();
}
}
@@ -0,0 +1,27 @@
package com.sap.sailing.gwt.home.shared.partials.labeledbox;
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.Composite;
import com.google.gwt.user.client.ui.Widget;
public class LabeledBox extends Composite {
@UiField
SpanElement headerTitleUi;
@UiField(provided = true)
Widget childUi;
private static LabeledBoxUiBinder uiBinder = GWT.create(LabeledBoxUiBinder.class);
interface LabeledBoxUiBinder extends UiBinder<Widget, LabeledBox> {
}
public LabeledBox(final String title, final Widget childUi) {
this.childUi = childUi;
initWidget(uiBinder.createAndBindUi(this));
headerTitleUi.setInnerText(title);
}
}
@@ -0,0 +1,16 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="local_res"
type="com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionResources" />
<ui:style>
</ui:style>
<g:HTMLPanel addStyleNames="{local_res.css.suggestions}">
<div class="{local_res.css.suggestionsHeader}">
<span class="{local_res.css.suggestionsHeaderTitle}"
ui:field="headerTitleUi" />
</div>
<g:Widget ui:field="childUi" />
</g:HTMLPanel>
</ui:UiBinder>
@@ -51,16 +51,18 @@ public abstract class AbstractSuggestedMultiSelectionPresenter<T, D extends Disp
selectedItemsMap.clear();
persist();
}
@Override
public Collection<T> getSelection() {
return new HashSet<>(selectedItemsMap.values());
}
@Override
public final void initSelectedItems(Collection<T> selectedItems) {
public final void initSelectedItems(Iterable<T> selectedItems) {
selectedItemsMap.clear();
for (T item : selectedItems) {
selectedItemsMap.put(getKey(item), item);
}
for (D display : displays) {
display.setSelectedItems(selectedItems);
}
}
@Override
@@ -0,0 +1,149 @@
package com.sap.sailing.gwt.home.shared.partials.multiselection;
import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.google.gwt.user.client.rpc.AsyncCallback;
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.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.gwt.home.shared.partials.checkboxtile.CheckBoxTile;
import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter;
import com.sap.sailing.gwt.home.shared.partials.labeledbox.LabeledBox;
import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.BoatClassSelectionPresenter;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
public class BoatClassDisplayImpl implements IsWidget, BoatClassSelectionPresenter.Display {
public final LabeledBox selectionUi;
private final FlowPanel childUi;
private final CheckBoxTile upcomingRacesUi;
private final CheckBoxTile resultsUi;
private final SuggestedMultiSelection<BoatClassDTO> filterUi;
private final BoatClassSelectionPresenter presenter;
@Override
public Widget asWidget() {
return selectionUi;
}
@Override
public boolean getNotifyAboutUpcomingRaces() {
return upcomingRacesUi.getValue();
}
@Override
public boolean getNotifyAboutResults() {
return resultsUi.getValue();
}
@Override
public Collection<BoatClassDTO> getSelection() {
return filterUi.getSelection();
}
public BoatClassDisplayImpl(final BoatClassSelectionPresenter presenter) {
this.presenter = presenter;
presenter.addDisplay(this);
upcomingRacesUi = composeUpcomingRacesTile();
resultsUi = composeResultsTile();
filterUi = composeFilter();
childUi = new FlowPanel();
childUi.add(upcomingRacesUi);
childUi.add(resultsUi);
childUi.add(filterUi);
final String title = StringMessages.INSTANCE.favoriteBoatClasses();
selectionUi = new LabeledBox(title, childUi);
}
private SuggestedMultiSelection<BoatClassDTO> composeFilter() {
final SuggestedMultiSelection.WidgetFactory<BoatClassDTO> widgetFactory = new SuggestedMultiSelection.WidgetFactory<BoatClassDTO>() {
@Override
public IsWidget generateItemDescriptionWidget(BoatClassDTO item) {
return new SuggestedMultiSelectionBoatClassItemDescription(item);
}
@Override
public AbstractSuggestBoxFilter<BoatClassDTO, BoatClassDTO> generateSuggestionSearchBar(
Consumer<BoatClassDTO> selectionCallback) {
final String text = StringMessages.INSTANCE.add(StringMessages.INSTANCE.boatClass());
return new SuggestedMultiSelection.SelectableSuggestion<BoatClassDTO>(presenter, selectionCallback, text);
}
};
final AsyncCallback<VoidResult> callbackWrappedWithToastNotification = new AsyncCallback<VoidResult>() {
@Override
public void onFailure(Throwable caught) {
Notification.notify(StringMessages.INSTANCE.failedToModifyFavoredBoatClasses(), NotificationType.ERROR);
}
@Override
public void onSuccess(VoidResult result) {
Notification.notify(StringMessages.INSTANCE.succesfullyModifiedFavoredBoatClasses(), NotificationType.SUCCESS);
}
};
presenter.setSelectionPersistenceCallback(callbackWrappedWithToastNotification);
return new SuggestedMultiSelection<>(presenter, widgetFactory);
}
private CheckBoxTile composeUpcomingRacesTile() {
final BiConsumer<Boolean, AsyncCallback<VoidResult>> onToggle = (isNowTrue, callback) -> {
presenter.setNotifyAboutUpcomingRaces(isNowTrue, wrapCallbackWithToastResponse(isNowTrue, callback,
StringMessages.INSTANCE.failedToSetStatusOfUpdatesOnUpcomingRacesForYourFavoredBoatClasses(),
StringMessages.INSTANCE.youWillNowReceiveNotificationsForFavoriteBoatClassUpcomingRaces(),
StringMessages.INSTANCE.youWillNotReceiveUpdatesOnUpcomingRacesForYourFavoredBoatClassesAnymore()));
};
final String title = StringMessages.INSTANCE.notificationAboutUpcomingRaces();
return new CheckBoxTile(title, false, onToggle);
}
private CheckBoxTile composeResultsTile() {
final BiConsumer<Boolean, AsyncCallback<VoidResult>> onToggle = (isNowTrue, callback) -> {
presenter.setNotifyAboutResults(isNowTrue, wrapCallbackWithToastResponse(isNowTrue, callback,
StringMessages.INSTANCE.failedToSetStatusOfUpdatesOnNewResultsForYourFavoredBoatClasses(),
StringMessages.INSTANCE.youWillNowReceiveUpdatesOnNewResultsForYourFavoredBoatClasses(),
StringMessages.INSTANCE.youWillNotReceiveNotificationsForFavoriteBoatClassNewResultsAnymore()));
};
final String title = StringMessages.INSTANCE.notificationAboutNewResults();
return new CheckBoxTile(title, false, onToggle);
}
private AsyncCallback<VoidResult> wrapCallbackWithToastResponse(final boolean isNowTrue,
final AsyncCallback<VoidResult> callback, final String failText, final String passAndTrue,
final String passAndFalse) {
final AsyncCallback<VoidResult> callbackWrappedWithToastNotification = new AsyncCallback<VoidResult>() {
@Override
public void onFailure(Throwable caught) {
Notification.notify(failText, NotificationType.ERROR);
if (callback != null) {
callback.onFailure(caught);
}
}
@Override
public void onSuccess(VoidResult result) {
final String message = isNowTrue ? passAndTrue : passAndFalse;
Notification.notify(message, NotificationType.SUCCESS);
if (callback != null) {
callback.onSuccess(result);
}
}
};
return callbackWrappedWithToastNotification;
}
@Override
public void setSelectedItems(Iterable<BoatClassDTO> selectedItems) {
filterUi.setSelectedItems(selectedItems);
}
@Override
public void initResults(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults, Collection<BoatClassDTO> selection) {
upcomingRacesUi.setValue(notifyAboutUpcomingRaces);
resultsUi.setValue(notifyAboutResults);
filterUi.setSelectedItems(selection);
}
}
@@ -0,0 +1,129 @@
package com.sap.sailing.gwt.home.shared.partials.multiselection;
import java.util.Collection;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.google.gwt.user.client.rpc.AsyncCallback;
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.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
import com.sap.sailing.gwt.home.shared.partials.checkboxtile.CheckBoxTile;
import com.sap.sailing.gwt.home.shared.partials.filter.AbstractSuggestBoxFilter;
import com.sap.sailing.gwt.home.shared.partials.labeledbox.LabeledBox;
import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.CompetitorSelectionPresenter;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
public class CompetitorDisplayImpl implements IsWidget, CompetitorSelectionPresenter.Display {
public final LabeledBox selectionUi;
private final FlowPanel childUi;
private final CheckBoxTile tileUi;
private final SuggestedMultiSelection<SimpleCompetitorWithIdDTO> filterUi;
private final CompetitorSelectionPresenter presenter;
@Override
public Widget asWidget() {
return selectionUi;
}
public boolean getIsNotify() {
return tileUi.getValue();
}
public CompetitorDisplayImpl(CompetitorSelectionPresenter presenter, FlagImageResolver flagImageResolver) {
this.presenter = presenter;
presenter.addDisplay(this);
tileUi = composeTile();
filterUi = composeFilter(flagImageResolver);
childUi = new FlowPanel();
childUi.add(tileUi);
childUi.add(filterUi);
final String title = StringMessages.INSTANCE.favoriteCompetitors();
selectionUi = new LabeledBox(title, childUi);
}
private SuggestedMultiSelection<SimpleCompetitorWithIdDTO> composeFilter(FlagImageResolver flagImageResolver) {
final SuggestedMultiSelection.WidgetFactory<SimpleCompetitorWithIdDTO> widgetFactory = new SuggestedMultiSelection.WidgetFactory<SimpleCompetitorWithIdDTO>() {
@Override
public IsWidget generateItemDescriptionWidget(SimpleCompetitorWithIdDTO item) {
return new SuggestedMultiSelectionCompetitorItemDescription(item, flagImageResolver);
}
@Override
public AbstractSuggestBoxFilter<SimpleCompetitorWithIdDTO, SimpleCompetitorWithIdDTO> generateSuggestionSearchBar(
Consumer<SimpleCompetitorWithIdDTO> onSuggestionSelectedCallback) {
final String text = StringMessages.INSTANCE.add(StringMessages.INSTANCE.competitor());
return new SuggestedMultiSelection.SelectableSuggestion<SimpleCompetitorWithIdDTO>(presenter, onSuggestionSelectedCallback,
text);
}
};
// TODO add different messages to toast response here
final AsyncCallback<VoidResult> selectionPersistenceCallback = new AsyncCallback<VoidResult>() {
@Override
public void onFailure(Throwable caught) {
Notification.notify(StringMessages.INSTANCE.failedToModifyFavoriteCompetitors(), NotificationType.ERROR);
}
@Override
public void onSuccess(VoidResult result) {
Notification.notify(StringMessages.INSTANCE.favoriteCompetitorsModifiedSuccessfully(), NotificationType.SUCCESS);
}
};
presenter.setSelectionPersistenceCallback(selectionPersistenceCallback);
return new SuggestedMultiSelection<>(presenter, widgetFactory);
}
private CheckBoxTile composeTile() {
final BiConsumer<Boolean, AsyncCallback<VoidResult>> onToggle = (isNowTrue, callback) -> {
presenter.persistResults(isNowTrue, wrapCallbackWithToastResponse(isNowTrue, callback),
presenter.getSelection());
};
final String title = StringMessages.INSTANCE.notificationAboutNewResults();
return new CheckBoxTile(title, false, onToggle);
}
private AsyncCallback<VoidResult> wrapCallbackWithToastResponse(final boolean isNowTrue,
final AsyncCallback<VoidResult> callback) {
final AsyncCallback<VoidResult> callbackWrappedWithToastNotification = new AsyncCallback<VoidResult>() {
@Override
public void onFailure(Throwable caught) {
final String failText = StringMessages.INSTANCE
.failedToSetStatusOfNotificationsForFavoriteCompetitors();
Notification.notify(failText, NotificationType.ERROR);
if (callback != null) {
callback.onFailure(caught);
}
}
@Override
public void onSuccess(VoidResult result) {
final String passAndTrue = StringMessages.INSTANCE
.youWillNowReceiveNotificationsForFavoriteCompetitors();
final String passAndFalse = StringMessages.INSTANCE
.youWillNotReceiveNotificationsForFavoriteCompetitorsAnymore();
final String message = isNowTrue ? passAndTrue : passAndFalse;
Notification.notify(message, NotificationType.SUCCESS);
if (callback != null) {
callback.onSuccess(result);
}
}
};
return callbackWrappedWithToastNotification;
}
@Override
public void setSelectedItems(Iterable<SimpleCompetitorWithIdDTO> selectedItemsToSet) {
filterUi.setSelectedItems(selectedItemsToSet);
}
@Override
public void initResults(boolean notifyAboutResults, Collection<SimpleCompetitorWithIdDTO> latestSelectedItems) {
filterUi.setSelectedItems(latestSelectedItems);
tileUi.setValue(notifyAboutResults, false);
}
}
@@ -0,0 +1,71 @@
package com.sap.sailing.gwt.home.shared.partials.multiselection;
import java.util.function.BiConsumer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.sap.sailing.gwt.home.shared.partials.checkboxtile.CheckBoxTile;
import com.sap.sailing.gwt.home.shared.partials.labeledbox.LabeledBox;
import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.MiscPreferencesPresenter;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
public class MiscellaneousDisplayImpl {
public final LabeledBox selectionUi;
private final CheckBoxTile featureAndCommunityUpdates;
public MiscellaneousDisplayImpl(final MiscPreferencesPresenter presenter) {
presenter.registerDisplay(this);
// compose ui
final String securityUpdatesTitle = StringMessages.INSTANCE.securityUpdates();
final CheckBoxTile securityUpdates = new CheckBoxTile(securityUpdatesTitle, true, null);
featureAndCommunityUpdates = composeFeatureAndCommunityUpdatesTile(presenter);
final FlowPanel tileList = new FlowPanel();
tileList.add(securityUpdates);
tileList.add(featureAndCommunityUpdates);
final String boxTitle = StringMessages.INSTANCE.miscellaneous();
selectionUi = new LabeledBox(boxTitle, tileList);
}
public void setIsSubscribedToFeatureAndCommunityUpdates(final boolean b, final boolean fireChangeHandlers) {
featureAndCommunityUpdates.setValue(b, fireChangeHandlers);
}
private AsyncCallback<VoidResult> wrapCallbackWithToastResponse(final boolean isNowTrue,
final AsyncCallback<VoidResult> callback) {
final AsyncCallback<VoidResult> callbackWrappedWithToastNotification = new AsyncCallback<VoidResult>() {
@Override
public void onFailure(Throwable caught) {
final String failText = StringMessages.INSTANCE.failedToSetStatusOfFeatureAndCommunityUpdates();
Notification.notify(failText, NotificationType.ERROR);
if (callback != null) {
callback.onFailure(caught);
}
}
@Override
public void onSuccess(VoidResult result) {
final String passAndTrue = StringMessages.INSTANCE.youWillNowReceiveFeatureAndCommunityUpdates();
final String passAndFalse = StringMessages.INSTANCE
.youWillNotReceiveFeatureAndCommunityUpdatesAnymore();
final String message = isNowTrue ? passAndTrue : passAndFalse;
Notification.notify(message, NotificationType.SUCCESS);
if (callback != null) {
callback.onSuccess(result);
}
}
};
return callbackWrappedWithToastNotification;
}
private CheckBoxTile composeFeatureAndCommunityUpdatesTile(final MiscPreferencesPresenter presenter) {
final BiConsumer<Boolean, AsyncCallback<VoidResult>> onToggle = (isNowTrue, callback) -> {
final AsyncCallback<VoidResult> wrappedCallback = wrapCallbackWithToastResponse(isNowTrue, callback);
presenter.updateIsSubscribedToFeatureAndCommunityUpdates(isNowTrue, wrappedCallback);
};
final String title = StringMessages.INSTANCE.featureAndCommunityUpdates();
return new CheckBoxTile(title, false, onToggle);
}
}
@@ -1,11 +1,12 @@
package com.sap.sailing.gwt.home.shared.partials.multiselection;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Consumer;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
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;
@@ -13,18 +14,13 @@ 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.HasValue;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.UIObject;
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.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.SuggestedMultiSelectionPresenter.SuggestionItemsCallback;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.suggestion.AbstractSuggestOracle;
/**
@@ -42,103 +38,98 @@ public final class SuggestedMultiSelection<T> extends Composite implements Sugge
interface SuggestedMultiSelectionUiBinder extends UiBinder<Widget, SuggestedMultiSelection<?>> {
}
@UiField
SpanElement headerTitleUi;
@UiField
FlowPanel notificationToggleContainerUi;
@UiField
DivElement contentSeparatorUi;
@UiField(provided = true)
AbstractFilterWidget<T, T> suggestionWidgetUi;
AbstractFilterWidget<T, T> searchUi;
@UiField
Button removeAllButtonUi;
@UiField
FlowPanel itemContainerUi;
FlowPanel selectedItemsUi;
private final SuggestedMultiSelectionPresenter<T, ?> presenter;
private final WidgetProvider<T> widgetProvider;
private final WidgetFactory<T> widgetFactory;
private SuggestedMultiSelection(SuggestedMultiSelectionPresenter<T, ?> presenter,
WidgetProvider<T> widgetProvider, String title) {
SuggestedMultiSelectionResources.INSTANCE.css().ensureInjected();
this.presenter = presenter;
this.widgetProvider = widgetProvider;
this.suggestionWidgetUi = widgetProvider.getSuggestBoxFilter(selectedItem -> {
presenter.addSelection(selectedItem);
SuggestedMultiSelection.this.addSelectedItem(selectedItem);
});
initWidget(uiBinder.createAndBindUi(this));
headerTitleUi.setInnerText(title);
UIObject.setVisible(contentSeparatorUi, false);
this.updateUiState();
public static interface WidgetFactory<T> {
IsWidget generateItemDescriptionWidget(T item);
AbstractSuggestBoxFilter<T, T> generateSuggestionSearchBar(Consumer<T> onSuggestionSelectedCallback);
}
/**
* Adds a checkbox with the given label to toggle notifications by notifying the provided callback.
*
* @param callback
* {@link Consumer Callback} which get notified on checkbox toggles
* @param label
* {@link String Label} for the added checkbox
* @return reference on the added checkbox
*/
public HasValue<Boolean> addNotificationToggle(Consumer<Boolean> callback, String label) {
SuggestedMultiSelectionNotificationToggle notification = new SuggestedMultiSelectionNotificationToggle(label);
notification.addValueChangeHandler(event -> callback.accept(event.getValue()));
notificationToggleContainerUi.add(notification);
UIObject.setVisible(contentSeparatorUi, true);
return notification;
public SuggestedMultiSelection(SuggestedMultiSelectionPresenter<T, ?> presenter,
WidgetFactory<T> widgetFactory) {
SuggestedMultiSelectionResources.INSTANCE.css().ensureInjected();
this.presenter = presenter;
this.widgetFactory = widgetFactory;
this.searchUi = widgetFactory.generateSuggestionSearchBar(e -> {
presenter.addSelection(e);
selectedItemsUi.add(generateSelectedItemUi(e));
});
initWidget(uiBinder.createAndBindUi(this));
}
@UiHandler("removeAllButtonUi")
void onRemoveAllButtonClicked(ClickEvent event) {
presenter.clearSelection();
itemContainerUi.clear();
this.updateUiState();
selectedItemsUi.clear();
UIObject.setVisible(contentSeparatorUi, false);
removeAllButtonUi.setEnabled(false);
}
public Set<T> getSelection(){
return new HashSet<>(presenter.getSelection());
}
@Override
public void setSelectedItems(Iterable<T> selectedItemsToSet) {
itemContainerUi.clear();
selectedItemsToSet.forEach(this::addSelectedItem);
public void setSelectedItems(Iterable<T> toBeSet) {
selectedItemsUi.clear();
UIObject.setVisible(contentSeparatorUi, true);
presenter.initSelectedItems(toBeSet);
toBeSet.forEach(e -> {
selectedItemsUi.add(generateSelectedItemUi(e));
});
final boolean areItemsNonEmpty = toBeSet.iterator().hasNext();
removeAllButtonUi.setEnabled(areItemsNonEmpty);
}
private void addSelectedItem(final T selectedItem) {
itemContainerUi.add(new SuggestedMultiSelectionItem() {
private SuggestedMultiSelectionItem generateSelectedItemUi(T selectedItem) {
return new SuggestedMultiSelectionItem() {
@Override
protected IsWidget getItemDescriptionWidget() {
return widgetProvider.getItemDescriptionWidget(selectedItem);
return widgetFactory.generateItemDescriptionWidget(selectedItem);
}
@Override
protected void onRemoveItemRequsted() {
presenter.removeSelection(selectedItem);
if (presenter.getSelection().isEmpty()) {
UIObject.setVisible(contentSeparatorUi, false);
}
this.removeFromParent();
updateUiState();
removeAllButtonUi.setEnabled(selectedItemsUi.getWidgetCount() > 0);
}
});
this.updateUiState();
};
}
private void updateUiState() {
removeAllButtonUi.setEnabled(itemContainerUi.getWidgetCount() > 0);
}
public static class SelectableSuggestion<T> extends AbstractAsyncSuggestBoxFilter<T, T> {
private final Consumer<T> onPressedCallback;
private static class SuggestedMultiSelectionFilter<T> extends AbstractAsyncSuggestBoxFilter<T, T> {
private final Consumer<T> selectionCallback;
public SelectableSuggestion(final SuggestedMultiSelectionPresenter<T, ?> presenter,
Consumer<T> onPressedCallback, String placeholderText) {
super(buildOracle(presenter), placeholderText);
this.onPressedCallback = onPressedCallback;
}
private SuggestedMultiSelectionFilter(final SuggestedMultiSelectionPresenter<T, ?> presenter,
Consumer<T> selectionCallback, String placeholderText) {
super(new AbstractSuggestOracle<T>() {
private static <T> AbstractSuggestOracle<T> buildOracle(final SuggestedMultiSelectionPresenter<T, ?> presenter) {
return new AbstractSuggestOracle<T>() {
@Override
protected void getSuggestions(final Request request, final Callback callback,
final Iterable<String> queryTokens) {
presenter.getSuggestionItems(queryTokens, request.getLimit(), new SuggestionItemsCallback<T>() {
final SuggestionItemsCallback<T> callback2 = new SuggestionItemsCallback<T>() {
@Override
public void setSuggestionItems(Collection<T> suggestionItems) {
setSuggestions(request, callback, suggestionItems, queryTokens);
}
});
};
presenter.getSuggestionItems(queryTokens, request.getLimit(), callback2);
}
@Override
@@ -150,55 +141,13 @@ public final class SuggestedMultiSelection<T> extends Composite implements Sugge
protected String createSuggestionAdditionalDisplayString(T value) {
return presenter.createSuggestionAdditionalDisplayString(value);
}
}, placeholderText);
this.selectionCallback = selectionCallback;
};
}
@Override
protected final void onSuggestionSelected(T selectedItem) {
SuggestedMultiSelectionFilter.this.clear();
selectionCallback.accept(selectedItem);
SelectableSuggestion.this.clear();
onPressedCallback.accept(selectedItem);
}
}
private interface WidgetProvider<T> {
IsWidget getItemDescriptionWidget(T item);
AbstractSuggestBoxFilter<T, T> getSuggestBoxFilter(Consumer<T> selectionCallback);
}
public static SuggestedMultiSelection<SimpleCompetitorWithIdDTO> forCompetitors(
final SuggestedMultiSelectionPresenter<SimpleCompetitorWithIdDTO, ?> presenter, String headerTitle,
FlagImageResolver flagImageResolver) {
return new SuggestedMultiSelection<>(presenter, new WidgetProvider<SimpleCompetitorWithIdDTO>() {
@Override
public IsWidget getItemDescriptionWidget(SimpleCompetitorWithIdDTO item) {
return new SuggestedMultiSelectionCompetitorItemDescription(item, flagImageResolver);
}
@Override
public AbstractSuggestBoxFilter<SimpleCompetitorWithIdDTO, SimpleCompetitorWithIdDTO> getSuggestBoxFilter(
Consumer<SimpleCompetitorWithIdDTO> selectionCallback) {
return new SuggestedMultiSelectionFilter<SimpleCompetitorWithIdDTO>(presenter, selectionCallback,
StringMessages.INSTANCE.add(StringMessages.INSTANCE.competitor()));
}
}, headerTitle);
}
public static SuggestedMultiSelection<BoatClassDTO> forBoatClasses(
final SuggestedMultiSelectionPresenter<BoatClassDTO, ?> presenter, String headerTitle) {
return new SuggestedMultiSelection<>(presenter, new WidgetProvider<BoatClassDTO>() {
@Override
public IsWidget getItemDescriptionWidget(BoatClassDTO item) {
return new SuggestedMultiSelectionBoatClassItemDescription(item);
}
@Override
public AbstractSuggestBoxFilter<BoatClassDTO, BoatClassDTO> getSuggestBoxFilter(
Consumer<BoatClassDTO> selectionCallback) {
return new SuggestedMultiSelectionFilter<BoatClassDTO>(presenter, selectionCallback,
StringMessages.INSTANCE.add(StringMessages.INSTANCE.boatClass()));
}
}, headerTitle);
}
}
@@ -5,19 +5,15 @@
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionResources" />
<g:HTMLPanel addStyleNames="{local_res.css.suggestions}">
<div class="{local_res.css.suggestionsHeader}">
<span class="{local_res.css.suggestionsHeaderTitle}" ui:field="headerTitleUi" />
</div>
<div class="{local_res.css.suggestionsContent}">
<g:FlowPanel ui:field="notificationToggleContainerUi" />
<div ui:field="contentSeparatorUi" class="{local_res.css.suggestionsContentSeparator}"></div>
<div class="{local_res.css.suggestionsContentToolbar}">
<sp:filter.AbstractFilterWidget addStyleNames="{local_res.css.suggestionsAddFilter}" ui:field="suggestionWidgetUi" />
<sp:filter.AbstractFilterWidget addStyleNames="{local_res.css.suggestionsAddFilter}" ui:field="searchUi" />
<g:Button addStyleNames="{res.mainCss.button} {res.mainCss.buttonred} {local_res.css.suggestionsRemoveButton}" ui:field="removeAllButtonUi">
<ui:text from="{i18n.removeAll}"/>
</g:Button>
</div>
<g:FlowPanel addStyleNames="{local_res.css.suggestionsContentTable}" ui:field="itemContainerUi" />
<g:FlowPanel addStyleNames="{local_res.css.suggestionsContentTable}" ui:field="selectedItemsUi" />
</div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -4,6 +4,7 @@ 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.safehtml.shared.SafeUri;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Widget;
@@ -24,8 +25,10 @@ public class SuggestedMultiSelectionCompetitorItemDescription extends Widget {
public SuggestedMultiSelectionCompetitorItemDescription(SimpleCompetitorDTO competitor,
FlagImageResolver flagImageResolver) {
setElement(uiBinder.createAndBindUi(this));
flagImageUi.getStyle().setBackgroundImage("url('" + flagImageResolver.getFlagImageUri(
competitor.getFlagImageURL(), competitor.getTwoLetterIsoCountryCode()).asString() + "')");
final String countryCode = competitor.getTwoLetterIsoCountryCode();
final SafeUri flagImageUri = flagImageResolver.getFlagImageUri(competitor.getFlagImageURL(), countryCode);
final String bgUrl = "url('" + flagImageUri.asString() + "')";
flagImageUi.getStyle().setBackgroundImage(bgUrl);
sailIdUi.setInnerText(competitor.getShortInfo());
nameUi.setInnerText(competitor.getName());
}
@@ -23,7 +23,7 @@ class SuggestedMultiSelectionNotificationToggle extends Composite implements Has
@UiField Label labelUi;
@UiField CheckBox toggleButtonUi;
SuggestedMultiSelectionNotificationToggle(String label) {
public SuggestedMultiSelectionNotificationToggle(String label) {
initWidget(uiBinder.createAndBindUi(this));
labelUi.setText(label);
}
@@ -6,13 +6,15 @@ import com.google.gwt.view.client.ProvidesKey;
import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionPresenter.Display;
public interface SuggestedMultiSelectionPresenter<T, D extends Display<T>> extends ProvidesKey<T> {
void addSelection(T item);
void removeSelection(T item);
void clearSelection();
Collection<T> getSelection();
void getSuggestionItems(Iterable<String> queryTokens, int limit, final SuggestionItemsCallback<T> callback);
String createSuggestionKeyString(T value);
@@ -23,7 +25,7 @@ public interface SuggestedMultiSelectionPresenter<T, D extends Display<T>> exten
void persist();
void initSelectedItems(Collection<T> selectedItems);
void initSelectedItems(Iterable<T> selectedItems);
interface SuggestionItemsCallback<T> {
void setSuggestionItems(Collection<T> suggestionItems);
@@ -1,22 +1,34 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.preferences;
import java.util.Collection;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.dto.BoatClassDTO;
import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionPresenter;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
public interface BoatClassSelectionPresenter
extends SuggestedMultiSelectionPresenter<BoatClassDTO, BoatClassSelectionPresenter.Display> {
void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces);
void setNotifyAboutResults(boolean notifyAboutResults);
void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults);
void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces, AsyncCallback<VoidResult> callback);
void setNotifyAboutResults(boolean notifyAboutResults, AsyncCallback<VoidResult> callback);
void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults, Collection<BoatClassDTO> selection);
void persistResults(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults,
AsyncCallback<VoidResult> callback, Collection<BoatClassDTO> latestSelectedItems);
void setSelectionPersistenceCallback(AsyncCallback<VoidResult> selectionCallback);
interface Display extends SuggestedMultiSelectionPresenter.Display<BoatClassDTO> {
void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces);
void setNotifyAboutResults(boolean notifyAboutResults);
void initResults(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults, Collection<BoatClassDTO> selection);
boolean getNotifyAboutUpcomingRaces();
boolean getNotifyAboutResults();
Collection<BoatClassDTO> getSelection();
}
}
@@ -1,17 +1,24 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.preferences;
import java.util.Collection;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
import com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionPresenter;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
public interface CompetitorSelectionPresenter
extends SuggestedMultiSelectionPresenter<SimpleCompetitorWithIdDTO, CompetitorSelectionPresenter.Display> {
void persistResults(boolean notifyAboutResults, AsyncCallback<VoidResult> callback,
Collection<SimpleCompetitorWithIdDTO> latestSelectedItems);
public void initResults(boolean notifyAboutResults, Collection<SimpleCompetitorWithIdDTO> latestSelectedItems);
void setNotifyAboutResults(boolean notifyAboutResults);
void initNotifications(boolean notifyAboutResults);
public void setSelectionPersistenceCallback(AsyncCallback<VoidResult> selectionCallback);
public static interface Display extends SuggestedMultiSelectionPresenter.Display<SimpleCompetitorWithIdDTO> {
void initResults(boolean notifyAboutResults, Collection<SimpleCompetitorWithIdDTO> latestSelectedItems);
void setNotifyAboutResults(boolean notifyAboutResults);
public boolean getIsNotify();
}
}
@@ -0,0 +1,14 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.preferences;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.gwt.home.shared.partials.multiselection.MiscellaneousDisplayImpl;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
public interface MiscPreferencesPresenter {
void registerDisplay(MiscellaneousDisplayImpl display);
void updateIsSubscribedToFeatureAndCommunityUpdates(final boolean b, final AsyncCallback<VoidResult> callback);
/** get value via dispatch method, set first correct value onto checkbox */
void initIsSubscribedToFeatureAndCommunityUpdates(final boolean b);
}
@@ -6,14 +6,13 @@ import com.google.gwt.resources.client.CssResource;
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.HasValue;
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.shared.partials.multiselection.SuggestedMultiSelection;
import com.sap.sailing.gwt.home.shared.partials.labeledbox.LabeledBox;
import com.sap.sailing.gwt.home.shared.partials.multiselection.BoatClassDisplayImpl;
import com.sap.sailing.gwt.home.shared.partials.multiselection.CompetitorDisplayImpl;
import com.sap.sailing.gwt.home.shared.partials.multiselection.MiscellaneousDisplayImpl;
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
import com.sap.sailing.gwt.ui.client.StringMessages;
/**
* Implementation of {@link UserPreferencesView} where users can change their preferred selections and notifications.
@@ -24,84 +23,38 @@ public class UserPreferences extends Composite implements UserPreferencesView {
interface UserPreferencesUiBinder extends UiBinder<Widget, UserPreferences> {
}
interface Style extends CssResource {
String edgeToEdge();
}
@UiField Style style;
@UiField SharedResources res;
@UiField(provided = true) SuggestedMultiSelection<SimpleCompetitorWithIdDTO> favoriteCompetitorsSelctionUi;
@UiField(provided = true) SuggestedMultiSelection<BoatClassDTO> favoriteBoatClassesSelctionUi;
@UiField DivElement notificationsTextUi;
@UiField
Style style;
@UiField
SharedResources res;
@UiField(provided = true)
LabeledBox favoriteCompetitorsSelctionUi;
@UiField(provided = true)
LabeledBox favoriteBoatClassesSelctionUi;
@UiField(provided = true)
LabeledBox miscUi;
@UiField
DivElement notificationsTextUi;
final UserPreferencesView.Presenter presenter;
public UserPreferences(UserPreferencesView.Presenter presenter, FlagImageResolver flagImageResolver) {
favoriteCompetitorsSelctionUi = new CompetitorDisplayImpl(
presenter.getFavoriteCompetitorsDataProvider(), flagImageResolver).selectionUi;
this.presenter = presenter;
favoriteCompetitorsSelctionUi = new CompetitorDisplayImpl(presenter.getFavoriteCompetitorsDataProvider(),
flagImageResolver).selectionUi;
favoriteBoatClassesSelctionUi = new BoatClassDisplayImpl(
presenter.getFavoriteBoatClassesDataProvider()).selectionUi;
miscUi = (new MiscellaneousDisplayImpl(presenter.getMiscPresenter())).selectionUi;
initWidget(uiBinder.createAndBindUi(this));
// TODO hide notificationsTextUi if the user's mail address is already verified
}
public void setEdgeToEdge(boolean edgeToEdge) {
favoriteBoatClassesSelctionUi.setStyleName(style.edgeToEdge(), edgeToEdge);
favoriteCompetitorsSelctionUi.setStyleName(style.edgeToEdge(), edgeToEdge);
favoriteBoatClassesSelctionUi.getElement().getParentElement().removeClassName(res.mediaCss().column());
favoriteCompetitorsSelctionUi.getElement().getParentElement().removeClassName(res.mediaCss().column());
}
private class CompetitorDisplayImpl implements CompetitorSelectionPresenter.Display {
private final SuggestedMultiSelection<SimpleCompetitorWithIdDTO> selectionUi;
private final HasValue<Boolean> notifyAboutResultsUi;
private CompetitorDisplayImpl(final CompetitorSelectionPresenter dataProvider,
FlagImageResolver flagImageResolver) {
selectionUi = SuggestedMultiSelection.forCompetitors(dataProvider, StringMessages.INSTANCE.favoriteCompetitors(), flagImageResolver);
notifyAboutResultsUi = selectionUi.addNotificationToggle(dataProvider::setNotifyAboutResults,
StringMessages.INSTANCE.notificationAboutNewResults());
dataProvider.addDisplay(this);
}
@Override
public void setSelectedItems(Iterable<SimpleCompetitorWithIdDTO> selectedItems) {
selectionUi.setSelectedItems(selectedItems);
}
@Override
public void setNotifyAboutResults(boolean notifyAboutResults) {
notifyAboutResultsUi.setValue(notifyAboutResults);
}
}
private class BoatClassDisplayImpl implements BoatClassSelectionPresenter.Display {
private final SuggestedMultiSelection<BoatClassDTO> selectionUi;
private final HasValue<Boolean> notifyAboutUpcomingRacesUi;
private final HasValue<Boolean> notifyAboutResultsUi;
private BoatClassDisplayImpl(final BoatClassSelectionPresenter dataProvider) {
selectionUi = SuggestedMultiSelection.forBoatClasses(dataProvider, StringMessages.INSTANCE.favoriteBoatClasses());
notifyAboutUpcomingRacesUi = selectionUi.addNotificationToggle(dataProvider::setNotifyAboutUpcomingRaces,
StringMessages.INSTANCE.notificationAboutUpcomingRaces());
notifyAboutResultsUi = selectionUi.addNotificationToggle(dataProvider::setNotifyAboutResults,
StringMessages.INSTANCE.notificationAboutNewResults());
dataProvider.addDisplay(this);
}
@Override
public void setSelectedItems(Iterable<BoatClassDTO> selectedItems) {
selectionUi.setSelectedItems(selectedItems);
}
@Override
public void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces) {
notifyAboutUpcomingRacesUi.setValue(notifyAboutUpcomingRaces);
}
@Override
public void setNotifyAboutResults(boolean notifyAboutResults) {
notifyAboutResultsUi.setValue(notifyAboutResults);
}
}
}
@@ -1,7 +1,9 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator"
xmlns:ms="urn:import:com.sap.sailing.gwt.home.shared.partials.multiselection">
xmlns:ms="urn:import:com.sap.sailing.gwt.home.shared.partials.multiselection"
xmlns:cbt="urn:import:com.sap.sailing.gwt.home.shared.partials.checkboxtile"
xmlns:lb="urn:import:com.sap.sailing.gwt.home.shared.partials.labeledbox">
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:style type="com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserPreferences.Style">
@@ -16,10 +18,13 @@
<ui:text from="{i18n.userNotificationsOnlyIfMailAddressIsVerified}" />
</div>
<div class="{res.mediaCss.column} {res.mediaCss.small12} {res.mediaCss.medium6} {res.mainCss.spacermargintopmediumsmall}">
<ms:SuggestedMultiSelection ui:field="favoriteCompetitorsSelctionUi"/>
<lb:LabeledBox ui:field="miscUi"/>
</div>
<div class="{res.mediaCss.column} {res.mediaCss.small12} {res.mediaCss.medium6} {res.mainCss.spacermargintopmediumsmall}">
<ms:SuggestedMultiSelection ui:field="favoriteBoatClassesSelctionUi"/>
<lb:LabeledBox ui:field="favoriteCompetitorsSelctionUi"/>
</div>
<div class="{res.mediaCss.column} {res.mediaCss.small12} {res.mediaCss.medium6} {res.mainCss.spacermargintopmediumsmall}">
<lb:LabeledBox ui:field="favoriteBoatClassesSelctionUi"/>
</div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -11,9 +11,11 @@ import com.sap.sailing.gwt.home.communication.user.profile.FavoritesResult;
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.communication.user.profile.SaveMiscEmailPreferences;
import com.sap.sailing.gwt.home.shared.app.ClientFactoryWithDispatch;
import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggestedBoatClassMultiSelectionPresenter;
import com.sap.sailing.gwt.home.shared.partials.multiselection.AbstractSuggestedCompetitorMultiSelectionPresenter;
import com.sap.sailing.gwt.home.shared.partials.multiselection.MiscellaneousDisplayImpl;
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
import com.sap.sse.gwt.dispatch.shared.commands.VoidResult;
@@ -29,17 +31,18 @@ public class UserPreferencesPresenter<C extends ClientFactoryWithDispatch & Erro
implements UserPreferencesView.Presenter {
private final BoatClassSelectionPresenter boatClassSelectionPresenter = new BoatClassSelectionPresenterImpl();
private final CompetitorSelectionPresenter competitorSelectionPresenter;
final CompetitorSelectionPresenter competitorPresenter;
private final MiscPreferencesPresenter miscPresenter = new MiscPresenterImpl();
private final C clientFactory;
public UserPreferencesPresenter(C clientFactory) {
this.clientFactory = clientFactory;
this.competitorSelectionPresenter = new CompetitorSelectionPresenterImpl(clientFactory);
competitorPresenter = new CompetitorSelectionPresenterImpl(clientFactory);
}
@Override
public void loadPreferences() {
clientFactory.getDispatch().execute(new GetFavoritesAction(), new AsyncCallback<FavoritesResult>() {
final AsyncCallback<FavoritesResult> callback = new AsyncCallback<FavoritesResult>() {
@Override
public void onFailure(Throwable caught) {
clientFactory.createErrorView("Error while loading notification preferences!", caught);
@@ -47,109 +50,150 @@ public class UserPreferencesPresenter<C extends ClientFactoryWithDispatch & Erro
@Override
public void onSuccess(FavoritesResult result) {
initFavoriteCompetitors(result.getFavoriteCompetitors());
initFavoriteBoatClasses(result.getFavoriteBoatClasses());
final boolean isNotify = result.getFavoriteCompetitors().isNotifyAboutResults();
final Collection<SimpleCompetitorWithIdDTO> selection = result.getFavoriteCompetitors().getSelectedCompetitors();
competitorPresenter.initResults(isNotify, selection);
final FavoriteBoatClassesDTO favoriteBoatClasses = result.getFavoriteBoatClasses();
boatClassSelectionPresenter.initNotifications(favoriteBoatClasses.isNotifyAboutUpcomingRaces(),
favoriteBoatClasses.isNotifyAboutResults(), favoriteBoatClasses.getSelectedBoatClasses());
miscPresenter.initIsSubscribedToFeatureAndCommunityUpdates(result.getIsSubscribedToFeatureAndCommunityUpdates());
}
});
};
clientFactory.getDispatch().execute(new GetFavoritesAction(), callback);
}
@Override
public CompetitorSelectionPresenter getFavoriteCompetitorsDataProvider() {
return competitorSelectionPresenter;
public MiscPreferencesPresenter getMiscPresenter() {
return miscPresenter;
}
private class MiscPresenterImpl implements MiscPreferencesPresenter {
MiscellaneousDisplayImpl display;
@Override
public void registerDisplay(MiscellaneousDisplayImpl display) {
this.display = display;
}
@Override
public void initIsSubscribedToFeatureAndCommunityUpdates(final boolean b) {
if (display != null) {
display.setIsSubscribedToFeatureAndCommunityUpdates(b, false);
}
}
@Override
public void updateIsSubscribedToFeatureAndCommunityUpdates(final boolean b, final AsyncCallback<VoidResult> callback) {
clientFactory.getDispatch().execute(new SaveMiscEmailPreferences(b), callback);
}
}
@Override
public BoatClassSelectionPresenter getFavoriteBoatClassesDataProvider() {
return boatClassSelectionPresenter;
}
private void initFavoriteCompetitors(FavoriteCompetitorsDTO favoriteCompetitors) {
competitorSelectionPresenter.initNotifications(favoriteCompetitors.isNotifyAboutResults());
competitorSelectionPresenter.initSelectedItems(favoriteCompetitors.getSelectedCompetitors());
}
private void initFavoriteBoatClasses(FavoriteBoatClassesDTO favoriteBoatClasses) {
boatClassSelectionPresenter.initNotifications(favoriteBoatClasses.isNotifyAboutUpcomingRaces(),
favoriteBoatClasses.isNotifyAboutResults());
boatClassSelectionPresenter.initSelectedItems(favoriteBoatClasses.getSelectedBoatClasses());
}
private class BoatClassSelectionPresenterImpl
extends AbstractSuggestedBoatClassMultiSelectionPresenter<BoatClassSelectionPresenter.Display>
implements BoatClassSelectionPresenter {
private boolean notifyAboutUpcomingRaces;
private boolean notifyAboutResults;
private AsyncCallback<VoidResult> selectionCallback;
@Override
public void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults) {
this.notifyAboutUpcomingRaces = notifyAboutUpcomingRaces;
this.notifyAboutResults = notifyAboutResults;
public void initNotifications(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults, Collection<BoatClassDTO> selection) {
this.displays.forEach(display -> {
display.setNotifyAboutUpcomingRaces(notifyAboutUpcomingRaces);
display.setNotifyAboutResults(notifyAboutResults);
display.initResults(notifyAboutUpcomingRaces, notifyAboutResults, selection);
});
}
@Override
public void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces) {
this.notifyAboutUpcomingRaces = notifyAboutUpcomingRaces;
this.persist();
public void setNotifyAboutUpcomingRaces(boolean notifyAboutUpcomingRaces, AsyncCallback<VoidResult> callback) {
if (!this.displays.isEmpty()) {
final BoatClassSelectionPresenter.Display display = (BoatClassSelectionPresenter.Display) this.displays
.toArray()[0];
final Collection<BoatClassDTO> selectedItems = display.getSelection();
persistResults(notifyAboutUpcomingRaces, display.getNotifyAboutResults(), callback, selectedItems);
}
}
@Override
public void setNotifyAboutResults(boolean notifyAboutResults) {
this.notifyAboutResults = notifyAboutResults;
this.persist();
public void setNotifyAboutResults(boolean notifyAboutResults, AsyncCallback<VoidResult> callback) {
if (!this.displays.isEmpty()) {
final BoatClassSelectionPresenter.Display display = (BoatClassSelectionPresenter.Display) this.displays
.toArray()[0];
final Collection<BoatClassDTO> selectedItems = display.getSelection();
persistResults(display.getNotifyAboutUpcomingRaces(), notifyAboutResults, callback, selectedItems);
}
}
@Override
protected void persist(Collection<BoatClassDTO> selectedItem) {
final FavoriteBoatClassesDTO favorites = new FavoriteBoatClassesDTO(selectedItem, notifyAboutUpcomingRaces,
notifyAboutResults);
clientFactory.getDispatch().execute(new SaveFavoriteBoatClassesAction(favorites), new SaveAsyncCallback());
protected void persist(Collection<BoatClassDTO> selectedItems) {
if (!this.displays.isEmpty()) {
final BoatClassSelectionPresenter.Display display = (BoatClassSelectionPresenter.Display) this.displays
.toArray()[0];
if (selectionCallback != null) {
persistResults(display.getNotifyAboutUpcomingRaces(), display.getNotifyAboutResults(),
selectionCallback, selectedItems);
}
}
}
@Override
public void persistResults(boolean notifyAboutUpcomingRaces, boolean notifyAboutResults,
AsyncCallback<VoidResult> callback, Collection<BoatClassDTO> latestSelectedItems) {
final FavoriteBoatClassesDTO favorites = new FavoriteBoatClassesDTO(latestSelectedItems,
notifyAboutUpcomingRaces, notifyAboutResults);
clientFactory.getDispatch().execute(new SaveFavoriteBoatClassesAction(favorites), callback);
}
@Override
public void setSelectionPersistenceCallback(AsyncCallback<VoidResult> selectionCallback) {
this.selectionCallback = selectionCallback;
}
}
private class CompetitorSelectionPresenterImpl
extends AbstractSuggestedCompetitorMultiSelectionPresenter<CompetitorSelectionPresenter.Display>
implements CompetitorSelectionPresenter {
private boolean notifyAboutResults;
private AsyncCallback<VoidResult> selectionCallback;
private CompetitorSelectionPresenterImpl(ClientFactoryWithDispatch clientFactory) {
super(clientFactory);
}
@Override
public void initNotifications(boolean notifyAboutResults) {
this.notifyAboutResults = notifyAboutResults;
this.displays.forEach(display -> display.setNotifyAboutResults(notifyAboutResults));
protected final void persist(Collection<SimpleCompetitorWithIdDTO> selectedItems) {
if (!this.displays.isEmpty()) {
final CompetitorSelectionPresenter.Display display = (CompetitorSelectionPresenter.Display) this.displays
.toArray()[0];
if (selectionCallback != null) {
persistResults(display.getIsNotify(), selectionCallback, selectedItems);
}
}
}
@Override
public void setNotifyAboutResults(boolean notifyAboutResults) {
this.notifyAboutResults = notifyAboutResults;
this.persist();
public void persistResults(boolean notifyAboutResults, AsyncCallback<VoidResult> callback,
Collection<SimpleCompetitorWithIdDTO> latestSelectedItems) {
final FavoriteCompetitorsDTO favorites = new FavoriteCompetitorsDTO(latestSelectedItems,
notifyAboutResults);
clientFactory.getDispatch().execute(new SaveFavoriteCompetitorsAction(favorites), callback);
}
@Override
protected final void persist(Collection<SimpleCompetitorWithIdDTO> selectedItem) {
final FavoriteCompetitorsDTO favorites = new FavoriteCompetitorsDTO(selectedItem, notifyAboutResults);
clientFactory.getDispatch().execute(new SaveFavoriteCompetitorsAction(favorites), new SaveAsyncCallback());
public void initResults(boolean notifyAboutResults, Collection<SimpleCompetitorWithIdDTO> latestSelectedItems) {
this.displays.forEach(display -> display.initResults(notifyAboutResults, latestSelectedItems));
}
@Override
public void setSelectionPersistenceCallback(AsyncCallback<VoidResult> selectionCallback) {
this.selectionCallback = selectionCallback;
}
}
private class SaveAsyncCallback implements AsyncCallback<VoidResult> {
@Override
public void onFailure(Throwable caught) {
clientFactory.createErrorView("Error while saving notification preferences!", caught);
}
@Override
public void onSuccess(VoidResult result) {
}
@Override
public CompetitorSelectionPresenter getFavoriteCompetitorsDataProvider() {
return competitorPresenter;
}
}
@@ -29,6 +29,8 @@ public interface UserPreferencesView extends IsWidget {
BoatClassSelectionPresenter getFavoriteBoatClassesDataProvider();
CompetitorSelectionPresenter getFavoriteCompetitorsDataProvider();
MiscPreferencesPresenter getMiscPresenter();
}
}
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.dataprovider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
@@ -107,11 +108,16 @@ public class SailorProfilesCompetitorSelectionPresenter implements EditModeChang
}
@Override
public void initSelectedItems(Collection<SimpleCompetitorWithIdDTO> selectedItems) {
public void initSelectedItems(Iterable<SimpleCompetitorWithIdDTO> selectedItems) {
}
@Override
public String createSuggestionAdditionalDisplayString(SimpleCompetitorWithIdDTO value) {
return competitorDataProvider.createSuggestionAdditionalDisplayString(value);
}
@Override
public Collection<SimpleCompetitorWithIdDTO> getSelection() {
return new ArrayList<>(competitors);
}
}
@@ -110,8 +110,8 @@ public class ManagementConsoleClientFactoryImpl implements ManagementConsoleClie
private void changeDefaultTenantForCurrentUser(final StrippedUserGroupDTO serverTenant) {
final UserDTO user = getUserService().getCurrentUser();
getUserManagementWriteService().updateUserProperties(user.getName(), user.getFullName(),
user.getCompany(), user.getLocale(), serverTenant.getId().toString(),
new AsyncCallback<UserDTO>() {
user.getCompany(), user.getLocale(), user.getDidOptOutOfFeatureAndCommunityEmails(),
serverTenant.getId().toString(), new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
Window.alert(caught.getMessage());
@@ -191,7 +191,6 @@ public class EventListComposite extends Composite {
}
}
remove.setEnabled(!selectedEvents.isEmpty() && canDeleteAll);
}
});
buttonPanel.addUnsecuredWidget(new HelpButton(HelpButtonResources.INSTANCE,
@@ -21,25 +21,20 @@ import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.cellview.client.AbstractCellTable;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.Header;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.DefaultSelectionEventManager.SelectAction;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
@@ -69,10 +64,10 @@ import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
import com.sap.sse.gwt.client.celltable.BaseCelltable;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.FlushableCellTable;
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
import com.sap.sse.gwt.client.controls.BetterCheckboxCell;
import com.sap.sse.gwt.client.celltable.SelectionCheckboxColumn;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.gwt.client.panels.AbstractFilterablePanel;
import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
@@ -103,11 +98,12 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
private final ErrorReporter errorReporter;
private final StringMessages stringMessages;
private final UserService userService;
private CellTable<MediaTrackWithSecurityDTO> mediaTracksTable;
private FlushableCellTable<MediaTrackWithSecurityDTO> mediaTracksTable;
private ListDataProvider<MediaTrackWithSecurityDTO> mediaTrackListDataProvider = new ListDataProvider<>();
private Date latestDate;
private RefreshableMultiSelectionModel<MediaTrackWithSecurityDTO> refreshableSelectionModel;
private final FileStorageServiceConnectionTestObservable storageServiceAvailable;
private final SelectionCheckboxColumn<MediaTrackWithSecurityDTO> checkColumn;
public MediaPanel(Presenter presenter, StringMessages stringMessages) {
this.sailingServiceWrite = presenter.getSailingService();
@@ -117,6 +113,43 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
this.stringMessages = stringMessages;
this.errorReporter = presenter.getErrorReporter();
this.storageServiceAvailable = new FileStorageServiceConnectionTestObservable(presenter.getSailingService());
Label lblFilterRaces = new Label(stringMessages.filterMediaByName() + ":");
lblFilterRaces.setWordWrap(false);
this.filterableMediaTracks = new LabeledAbstractFilterablePanel<MediaTrackWithSecurityDTO>(lblFilterRaces,
allMediaTracks, mediaTrackListDataProvider, stringMessages) {
@Override
public List<String> getSearchableStrings(MediaTrackWithSecurityDTO t) {
List<String> strings = new ArrayList<String>();
strings.add(t.title);
strings.add(t.url);
if (t.startTime == null) {
GWT.log("startTime of media track " + t.title + " undefined");
} else {
strings.add(t.startTime.toString());
}
return strings;
}
@Override
public AbstractCellTable<MediaTrackWithSecurityDTO> getCellTable() {
return mediaTracksTable;
}
};
checkColumn = new SelectionCheckboxColumn<>(
tableResources.cellTableStyle().cellTableCheckboxSelected(),
tableResources.cellTableStyle().cellTableCheckboxDeselected(),
tableResources.cellTableStyle().cellTableCheckboxColumnCell(),
new EntityIdentityComparator<MediaTrackWithSecurityDTO>() {
@Override
public boolean representSameEntity(MediaTrackWithSecurityDTO dto1, MediaTrackWithSecurityDTO dto2) {
return dto1.dbId.equals(dto2.dbId);
}
@Override
public int hashCode(MediaTrackWithSecurityDTO t) {
return t.dbId.hashCode();
}
}, filterableMediaTracks.getAllListDataProvider());
refreshableSelectionModel = checkColumn.getSelectionModel();
AccessControlledButtonPanel buttonAndFilterPanel = new AccessControlledButtonPanel(userService,
SecuredDomainType.MEDIA_TRACK);
add(buttonAndFilterPanel);
@@ -144,12 +177,12 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
}).center();
}
});
Button multiURLChange = buttonAndFilterPanel.addUnsecuredAction(stringMessages.multiUrlChangeMediaTrack(),
final Button multiUrlChange = buttonAndFilterPanel.addUpdateAction(stringMessages.multiUrlChangeMediaTrack(),
refreshableSelectionModel,
new Command() {
@Override
public void execute() {
Set<MediaTrackWithSecurityDTO> selected = refreshableSelectionModel.getSelectedSet();
final Set<MediaTrackWithSecurityDTO> selected = refreshableSelectionModel.getSelectedSet();
if (selected.isEmpty()) {
Notification.notify(stringMessages.noSelection(), NotificationType.ERROR);
} else {
@@ -162,48 +195,39 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
}
}
});
multiURLChange.setEnabled(false);
Label lblFilterRaces = new Label(stringMessages.filterMediaByName() + ":");
lblFilterRaces.setWordWrap(false);
buttonAndFilterPanel.addUnsecuredWidget(lblFilterRaces);
this.filterableMediaTracks = new LabeledAbstractFilterablePanel<MediaTrackWithSecurityDTO>(lblFilterRaces,
allMediaTracks, mediaTrackListDataProvider, stringMessages) {
final Button remove = buttonAndFilterPanel.addRemoveAction(stringMessages.remove(), refreshableSelectionModel,
/* with confirmation */ true, new Command() {
@Override
public List<String> getSearchableStrings(MediaTrackWithSecurityDTO t) {
List<String> strings = new ArrayList<String>();
strings.add(t.title);
strings.add(t.url);
if (t.startTime == null) {
GWT.log("startTime of media track " + t.title + " undefined");
} else {
strings.add(t.startTime.toString());
public void execute() {
for (final MediaTrackWithSecurityDTO track : refreshableSelectionModel.getSelectedSet()) {
removeMediaTrack(track);
}
return strings;
}
});
refreshableSelectionModel.addSelectionChangeHandler(new Handler() {
@Override
public AbstractCellTable<MediaTrackWithSecurityDTO> getCellTable() {
return mediaTracksTable;
public void onSelectionChange(final SelectionChangeEvent event) {
final Set<MediaTrackWithSecurityDTO> selected = refreshableSelectionModel.getSelectedSet();
boolean canDeleteAllSelected = true;
boolean canUpdateAllSelected = true;
for (final MediaTrackWithSecurityDTO track : selected) {
if (!userService.hasPermission(track, DefaultActions.DELETE)) {
canDeleteAllSelected = false;
}
if (!userService.hasPermission(track, DefaultActions.UPDATE)) {
canUpdateAllSelected = false;
}
}
remove.setEnabled(!selected.isEmpty() && canDeleteAllSelected);
multiUrlChange.setEnabled(!selected.isEmpty() && canUpdateAllSelected);
}
};
});
buttonAndFilterPanel.addUnsecuredWidget(lblFilterRaces);
createMediaTracksTable(userService);
filterableMediaTracks.getTextBox().ensureDebugId("MediaTracksFilterTextBox");
filterableMediaTracks
.setUpdatePermissionFilterForCheckbox(mediaTrack -> userService.hasPermission(mediaTrack, DefaultActions.UPDATE));
buttonAndFilterPanel.addUnsecuredWidget(filterableMediaTracks);
refreshableSelectionModel.addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
boolean canUpdateAll = true;
for (MediaTrackWithSecurityDTO track : refreshableSelectionModel.getSelectedSet()) {
if (!userService.hasPermission(track, DefaultActions.UPDATE)) {
canUpdateAll = false;
}
}
multiURLChange.setEnabled(!refreshableSelectionModel.getSelectedSet().isEmpty() && canUpdateAll);
}
});
}
private final Displayer<MediaTrackWithSecurityDTO> mediaTracksDisplayer = new Displayer<MediaTrackWithSecurityDTO>() {
@@ -226,58 +250,10 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
}
private void createMediaTracksTable(final UserService userService) {
// Create a CellTable.
// Set a key provider that provides a unique key for each contact. If key is
// used to identify contacts when fields (such as the name and address)
// change.
mediaTracksTable = new BaseCelltable<>(1000, tableResources);
mediaTracksTable = new FlushableCellTable<>(1000, tableResources);
mediaTracksTable.setWidth("100%");
// Attach a column sort handler to the ListDataProvider to sort the list.
ListHandler<MediaTrackWithSecurityDTO> sortHandler = new ListHandler<>(mediaTrackListDataProvider.getList());
final ListHandler<MediaTrackWithSecurityDTO> sortHandler = new ListHandler<>(mediaTrackListDataProvider.getList());
mediaTracksTable.addColumnSortHandler(sortHandler);
// Add a selection model so we can select cells.
refreshableSelectionModel = new RefreshableMultiSelectionModel<>(
new EntityIdentityComparator<MediaTrackWithSecurityDTO>() {
@Override
public boolean representSameEntity(MediaTrackWithSecurityDTO dto1, MediaTrackWithSecurityDTO dto2) {
return dto1.dbId.equals(dto2.dbId);
}
@Override
public int hashCode(MediaTrackWithSecurityDTO t) {
return t.dbId.hashCode();
}
}, filterableMediaTracks.getAllListDataProvider());
mediaTracksTable.setSelectionModel(refreshableSelectionModel,
DefaultSelectionEventManager.createCustomManager(
new DefaultSelectionEventManager.CheckboxEventTranslator<MediaTrackWithSecurityDTO>() {
@Override
public boolean clearCurrentSelection(CellPreviewEvent<MediaTrackWithSecurityDTO> event) {
return !isCheckboxColumn(event.getColumn());
}
@Override
public SelectAction translateSelectionEvent(
CellPreviewEvent<MediaTrackWithSecurityDTO> event) {
NativeEvent nativeEvent = event.getNativeEvent();
if (BrowserEvents.CLICK.equals(nativeEvent.getType())) {
if (nativeEvent.getCtrlKey()) {
MediaTrackWithSecurityDTO value = event.getValue();
refreshableSelectionModel.setSelected(value, !refreshableSelectionModel.isSelected(value));
return SelectAction.IGNORE;
}
if (!refreshableSelectionModel.getSelectedSet().isEmpty() && !isCheckboxColumn(event.getColumn())) {
return SelectAction.DEFAULT;
}
}
return SelectAction.TOGGLE;
}
private boolean isCheckboxColumn(int columnIndex) {
return columnIndex == 0;
}
}));
// Initialize the columns.
initTableColumns(sortHandler, userService);
mediaTrackListDataProvider.addDataDisplay(mediaTracksTable);
add(mediaTracksTable);
@@ -290,17 +266,10 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
*/
private void initTableColumns(final ListHandler<MediaTrackWithSecurityDTO> sortHandler,
final UserService userService) {
Column<MediaTrackWithSecurityDTO, Boolean> checkColumn = new Column<MediaTrackWithSecurityDTO, Boolean>(
new BetterCheckboxCell(tableResources.cellTableStyle().cellTableCheckboxSelected(),
tableResources.cellTableStyle().cellTableCheckboxDeselected())) {
@Override
public Boolean getValue(MediaTrackWithSecurityDTO object) {
// Get the value from the selection model.
return refreshableSelectionModel.isSelected(object);
}
};
mediaTracksTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant("<br/>"));
final Header<Boolean> selectAllHeader = checkColumn.createHeader();
mediaTracksTable.addColumn(checkColumn, selectAllHeader);
mediaTracksTable.setColumnWidth(checkColumn, 40, Unit.PX);
mediaTracksTable.setSelectionModel(refreshableSelectionModel, checkColumn.getSelectionManager());
// db id
Column<MediaTrackWithSecurityDTO, String> dbIdColumn = new Column<MediaTrackWithSecurityDTO, String>(
new TextCell()) {
@@ -715,4 +684,4 @@ public class MediaPanel extends FlowPanel implements FilterablePanelProvider<Med
public AbstractFilterablePanel<MediaTrackWithSecurityDTO> getFilterablePanel() {
return filterableMediaTracks;
}
}
}
@@ -3,10 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import static com.sap.sse.security.ui.client.component.DefaultActionsImagesBarCell.ACTION_DELETE;
import static com.sap.sse.security.ui.client.component.DefaultActionsImagesBarCell.ACTION_UPDATE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -15,9 +12,7 @@ import com.google.gwt.cell.client.SafeHtmlCell;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.AbstractCellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
@@ -27,7 +22,6 @@ import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.sap.sailing.gwt.ui.adminconsole.places.AdminConsoleView.Presenter;
import com.sap.sailing.gwt.ui.client.SailingServiceWriteAsync;
@@ -40,10 +34,8 @@ import com.sap.sse.gwt.client.IconResources;
import com.sap.sse.gwt.client.Notification;
import com.sap.sse.gwt.client.Notification.NotificationType;
import com.sap.sse.gwt.client.celltable.CellTableWithCheckboxResources;
import com.sap.sse.gwt.client.celltable.FlushableCellTable;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.gwt.client.panels.AbstractFilterablePanel;
import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes.ServerActions;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.client.component.DefaultActionsImagesBarCell;
@@ -54,10 +46,8 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel implements
private final UserService userService;
private final ErrorReporter errorReporter;
private final StringMessages stringMessages;
private FlushableCellTable<RemoteSailingServerReferenceDTO> remoteServersTable;
private final ListDataProvider<RemoteSailingServerReferenceDTO> serverDataProvider;
private RemoteServerInstancesManagementTableWrapper remoteServersTable;
private MultiSelectionModel<RemoteSailingServerReferenceDTO> refreshableServerSelectionModel;
private LabeledAbstractFilterablePanel<RemoteSailingServerReferenceDTO> filteredServerTablePanel;
private final CaptionPanel remoteServersPanel;
public RemoteServerInstancesManagementPanel(final Presenter presenter, StringMessages stringMessages, CellTableWithCheckboxResources tableResources) {
@@ -72,40 +62,12 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel implements
mainPanel.add(remoteServersPanel);
VerticalPanel remoteServersContentPanel = new VerticalPanel();
remoteServersPanel.setContentWidget(remoteServersContentPanel);
serverDataProvider = new ListDataProvider<>();
filteredServerTablePanel = createFilteredServerTablePanel();
remoteServersTable = createRemoteServersTable(tableResources);
serverDataProvider.addDataDisplay(remoteServersTable);
remoteServersContentPanel.add(filteredServerTablePanel);
remoteServersContentPanel.add(remoteServersTable);
remoteServersContentPanel.add(createButtonToolbar());
refreshSailingServerList();
}
private LabeledAbstractFilterablePanel<RemoteSailingServerReferenceDTO> createFilteredServerTablePanel() {
return new LabeledAbstractFilterablePanel<RemoteSailingServerReferenceDTO>(
new Label(stringMessages.filterBy() + ":"), Collections.<RemoteSailingServerReferenceDTO> emptyList(),
serverDataProvider, stringMessages) {
@Override
public List<String> getSearchableStrings(RemoteSailingServerReferenceDTO t) {
List<String> strings = new ArrayList<String>();
strings.add(t.getName());
strings.add(t.getUrl());
if (t.getEvents() != null) {
for (EventBaseDTO e : t.getEvents()) {
strings.add(e.getName());
}
}
return strings;
}
@Override
public AbstractCellTable<RemoteSailingServerReferenceDTO> getCellTable() {
return remoteServersTable;
}
};
}
private Panel createButtonToolbar() {
HorizontalPanel buttonPanel = new HorizontalPanel();
buttonPanel.setSpacing(5);
@@ -121,27 +83,17 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel implements
(ClickHandler) event -> removeSelectedSailingServers());
}
private FlushableCellTable<RemoteSailingServerReferenceDTO> createRemoteServersTable(
private RemoteServerInstancesManagementTableWrapper createRemoteServersTable(
CellTableWithCheckboxResources tableResources) {
RemoteServerInstancesManagementTableWrapper wrapper = new RemoteServerInstancesManagementTableWrapper(
stringMessages, errorReporter, filteredServerTablePanel.getAllListDataProvider(), tableResources);
wrapper.addColumn(createTextColumn(RemoteSailingServerReferenceDTO::getName), stringMessages.name());
wrapper.addColumn(createTextColumn(RemoteSailingServerReferenceDTO::getUrl), stringMessages.url());
stringMessages, errorReporter, tableResources);
wrapper.addColumn(RemoteSailingServerReferenceDTO::getName, stringMessages.name());
wrapper.addColumn(RemoteSailingServerReferenceDTO::getUrl, stringMessages.url());
wrapper.addColumn(createEventsColumn(), stringMessages.events());
wrapper.addColumn(createActionsColumn(), stringMessages.actions());
wrapper.setEmptyTableWidget(new Label(stringMessages.noSailingServerInstancesYet()));
refreshableServerSelectionModel = wrapper.getSelectionModel();
return wrapper.getTable();
}
private TextColumn<RemoteSailingServerReferenceDTO> createTextColumn(
Function<RemoteSailingServerReferenceDTO, String> getter) {
return new TextColumn<RemoteSailingServerReferenceDTO>() {
@Override
public String getValue(RemoteSailingServerReferenceDTO server) {
return getter.apply(server) != null ? getter.apply(server) : "";
}
};
return wrapper;
}
private Column<RemoteSailingServerReferenceDTO, SafeHtml> createEventsColumn() {
@@ -224,7 +176,7 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel implements
private void refreshSailingServerList() {
sailingService.getRemoteSailingServerReferences(createCallback(stringMessages::errorRefreshingSailingServers,
filteredServerTablePanel::updateAll, false));
remoteServersTable.getFilterPanel()::updateAll, false));
}
private void removeSelectedSailingServers() {
@@ -241,7 +193,7 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel implements
}
private void addRemoteSailingServerReference() {
new SailingServerCreateOrEditDialog(filteredServerTablePanel.getAll(), stringMessages,
new SailingServerCreateOrEditDialog(remoteServersTable.getFilterPanel().getAll(), stringMessages,
new DialogCallback<RemoteSailingServerReferenceDTO>() {
@Override
public void cancel() {
@@ -249,8 +201,9 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel implements
@Override
public void ok(final RemoteSailingServerReferenceDTO server) {
sailingService.addRemoteSailingServerReference(server, createCallback(
stringMessages::errorAddingSailingServer, filteredServerTablePanel::add, true));
sailingService.addRemoteSailingServerReference(server,
createCallback(stringMessages::errorAddingSailingServer,
remoteServersTable.getFilterPanel()::add, true));
}
}).show();
}
@@ -275,6 +228,6 @@ public class RemoteServerInstancesManagementPanel extends SimplePanel implements
@Override
public AbstractFilterablePanel<RemoteSailingServerReferenceDTO> getFilterablePanel() {
return filteredServerTablePanel;
return remoteServersTable.getFilterPanel();
}
}
@@ -1,20 +1,23 @@
package com.sap.sailing.gwt.ui.adminconsole;
import com.google.gwt.view.client.ListDataProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import com.sap.sailing.gwt.ui.shared.EventBaseDTO;
import com.sap.sailing.gwt.ui.shared.RemoteSailingServerReferenceDTO;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.celltable.CellTableWithCheckboxResources;
import com.sap.sse.gwt.client.celltable.EntityIdentityComparator;
import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel;
import com.sap.sse.gwt.client.celltable.TableWrapper;
import com.sap.sse.gwt.client.celltable.TableWrapperWithMultiSelectionAndFilter;
import com.sap.sse.security.ui.client.i18n.StringMessages;
public class RemoteServerInstancesManagementTableWrapper extends
TableWrapper<RemoteSailingServerReferenceDTO, RefreshableMultiSelectionModel<RemoteSailingServerReferenceDTO>, StringMessages, CellTableWithCheckboxResources> {
TableWrapperWithMultiSelectionAndFilter<RemoteSailingServerReferenceDTO, StringMessages, CellTableWithCheckboxResources> {
public RemoteServerInstancesManagementTableWrapper(StringMessages stringMessages, ErrorReporter errorReporter,
ListDataProvider<RemoteSailingServerReferenceDTO> dataProvider, CellTableWithCheckboxResources tableResources) {
super(stringMessages, errorReporter, /* multiSelection */ true, /* pager */ true,
new EntityIdentityComparator<RemoteSailingServerReferenceDTO>() {
CellTableWithCheckboxResources tableResources) {
super(stringMessages, errorReporter, /* enablePager */ true,
Optional.of(new EntityIdentityComparator<RemoteSailingServerReferenceDTO>() {
@Override
public boolean representSameEntity(RemoteSailingServerReferenceDTO dto1,
RemoteSailingServerReferenceDTO dto2) {
@@ -25,7 +28,21 @@ public class RemoteServerInstancesManagementTableWrapper extends
public int hashCode(RemoteSailingServerReferenceDTO t) {
return t.getUrl().hashCode();
}
}, tableResources);
registerSelectionModelOnNewDataProvider(dataProvider);
}), tableResources, /* updatePermissionFilterForCheckbox */ Optional.empty(),
/* use default filter-by text */ Optional.empty(),
/* filterCheckboxLabel */ null);
}
@Override
public List<String> getSearchableStrings(RemoteSailingServerReferenceDTO t) {
List<String> strings = new ArrayList<String>();
strings.add(t.getName());
strings.add(t.getUrl());
if (t.getEvents() != null) {
for (EventBaseDTO e : t.getEvents()) {
strings.add(e.getName());
}
}
return strings;
}
}
@@ -311,8 +311,8 @@ public class AdminConsoleActivity extends AbstractActivity implements AdminConso
private void changeDefaultTenantForCurrentUser(final StrippedUserGroupDTO serverTenant) {
final UserDTO user = clientFactory.getUserService().getCurrentUser();
clientFactory.getUserManagementWriteService().updateUserProperties(user.getName(), user.getFullName(),
user.getCompany(), user.getLocale(), serverTenant.getId().toString(),
new AsyncCallback<UserDTO>() {
user.getCompany(), user.getLocale(), user.getDidOptOutOfFeatureAndCommunityEmails(),
serverTenant.getId().toString(), new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
Window.alert(caught.getMessage());
@@ -2556,6 +2556,25 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String ipsLockedForUserCreationAbuse();
String unableToLoadIpsBlockedForUserCreationAbuse();
String sourceCode();
String miscellaneous();
String securityUpdates();
String featureAndCommunityUpdates();
String youWillNowReceiveFeatureAndCommunityUpdates();
String youWillNotReceiveFeatureAndCommunityUpdatesAnymore();
String failedToSetStatusOfFeatureAndCommunityUpdates();
String youWillNowReceiveNotificationsForFavoriteCompetitors();
String youWillNotReceiveNotificationsForFavoriteCompetitorsAnymore();
String failedToSetStatusOfNotificationsForFavoriteCompetitors();
String youWillNowReceiveNotificationsForFavoriteBoatClassUpcomingRaces();
String youWillNotReceiveUpdatesOnUpcomingRacesForYourFavoredBoatClassesAnymore();
String failedToSetStatusOfUpdatesOnUpcomingRacesForYourFavoredBoatClasses();
String youWillNowReceiveUpdatesOnNewResultsForYourFavoredBoatClasses();
String youWillNotReceiveNotificationsForFavoriteBoatClassNewResultsAnymore();
String failedToSetStatusOfUpdatesOnNewResultsForYourFavoredBoatClasses();
String failedToModifyFavoriteCompetitors();
String favoriteCompetitorsModifiedSuccessfully();
String failedToModifyFavoredBoatClasses();
String succesfullyModifiedFavoredBoatClasses();
String revokeExplicitTrackingTimes();
String confirmRevokeExplicitTrackingTimes(String leaderboardName);
String errorRevokingExplicitTrackingTimes(String leaderboardName, String message);
@@ -580,7 +580,7 @@ factor=Factor
errorUpdatingIsMedalRace=Error updating the medal race setting: {0}
maneuverLoss=Maneuver loss
averageManeuverLossInMeters=\u2205 Maneuver Loss
averageManeuverLossInMetersTooltip=The average distance loss during any mneuver.
averageManeuverLossInMetersTooltip=The average distance loss during any maneuver.
averageTackLossInMeters=\u2205 Tack Loss
averageTackLossInMetersTooltip=The average distance loss during tacks.
averageJibeLossInMeters=\u2205 Jibe Loss
@@ -637,7 +637,7 @@ polarSheetRemoveOutliersTooltip=Outliers are removed by a distance based approac
polarSheetOutlierDetectionRadius=Outlier detection neighborhood radius
polarSheetOutlierDetectionRadiusTooltip=The radius used in the distance based outlier\ndetection algorithm.
polarSheetOutlierDetectionMinimumPerc=Minimum outlier detection neighborhood percentage
polarSheetOutlierDetectionMinimumPercTooltip=The percentage of neightborhood datapoints / overall datapoints\nneeds to be at less than the given value for the point to be considered an outlier.
polarSheetOutlierDetectionMinimumPercTooltip=The percentage of neighborhood datapoints / overall datapoints\nneeds to be at less than the given value for the point to be considered an outlier.
polarSheetNumberOfHistogramColumns=Number of histogram columns per wind range
polarSheetWindSteppingInKnots=Wind stepping in knots
polarSheetWindSteppingMaxDistance=Max. distance to wind level
@@ -1021,7 +1021,7 @@ addIgtimiUser=Add Igtimi User
errorTryingToRemoveIgtimiDevice=Error trying to remove Igtimi device {0}: {1}
successfullyRemoveIgtimiDevice=Igtimi device {0} removed successfully
errorCreatingDataAccessWindow=Error creating data access window for Igtimi device {0}: {1}
successfullyCreatedIgtimiDataAccessWindow=Data access window for Igtimi devic {0} created successfully
successfullyCreatedIgtimiDataAccessWindow=Data access window for Igtimi device {0} created successfully
errorFetchingIgtimiDataAccessWindows=Error fetching Igtimi data access windows: {0}
doYouReallyWantToRemoveTheSelectedIgtimiDataAccessWindows=Do you really want to remove the selected Igtimi data access windows?
igtimiDataAccessWindows=Igtimi Data Access Windows
@@ -1525,7 +1525,7 @@ showOnlyCompetitorsOfLog=Show only competitors registered in Log
showOnlyBoatsOfLog=Show only boats registered in Log
confirmLosingCompetitorEditsWhenTogglingLogBasedView=This will reset your current, unsaved changes to the competitors.\nDo you really want to continue?
confirmLosingBoatEditsWhenTogglingLogBasedView=This will reset your current, unsaved changes to the boats.\nDo you really want to continue?
removalOfMarkDisabledMayBeUsedInRaces=Removal deavticated, marks are used in races {0}
removalOfMarkDisabledMayBeUsedInRaces=Removal deactivated, marks are used in races {0}
createDefaultLeaderboardGroup=Would you like to create a default LeaderboardGroup for your event?
pleaseCreateAtLeastOneMappingBy=Please create at least one mapping by first selecting a track on the left hand side and then selecting a mark, boat or competitor on the right hand side
matcherType=Matcher type
@@ -2464,8 +2464,8 @@ errorLoadingPolarDataForBoatClass=Error loading polar data for boat class {0}: {
videoGuide=Video guide
orcExplanation=ORC explanation
confirmNonRenewingSubscriptionTitle=Stop auto-renewal
confirmNonRenewingSubscriptionText=Do you really want to stop the auto-renewal of your subscription?\n You will loose your aquired premium privileges at the end of the current term.
subscriptionOneTimePlanLockedText=This plan may only be aquired once.
confirmNonRenewingSubscriptionText=Do you really want to stop the auto-renewal of your subscription?\n You will loose your acquired premium privileges at the end of the current term.
subscriptionOneTimePlanLockedText=This plan may only be acquired once.
errorSettingRaceToDefineItsOwnCompetitors=Error setting race for fleet {2} in column {1} of leaderboard {0} to define its own competitors: {3}
twdInDegrees=TWD (from) in degrees
legDirectionInDegrees=Leg direction in degrees
@@ -2578,7 +2578,7 @@ selectRaceColumnsWhosePairingsToCopy=Race columns whose pairings to copy
errorCopyingPairings=Error copying pairings: {0}
successfullyCopiedPairings=Successfully copied pairings
selectFromRaceColumn=Select race column from where to start copying pairings
selectToRaceColumn=Select race colunm to where to copy pairings
selectToRaceColumn=Select race column to where to copy pairings
exportTWAHistogramToCsv=Export True Wind Angle histogram to CSV
exportWindSpeedHistogramToCsv=Export Wind Speed histogram to CSV
optionalBearerTokenForWindImport=Optional bearer token for wind import
@@ -2592,6 +2592,25 @@ unlock=Unlock
ipsLockedForUserCreationAbuse=IPs Locked for User Creation Abuse
unableToLoadIpsBlockedForUserCreationAbuse=Unable to load IPs Blocked for User Creation Abuse
sourceCode=Source Code
miscellaneous=Miscellaneous
securityUpdates=Security Updates
featureAndCommunityUpdates=Feature and Community Updates
youWillNowReceiveFeatureAndCommunityUpdates=You will now receive feature and community updates
youWillNotReceiveFeatureAndCommunityUpdatesAnymore=You will not receive feature and community updates anymore
failedToSetStatusOfFeatureAndCommunityUpdates=Failed to set status of feature and community updates
failedToSetStatusOfNotificationsForFavoriteCompetitors=Failed to set status of notifications for favorite competitors
youWillNowReceiveNotificationsForFavoriteCompetitors=You will now receive notifications for favorite competitors
failedToSetStatusOfUpdatesOnUpcomingRacesForYourFavoredBoatClasses=Failed to set status of notifications for upcoming races of your favored boat classes
youWillNowReceiveNotificationsForFavoriteBoatClassUpcomingRaces=You will now receive notifications for upcoming races of your favored boat classes
youWillNotReceiveUpdatesOnUpcomingRacesForYourFavoredBoatClassesAnymore=You will not receive notifications for upcoming races of your favored boat classes anymore
failedToSetStatusOfUpdatesOnNewResultsForYourFavoredBoatClasses=Failed to set status of notifications for new results of your favored boat classes
youWillNowReceiveUpdatesOnNewResultsForYourFavoredBoatClasses=You will now receive notifications for new results of your favored boat classes
youWillNotReceiveNotificationsForFavoriteBoatClassNewResultsAnymore=You will not receive notifications for new results of your favored boat classes anymore
failedToModifyFavoriteCompetitors=Failed to modify favorite competitors
favoriteCompetitorsModifiedSuccessfully=Favorite competitors modified successfully
failedToModifyFavoredBoatClasses=Failed to modify favorite boat classes
succesfullyModifiedFavoredBoatClasses=Successfully modified favored boat classes
youWillNotReceiveNotificationsForFavoriteCompetitorsAnymore=You will not receive notifications for favorite competitors anymore
revokeExplicitTrackingTimes=Revoke explicit tracking times for races with valid start and finishing times
confirmRevokeExplicitTrackingTimes=Really revoke explicit tracking times for all races of leaderboard {0} that have valid start and finishing times?
errorRevokingExplicitTrackingTimes=Error revoking explicit tracking times for leaderboard {0}: {1}
@@ -2586,6 +2586,25 @@ unlock=Entsperren
ipsLockedForUserCreationAbuse=Wegen Missbrauchs bei der Benutzererstellung gesperrte IPs
unableToLoadIpsBlockedForUserCreationAbuse=Wegen Missbrauchs der Benutzererstellung blockierte IPs können nicht geladen werden
sourceCode=Quellcode
miscellaneous=Verschiedenes
securityUpdates=Sicherheitsupdates
featureAndCommunityUpdates=Funktions- und Community-Updates
youWillNowReceiveFeatureAndCommunityUpdates=Sie erhalten nun Funktions- und Community-Updates.
youWillNotReceiveFeatureAndCommunityUpdatesAnymore=Sie erhalten keine Funktions- und Community-Updates mehr.
failedToSetStatusOfFeatureAndCommunityUpdates=Fehler beim Festlegen des Status von Funktions- und Community-Updates
failedToSetStatusOfNotificationsForFavoriteCompetitors=Status der Benachrichtigungen für bevorzugte Teilnehmer konnte nicht festgelegt werden.
youWillNowReceiveNotificationsForFavoriteCompetitors=Sie erhalten nun Benachrichtigungen für Ihre bevorzugten Teilnehmer.
youWillNotReceiveNotificationsForFavoriteCompetitorsAnymore=Sie erhalten keine Benachrichtigungen mehr für Ihre Lieblingskonkurrenten.
failedToSetStatusOfUpdatesOnUpcomingRacesForYourFavoredBoatClasses=Fehler beim Festlegen des Benachrichtigungsstatus für bevorstehende Rennen Ihrer bevorzugten Bootsklasse
youWillNowReceiveNotificationsForFavoriteBoatClassUpcomingRaces=Sie erhalten nun Benachrichtigungen für anstehende Rennen Ihrer bevorzugten Bootsklasse.
youWillNotReceiveUpdatesOnUpcomingRacesForYourFavoredBoatClassesAnymore=Sie erhalten keine Benachrichtigungen mehr für bevorstehende Rennen Ihrer bevorzugten Bootsklasse.
failedToSetStatusOfUpdatesOnNewResultsForYourFavoredBoatClasses=Fehler beim Festlegen des Benachrichtigungsstatus für neue Ergebnisse Ihrer bevorzugten Bootsklasse
youWillNowReceiveUpdatesOnNewResultsForYourFavoredBoatClasses=Sie erhalten nun Benachrichtigungen über neue Ergebnisse Ihrer bevorzugten Bootsklasse.
youWillNotReceiveNotificationsForFavoriteBoatClassNewResultsAnymore=Sie erhalten keine Benachrichtigungen mehr über neue Ergebnisse Ihrer bevorzugten Bootsklasse.
failedToModifyFavoriteCompetitors=Fehler beim Setzen der Teilnemer-Favoriten
favoriteCompetitorsModifiedSuccessfully=Teilnehmer-Favoriten erfolgreich aktualisiert
failedToModifyFavoredBoatClasses=Die bevorzugten Bootsklassen konnten nicht angepasst werden.
succesfullyModifiedFavoredBoatClasses=Die bevorzugten Bootsklassen wurden erfolgreich angepasst.
revokeExplicitTrackingTimes=Explizite Tracking-Zeiten zurücksetzen für Rennen mit gültigen Start- und Endzeitpunkten
confirmRevokeExplicitTrackingTimes=Wirklich explizite Tracking-Zeiten zurücksetzen für Rennen mit gültigen Start- und Endzeitpunkten der Rangliste {0}?
errorRevokingExplicitTrackingTimes=Fehler beim Zurücksetzen expliziter Tracking-Zeiten für Rennen mit gültigen Start- und Endzeitpunkten der Rangliste {0}: {1}
@@ -2595,4 +2614,4 @@ notRevokedTrackingTimesBecauseNotForTracking=Nicht widerrufene explizite Trackin
notRevokedTrackingTimesBecauseOfMissingStartOrFinishTime=Nicht widerrufene explizite Tracking-Zeiten für Rennen mit ungültigen Start- oder Endzeitpunkten:
noRegattaLeaderboard=Rangliste {0} ist keine Regatta-Rangliste.
noAutomatedTrackingTimes=Rangliste {0} nutzt keine automatisierten Tracking-Zeiten, auf die zurückgesetzt werden könnte.
unknownError=Unbekannter Fehler: {0}
unknownError=Unbekannter Fehler: {0}
@@ -2815,8 +2815,8 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
private void adjustColumnLayout(LeaderboardDTO leaderboard) {
int columnIndex = 0;
columnIndex = ensureRaceRankColumn(columnIndex);
columnIndex = ensureSelectionCheckboxColumn(columnIndex);
columnIndex = ensureRaceRankColumn(columnIndex);
columnIndex = ensureRankColumn(columnIndex);
columnIndex = ensureCompetitorInfoWithFlagColumnAndCompetitorColumn(columnIndex);
columnIndex = updateCarryColumn(leaderboard, columnIndex);
@@ -2833,7 +2833,7 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
// Single leaderboard hook
protected int ensureRaceRankColumn(int columnIndex) {
return 0;
return columnIndex;
}
/**
@@ -92,7 +92,7 @@ public class SingleRaceLeaderboardPanel extends LeaderboardPanel<SingleRaceLeade
@Override
protected int ensureRaceRankColumn(int rankColumnIndex) {
boolean required = isShowRaceRankColumn() && preSelectedRace != null;
final int indexOfNextColumn = required ? 1 : 0;
final int indexOfNextColumn = rankColumnIndex + (required ? 1 : 0);
if (getLeaderboardTable().getColumnCount() > rankColumnIndex) {
if (required) {
if (getLeaderboardTable().getColumn(rankColumnIndex) != getRaceRankColumn()) {
@@ -329,8 +329,10 @@ public class SingleRaceLeaderboardPanel extends LeaderboardPanel<SingleRaceLeade
@Override
public void updateSettings(SingleRaceLeaderboardSettings newSettings) {
super.updateSettings(newSettings);
// Note: it's important to update showRaceRankColumn *before* calling super.updateSettings(newSettings)
// because the base class implementation then also ensures all columns are displayed according to settings
showRaceRankColumn = newSettings.isShowRaceRankColumn();
super.updateSettings(newSettings);
}
@Override
@@ -169,7 +169,7 @@ public class ArchiveCandidateMonitoringBackgroundTask implements Runnable {
} else {
rescheduleCurrentCheckAfterFailureOrTimeout();
}
} catch (Exception e) {
} catch (Throwable e) {
logger.warning("Exception while running check \"" + currentCheck + "\" for candidate " + replicaSet.getMaster().getHost().getHostname() + ": " + e.getMessage());
currentCheck.setLastFailureMessage(e.getMessage()==null?e.getClass().getSimpleName():e.getMessage());
try {
@@ -46,6 +46,7 @@ public class ResultImportUrlsPanelPO extends PageArea {
dialogPO.setUrl(url);
dialogPO.clickOkButtonOrThrow();
waitForElementNotExistsBySeleniumId(driver, "ResultImportUrlAddDialog");
waitForAjaxRequests();
}
public void removeUrl(String url) {
@@ -130,6 +130,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -198,9 +200,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -14,6 +14,9 @@
<setAttribute key="deselected_workspace_bundles"/>
<booleanAttribute key="includeOptional" value="false"/>
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
<mapAttribute key="org.eclipse.debug.core.environmentVariables">
<mapEntry key="GITHUB_TOKEN" value="${GITHUB_TOKEN}"/>
</mapAttribute>
<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.pde.ui.launcher.PDESourceLookupDirector"/>
<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;sourceLookupDirector&gt;&#13;&#10; &lt;sourceContainers duplicates=&quot;false&quot;&gt;&#13;&#10; &lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;directory nest=&amp;quot;false&amp;quot; path=&amp;quot;C:\Users\georg\Documents\Business\Kunden\OIO\SAPsailing\jetty.project\apache-jsp\src\main\java&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.debug.core.containerType.directory&quot;/&gt;&#13;&#10; &lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;classpathContainer path=&amp;quot;com.google.gwt.eclipse.core.GWT_CONTAINER&amp;quot;/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.classpathContainer&quot;/&gt;&#13;&#10; &lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#13;&amp;#10;&amp;lt;default/&amp;gt;&amp;#13;&amp;#10;&quot; typeId=&quot;org.eclipse.debug.core.containerType.default&quot;/&gt;&#13;&#10; &lt;/sourceContainers&gt;&#13;&#10;&lt;/sourceLookupDirector&gt;&#13;&#10;"/>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
@@ -34,348 +37,368 @@
<stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%false%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%true%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
<stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_TENANT_FILTER%CTX_KEY%*%CTX_ENTRY%"/>
<setAttribute key="selected_target_bundles">
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.diffplug.osgi.extension.sun.misc@default:false"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
<setEntry value="com.esotericsoftware.minlog@default:default"/>
<setEntry value="com.esotericsoftware.reflectasm@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
<setEntry value="com.fasterxml.jackson.dataformat.jackson-dataformat-yaml@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.mwiede.jsch.source"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.google.gson.source"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.google.protobuf.source"/>
<setEntry value="com.google.protobuf@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn.source"/>
<setEntry value="com.nulab-inc.zxcvbn@default:default"/>
<setEntry value="com.rabbitmq.client.source"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.sap.db.jdbc.source"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="com.sun.jna.platform.source"/>
<setEntry value="com.sun.jna.platform@default:default"/>
<setEntry value="com.sun.jna.source"/>
<setEntry value="com.sun.jna@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="io.netty.buffer@default:default"/>
<setEntry value="io.netty.codec-dns@default:default"/>
<setEntry value="io.netty.codec@default:default"/>
<setEntry value="io.netty.common@default:default"/>
<setEntry value="io.netty.handler@default:default"/>
<setEntry value="io.netty.incubator.netty-incubator-transport-classes-io_uring@default:default"/>
<setEntry value="io.netty.resolver-dns@default:default"/>
<setEntry value="io.netty.resolver@default:default"/>
<setEntry value="io.netty.transport-classes-epoll@default:default"/>
<setEntry value="io.netty.transport-classes-kqueue@default:default"/>
<setEntry value="io.netty.transport-native-unix-common@default:default"/>
<setEntry value="io.netty.transport@default:default"/>
<setEntry value="io.projectreactor.reactor-core@default:default"/>
<setEntry value="io.reactivex.rxjava3.rxjava@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="javax.cache.api@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="jodd-bean@default:default"/>
<setEntry value="jul.to.slf4j@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent.source"/>
<setEntry value="net.bytebuddy.byte-buddy-agent@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy.source"/>
<setEntry value="net.bytebuddy.byte-buddy@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.commons.collections4.source"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.apache.commons.compress.source"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.poi.ooxml.source"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.source"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.shiro.core.source"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.web.source"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.http.source"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.io.source"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:false"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="org.eclipse.jetty.security.source"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.server.source"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.source"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server.source"/>
<setEntry value="org.eclipse.jetty.websocket.server@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet.source"/>
<setEntry value="org.eclipse.jetty.websocket.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.osgi.services.source"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.source"/>
<setEntry value="org.eclipse.osgi.util.source"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="org.jboss.marshalling.jboss-marshalling-osgi@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.mongodb.bson.source"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.driver-core.source"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el.source"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp.source"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.objectweb.asm.commons.source"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.source"/>
<setEntry value="org.objectweb.asm.tree.analysis.source"/>
<setEntry value="org.objectweb.asm.tree.analysis@default:default"/>
<setEntry value="org.objectweb.asm.tree.source"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util.source"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="org.osgi.util.function.source"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.measurement.source"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.position.source"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.promise.source"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.util.xml.source"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.owasp.encoder.source"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="org.yaml.snakeyaml@default:default"/>
<setEntry value="reactive-streams@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="routeconverter@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
</setAttribute>
<setEntry value="routeconverter@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.poi.source@default:default"/>
<setEntry value="org.apache.poi.ooxml.source@default:default"/>
<setEntry value="org.apache.commons.collections4.source@default:default"/>
<setEntry value="org.apache.commons.compress.source@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-core.source@default:default"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.bson.source@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source@default:default"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.http.source@default:default"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.io.source@default:default"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source@default:default"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.security.source@default:default"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.server.source@default:default"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source@default:default"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source@default:default"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet.source@default:default"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="jul.to.slf4j@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.rabbitmq.client.source@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="org.owasp.encoder.source@default:default"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.core.source@default:default"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source@default:default"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.shiro.web.source@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.eclipse.osgi.source@default:default"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.promise.source@default:default"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.function.source@default:default"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.measurement.source@default:default"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.position.source@default:default"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.osgi.util.xml.source@default:default"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.services.source@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi.util.source@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.github.mwiede.jsch.source@default:default"/>
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.tree.analysis@default:default"/>
<setEntry value="org.objectweb.asm.tree.analysis.source@default:default"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.tree.source@default:default"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm.source@default:default"/>
<setEntry value="org.objectweb.asm.commons.source@default:default"/>
<setEntry value="org.objectweb.asm.tree.source@default:default"/>
<setEntry value="org.objectweb.asm.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el.source@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp.source@default:default"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
<setEntry value="com.esotericsoftware.reflectasm@default:default"/>
<setEntry value="com.esotericsoftware.minlog@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
<setEntry value="com.fasterxml.jackson.dataformat.jackson-dataformat-yaml@default:default"/>
<setEntry value="org.yaml.snakeyaml@default:default"/>
<setEntry value="io.netty.transport@default:default"/>
<setEntry value="io.netty.buffer@default:default"/>
<setEntry value="io.netty.common@default:default"/>
<setEntry value="io.netty.resolver@default:default"/>
<setEntry value="io.netty.transport-classes-epoll@default:default"/>
<setEntry value="io.netty.transport-native-unix-common@default:default"/>
<setEntry value="io.netty.transport-classes-kqueue@default:default"/>
<setEntry value="io.netty.codec@default:default"/>
<setEntry value="io.netty.handler@default:default"/>
<setEntry value="io.netty.resolver-dns@default:default"/>
<setEntry value="io.netty.codec-dns@default:default"/>
<setEntry value="io.netty.incubator.netty-incubator-transport-classes-io_uring@default:default"/>
<setEntry value="io.reactivex.rxjava3.rxjava@default:default"/>
<setEntry value="reactive-streams@default:default"/>
<setEntry value="javax.cache.api@default:default"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source@default:default"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source@default:default"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source@default:default"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source@default:default"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.google.gson.source@default:default"/>
<setEntry value="jodd-bean@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy.source@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent.source@default:default"/>
<setEntry value="org.jboss.marshalling.jboss-marshalling-osgi@default:default"/>
<setEntry value="io.projectreactor.reactor-core@default:default"/>
<setEntry value="com.diffplug.osgi.extension.sun.misc@default:default"/>
<setEntry value="com.google.protobuf@default:default"/>
<setEntry value="com.google.protobuf.source@default:default"/>
<setEntry value="com.sun.jna@default:default"/>
<setEntry value="com.sun.jna.source@default:default"/>
<setEntry value="com.sun.jna.platform@default:default"/>
<setEntry value="com.sun.jna.platform.source@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn.source@default:default"/>
</setAttribute>
<setAttribute key="selected_workspace_bundles">
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="com.sap.sailing.aiagent.gateway@6:true"/>
<setEntry value="com.sap.sailing.aiagent.interfaces@default:default"/>
<setEntry value="com.sap.sailing.aiagent.persistence@5:true"/>
<setEntry value="com.sap.sailing.aiagent@4:true"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.server@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@default:default"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.queclinkadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.vakarosadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:false"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.html.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sse.aicore@default:default"/>
<setEntry value="com.sap.sse.branding.sap@5:true"/>
<setEntry value="com.sap.sse.branding@default:default"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="elemental2@default:default"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
</setAttribute>
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.vakarosadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.html.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.server@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:default"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.sap.sailing.domain.queclinkadapter@5:true"/>
<setEntry value="com.sap.sailing.aiagent.interfaces@default:default"/>
<setEntry value="com.sap.sailing.aiagent@4:true"/>
<setEntry value="com.sap.sailing.aiagent.persistence@5:true"/>
<setEntry value="com.sap.sailing.aiagent.gateway@6:true"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.branding@default:default"/>
<setEntry value="com.sap.sse.branding.sap@5:true"/>
<setEntry value="com.sap.sse.aicore@default:default"/>
<setEntry value="elemental2@default:default"/>
</setAttribute>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
@@ -136,6 +136,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -204,9 +206,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -129,6 +129,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -197,9 +199,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -134,6 +134,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -202,9 +204,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -133,6 +133,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -201,9 +203,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -127,6 +127,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -195,9 +197,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -123,6 +123,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -191,9 +193,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -129,6 +129,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -197,9 +199,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -127,6 +127,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -195,9 +197,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -27,348 +27,368 @@
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/>
<setAttribute key="selected_target_bundles">
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.diffplug.osgi.extension.sun.misc@default:false"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
<setEntry value="com.esotericsoftware.minlog@default:default"/>
<setEntry value="com.esotericsoftware.reflectasm@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
<setEntry value="com.fasterxml.jackson.dataformat.jackson-dataformat-yaml@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.mwiede.jsch.source"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.google.gson.source"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.google.protobuf.source"/>
<setEntry value="com.google.protobuf@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn.source"/>
<setEntry value="com.nulab-inc.zxcvbn@default:default"/>
<setEntry value="com.rabbitmq.client.source"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.sap.db.jdbc.source"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="com.sun.jna.platform.source"/>
<setEntry value="com.sun.jna.platform@default:default"/>
<setEntry value="com.sun.jna.source"/>
<setEntry value="com.sun.jna@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="io.netty.buffer@default:default"/>
<setEntry value="io.netty.codec-dns@default:default"/>
<setEntry value="io.netty.codec@default:default"/>
<setEntry value="io.netty.common@default:default"/>
<setEntry value="io.netty.handler@default:default"/>
<setEntry value="io.netty.incubator.netty-incubator-transport-classes-io_uring@default:default"/>
<setEntry value="io.netty.resolver-dns@default:default"/>
<setEntry value="io.netty.resolver@default:default"/>
<setEntry value="io.netty.transport-classes-epoll@default:default"/>
<setEntry value="io.netty.transport-classes-kqueue@default:default"/>
<setEntry value="io.netty.transport-native-unix-common@default:default"/>
<setEntry value="io.netty.transport@default:default"/>
<setEntry value="io.projectreactor.reactor-core@default:default"/>
<setEntry value="io.reactivex.rxjava3.rxjava@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="javax.cache.api@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="jodd-bean@default:default"/>
<setEntry value="jul.to.slf4j@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent.source"/>
<setEntry value="net.bytebuddy.byte-buddy-agent@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy.source"/>
<setEntry value="net.bytebuddy.byte-buddy@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.commons.collections4.source"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.apache.commons.compress.source"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.poi.ooxml.source"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.source"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.shiro.core.source"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.web.source"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.http.source"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.io.source"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:false"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="org.eclipse.jetty.security.source"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.server.source"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.source"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server.source"/>
<setEntry value="org.eclipse.jetty.websocket.server@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet.source"/>
<setEntry value="org.eclipse.jetty.websocket.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.osgi.services.source"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.source"/>
<setEntry value="org.eclipse.osgi.util.source"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="org.jboss.marshalling.jboss-marshalling-osgi@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.mongodb.bson.source"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.driver-core.source"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el.source"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp.source"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.objectweb.asm.commons.source"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.source"/>
<setEntry value="org.objectweb.asm.tree.analysis.source"/>
<setEntry value="org.objectweb.asm.tree.analysis@default:default"/>
<setEntry value="org.objectweb.asm.tree.source"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util.source"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="org.osgi.util.function.source"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.measurement.source"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.position.source"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.promise.source"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.util.xml.source"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.owasp.encoder.source"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="org.yaml.snakeyaml@default:default"/>
<setEntry value="reactive-streams@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="routeconverter@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
</setAttribute>
<setEntry value="routeconverter@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.poi.source@default:default"/>
<setEntry value="org.apache.poi.ooxml.source@default:default"/>
<setEntry value="org.apache.commons.collections4.source@default:default"/>
<setEntry value="org.apache.commons.compress.source@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-core.source@default:default"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.bson.source@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source@default:default"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.http.source@default:default"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.io.source@default:default"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source@default:default"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.security.source@default:default"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.server.source@default:default"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source@default:default"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source@default:default"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet.source@default:default"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="jul.to.slf4j@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.rabbitmq.client.source@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="org.owasp.encoder.source@default:default"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.core.source@default:default"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source@default:default"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.shiro.web.source@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.eclipse.osgi.source@default:default"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.promise.source@default:default"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.function.source@default:default"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.measurement.source@default:default"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.position.source@default:default"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.osgi.util.xml.source@default:default"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.services.source@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi.util.source@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.github.mwiede.jsch.source@default:default"/>
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.tree.analysis@default:default"/>
<setEntry value="org.objectweb.asm.tree.analysis.source@default:default"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.tree.source@default:default"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm.source@default:default"/>
<setEntry value="org.objectweb.asm.commons.source@default:default"/>
<setEntry value="org.objectweb.asm.tree.source@default:default"/>
<setEntry value="org.objectweb.asm.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el.source@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp.source@default:default"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
<setEntry value="com.esotericsoftware.reflectasm@default:default"/>
<setEntry value="com.esotericsoftware.minlog@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
<setEntry value="com.fasterxml.jackson.dataformat.jackson-dataformat-yaml@default:default"/>
<setEntry value="org.yaml.snakeyaml@default:default"/>
<setEntry value="io.netty.transport@default:default"/>
<setEntry value="io.netty.buffer@default:default"/>
<setEntry value="io.netty.common@default:default"/>
<setEntry value="io.netty.resolver@default:default"/>
<setEntry value="io.netty.transport-classes-epoll@default:default"/>
<setEntry value="io.netty.transport-native-unix-common@default:default"/>
<setEntry value="io.netty.transport-classes-kqueue@default:default"/>
<setEntry value="io.netty.codec@default:default"/>
<setEntry value="io.netty.handler@default:default"/>
<setEntry value="io.netty.resolver-dns@default:default"/>
<setEntry value="io.netty.codec-dns@default:default"/>
<setEntry value="io.netty.incubator.netty-incubator-transport-classes-io_uring@default:default"/>
<setEntry value="io.reactivex.rxjava3.rxjava@default:default"/>
<setEntry value="reactive-streams@default:default"/>
<setEntry value="javax.cache.api@default:default"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source@default:default"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source@default:default"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source@default:default"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source@default:default"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.google.gson.source@default:default"/>
<setEntry value="jodd-bean@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy.source@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent.source@default:default"/>
<setEntry value="org.jboss.marshalling.jboss-marshalling-osgi@default:default"/>
<setEntry value="io.projectreactor.reactor-core@default:default"/>
<setEntry value="com.diffplug.osgi.extension.sun.misc@default:default"/>
<setEntry value="com.google.protobuf@default:default"/>
<setEntry value="com.google.protobuf.source@default:default"/>
<setEntry value="com.sun.jna@default:default"/>
<setEntry value="com.sun.jna.source@default:default"/>
<setEntry value="com.sun.jna.platform@default:default"/>
<setEntry value="com.sun.jna.platform.source@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn.source@default:default"/>
</setAttribute>
<setAttribute key="selected_workspace_bundles">
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="com.sap.sailing.aiagent.gateway@6:true"/>
<setEntry value="com.sap.sailing.aiagent.interfaces@default:default"/>
<setEntry value="com.sap.sailing.aiagent.persistence@5:true"/>
<setEntry value="com.sap.sailing.aiagent@4:true"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.server@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@default:default"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.queclinkadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.vakarosadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:false"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.html.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sse.aicore@default:default"/>
<setEntry value="com.sap.sse.branding.sap@5:true"/>
<setEntry value="com.sap.sse.branding@default:default"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="elemental2@default:default"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
</setAttribute>
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.vakarosadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.html.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.server@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:default"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.sap.sailing.domain.queclinkadapter@5:true"/>
<setEntry value="com.sap.sailing.aiagent.interfaces@default:default"/>
<setEntry value="com.sap.sailing.aiagent@4:true"/>
<setEntry value="com.sap.sailing.aiagent.persistence@5:true"/>
<setEntry value="com.sap.sailing.aiagent.gateway@6:true"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.branding@default:default"/>
<setEntry value="com.sap.sse.branding.sap@5:true"/>
<setEntry value="com.sap.sse.aicore@default:default"/>
<setEntry value="elemental2@default:default"/>
</setAttribute>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
@@ -127,6 +127,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -195,9 +197,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -127,6 +127,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -195,9 +197,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -123,6 +123,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -191,9 +193,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -132,6 +132,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -200,9 +202,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -129,6 +129,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -197,9 +199,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -27,349 +27,370 @@
<stringAttribute key="profilingTraceType-PERFORMANCE_HOTSPOT_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_IGNORE_SLEEPING_THREADS%CTX_KEY%true%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
<stringAttribute key="profilingTraceType-SYNCHRONIZATION_TRACE" value="KEY_SESSION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_USER_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_REQUEST_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_APPLICATION_FILTER%CTX_KEY%*%CTX_ENTRY%KEY_ENABLEMENT%CTX_KEY%false%CTX_ENTRY%"/>
<setAttribute key="selected_target_bundles">
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.diffplug.osgi.extension.sun.misc@default:false"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
<setEntry value="com.esotericsoftware.minlog@default:default"/>
<setEntry value="com.esotericsoftware.reflectasm@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
<setEntry value="com.fasterxml.jackson.dataformat.jackson-dataformat-yaml@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.mwiede.jsch.source"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.google.gson.source"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.google.protobuf.source"/>
<setEntry value="com.google.protobuf@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn.source"/>
<setEntry value="com.nulab-inc.zxcvbn@default:default"/>
<setEntry value="com.rabbitmq.client.source"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.sap.db.jdbc.source"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="com.sun.jna.platform.source"/>
<setEntry value="com.sun.jna.platform@default:default"/>
<setEntry value="com.sun.jna.source"/>
<setEntry value="com.sun.jna@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="io.netty.buffer@default:default"/>
<setEntry value="io.netty.codec-dns@default:default"/>
<setEntry value="io.netty.codec@default:default"/>
<setEntry value="io.netty.common@default:default"/>
<setEntry value="io.netty.handler@default:default"/>
<setEntry value="io.netty.incubator.netty-incubator-transport-classes-io_uring@default:default"/>
<setEntry value="io.netty.resolver-dns@default:default"/>
<setEntry value="io.netty.resolver@default:default"/>
<setEntry value="io.netty.transport-classes-epoll@default:default"/>
<setEntry value="io.netty.transport-classes-kqueue@default:default"/>
<setEntry value="io.netty.transport-native-unix-common@default:default"/>
<setEntry value="io.netty.transport@default:default"/>
<setEntry value="io.projectreactor.reactor-core@default:default"/>
<setEntry value="io.reactivex.rxjava3.rxjava@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="javax.cache.api@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="jodd-bean@default:default"/>
<setEntry value="jul.to.slf4j@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent.source"/>
<setEntry value="net.bytebuddy.byte-buddy-agent@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy.source"/>
<setEntry value="net.bytebuddy.byte-buddy@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.commons.collections4.source"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.apache.commons.compress.source"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.poi.ooxml.source"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.source"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.shiro.core.source"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.web.source"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.http.source"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.io.source"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:false"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="org.eclipse.jetty.security.source"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.server.source"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.source"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server.source"/>
<setEntry value="org.eclipse.jetty.websocket.server@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet.source"/>
<setEntry value="org.eclipse.jetty.websocket.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.osgi.services.source"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.source"/>
<setEntry value="org.eclipse.osgi.util.source"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="org.jboss.marshalling.jboss-marshalling-osgi@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.mongodb.bson.source"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.driver-core.source"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el.source"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp.source"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.objectweb.asm.commons.source"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.source"/>
<setEntry value="org.objectweb.asm.tree.analysis.source"/>
<setEntry value="org.objectweb.asm.tree.analysis@default:default"/>
<setEntry value="org.objectweb.asm.tree.source"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util.source"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="org.osgi.util.function.source"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.measurement.source"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.position.source"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.promise.source"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.util.xml.source"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.owasp.encoder.source"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="org.yaml.snakeyaml@default:default"/>
<setEntry value="reactive-streams@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="routeconverter@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
</setAttribute>
<setEntry value="routeconverter@default:default"/>
<setEntry value="org.apache.commons.codec@default:default"/>
<setEntry value="org.apache.poi@default:default"/>
<setEntry value="org.apache.poi.ooxml@default:default"/>
<setEntry value="org.apache.poi.ooxml.schemas@default:default"/>
<setEntry value="org.apache.commons.collections4@default:default"/>
<setEntry value="org.apache.commons.compress@default:default"/>
<setEntry value="org.apache.poi.source@default:default"/>
<setEntry value="org.apache.poi.ooxml.source@default:default"/>
<setEntry value="org.apache.commons.collections4.source@default:default"/>
<setEntry value="org.apache.commons.compress.source@default:default"/>
<setEntry value="org.dom4j@default:default"/>
<setEntry value="org.apache.xmlbeans@default:default"/>
<setEntry value="org.apache.commons.math@default:default"/>
<setEntry value="org.apache.httpcomponents.httpclient@default:default"/>
<setEntry value="org.apache.httpcomponents.httpcore@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="com.sun.jersey.contribs.jersey-multipart@default:default"/>
<setEntry value="javax.validation@default:default"/>
<setEntry value="org.apache.commons.fileupload@default:default"/>
<setEntry value="org.jvnet.mimepull@default:default"/>
<setEntry value="org.apache.commons.math3@default:default"/>
<setEntry value="org.mongodb.driver-core@default:default"/>
<setEntry value="org.mongodb.driver-core.source@default:default"/>
<setEntry value="org.mongodb.bson@default:default"/>
<setEntry value="org.mongodb.bson.source@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.mongodb.driver-sync@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot@3:true"/>
<setEntry value="org.eclipse.jetty.osgi.boot.warurl@default:default"/>
<setEntry value="org.hyperic.sigar@default:default"/>
<setEntry value="slf4j.jdk14@default:default"/>
<setEntry value="lz4-java@default:default"/>
<setEntry value="org.apache.felix.gogo.command@default:default"/>
<setEntry value="org.apache.felix.gogo.runtime@default:default"/>
<setEntry value="org.apache.felix.gogo.shell@default:default"/>
<setEntry value="org.eclipse.jetty.deploy@default:default"/>
<setEntry value="org.eclipse.jetty.deploy.source@default:default"/>
<setEntry value="org.eclipse.jetty.http@3:true"/>
<setEntry value="org.eclipse.jetty.http.source@default:default"/>
<setEntry value="org.eclipse.jetty.io@default:default"/>
<setEntry value="org.eclipse.jetty.io.source@default:default"/>
<setEntry value="org.eclipse.jetty.jmx@default:default"/>
<setEntry value="org.eclipse.jetty.jmx.source@default:default"/>
<setEntry value="org.eclipse.jetty.security@default:default"/>
<setEntry value="org.eclipse.jetty.security.source@default:default"/>
<setEntry value="org.eclipse.jetty.server@default:default"/>
<setEntry value="org.eclipse.jetty.server.source@default:default"/>
<setEntry value="org.eclipse.jetty.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.servlet.source@default:default"/>
<setEntry value="org.eclipse.jetty.util@default:default"/>
<setEntry value="org.eclipse.jetty.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax@default:default"/>
<setEntry value="org.eclipse.jetty.util.ajax.source@default:default"/>
<setEntry value="org.eclipse.jetty.webapp@default:default"/>
<setEntry value="org.eclipse.jetty.webapp.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.api.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.client.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.common.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.server.source@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet@default:default"/>
<setEntry value="org.eclipse.jetty.websocket.servlet.source@default:default"/>
<setEntry value="org.eclipse.jetty.xml@default:default"/>
<setEntry value="org.eclipse.jetty.xml.source@default:default"/>
<setEntry value="slf4j.api@default:default"/>
<setEntry value="org.apache.servicemix.bundles.zxing@default:default"/>
<setEntry value="org.apache.commons.io@default:default"/>
<setEntry value="jcl.over.slf4j@default:default"/>
<setEntry value="jul.to.slf4j@default:default"/>
<setEntry value="com.sun.mail.javax.mail@default:default"/>
<setEntry value="com.rabbitmq.client@default:default"/>
<setEntry value="com.rabbitmq.client.source@default:default"/>
<setEntry value="org.apache.commons.lang@default:default"/>
<setEntry value="org.apache.commons.logging@default:default"/>
<setEntry value="jackson-jaxrs@default:default"/>
<setEntry value="com.sun.jersey@default:default"/>
<setEntry value="javax.ws.rs@default:default"/>
<setEntry value="org.apache.commons.beanutils@default:default"/>
<setEntry value="org.apache.commons.beanutils.source@default:default"/>
<setEntry value="org.apache.servicemix.bundles.ehcache@default:default"/>
<setEntry value="org.apache.servicemix.bundles.scribe@default:default"/>
<setEntry value="org.owasp.encoder@default:default"/>
<setEntry value="org.owasp.encoder.source@default:default"/>
<setEntry value="org.apache.shiro.core@default:default"/>
<setEntry value="org.apache.shiro.core.source@default:default"/>
<setEntry value="org.apache.shiro.ehcache@default:default"/>
<setEntry value="org.apache.shiro.ehcache.source@default:default"/>
<setEntry value="org.apache.shiro.web@default:default"/>
<setEntry value="org.apache.shiro.web.source@default:default"/>
<setEntry value="jackson-core-asl@default:default"/>
<setEntry value="jackson-mapper-asl@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-core@default:default"/>
<setEntry value="org.apache.commons.collections@default:default"/>
<setEntry value="org.eclipse.jetty.client@default:default"/>
<setEntry value="javax.xml@default:default"/>
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
<setEntry value="org.eclipse.osgi.source@default:default"/>
<setEntry value="org.osgi.util.promise@default:default"/>
<setEntry value="org.osgi.util.promise.source@default:default"/>
<setEntry value="org.osgi.util.function@default:default"/>
<setEntry value="org.osgi.util.function.source@default:default"/>
<setEntry value="org.osgi.util.measurement@default:default"/>
<setEntry value="org.osgi.util.measurement.source@default:default"/>
<setEntry value="org.osgi.util.position@default:default"/>
<setEntry value="org.osgi.util.position.source@default:default"/>
<setEntry value="org.osgi.util.xml@default:default"/>
<setEntry value="org.osgi.util.xml.source@default:default"/>
<setEntry value="org.eclipse.osgi.services@default:default"/>
<setEntry value="org.eclipse.osgi.services.source@default:default"/>
<setEntry value="org.eclipse.equinox.cm@default:default"/>
<setEntry value="com.sun.istack.commons-runtime@default:default"/>
<setEntry value="com.sun.xml.bind.jaxb-impl@default:default"/>
<setEntry value="javax.xml.stream@default:default"/>
<setEntry value="javax.xml.ws@default:default"/>
<setEntry value="javax.xml.soap@default:default"/>
<setEntry value="org.eclipse.osgi.util@default:default"/>
<setEntry value="org.eclipse.osgi.util.source@default:default"/>
<setEntry value="com.chargebee.chargebee-java@default:default"/>
<setEntry value="com.github.mwiede.jsch@default:default"/>
<setEntry value="com.github.mwiede.jsch.source@default:default"/>
<setEntry value="bcprov-ext@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api@default:default"/>
<setEntry value="com.amazon.aws.aws-java-api.source@default:default"/>
<setEntry value="org.objectweb.asm@default:default"/>
<setEntry value="org.objectweb.asm.commons@default:default"/>
<setEntry value="org.objectweb.asm.tree.analysis@default:default"/>
<setEntry value="org.objectweb.asm.tree.analysis.source@default:default"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.tree.source@default:default"/>
<setEntry value="org.objectweb.asm.tree@default:default"/>
<setEntry value="org.objectweb.asm.util@default:default"/>
<setEntry value="org.objectweb.asm.source@default:default"/>
<setEntry value="org.objectweb.asm.commons.source@default:default"/>
<setEntry value="org.objectweb.asm.tree.source@default:default"/>
<setEntry value="org.objectweb.asm.util.source@default:default"/>
<setEntry value="org.eclipse.jetty.apache-jsp@4:true"/>
<setEntry value="org.eclipse.jetty.apache-jsp.source@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp@default:default"/>
<setEntry value="org.eclipse.jetty.osgi.boot.jsp.source@default:default"/>
<setEntry value="org.apache.geronimo.specs.geronimo-jta_1.1_spec@default:default"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle@3:true"/>
<setEntry value="org.apache.aries.spifly.dynamic.bundle.source@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp@default:default"/>
<setEntry value="org.mortbay.jasper.apache-el.source@default:default"/>
<setEntry value="org.mortbay.jasper.apache-jsp.source@default:default"/>
<setEntry value="org.eclipse.jdt.core.compiler.batch@default:default"/>
<setEntry value="org.apache.taglibs.standard-impl@default:default"/>
<setEntry value="org.apache.taglibs.taglibs-standard-spec@default:default"/>
<setEntry value="javax.annotation@default:default"/>
<setEntry value="org.eclipse.jetty.osgi-servlet-api@default:default"/>
<setEntry value="org.apache.xalan@default:default"/>
<setEntry value="org.apache.xml.serializer@default:default"/>
<setEntry value="org.eclipse.equinox.event@default:default"/>
<setEntry value="org.eclipse.jetty.annotations@4:true"/>
<setEntry value="org.eclipse.jetty.jndi@default:default"/>
<setEntry value="org.eclipse.jetty.plus@default:default"/>
<setEntry value="com.sap.db.jdbc@default:default"/>
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
<setEntry value="com.esotericsoftware.reflectasm@default:default"/>
<setEntry value="com.esotericsoftware.minlog@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-annotations@default:default"/>
<setEntry value="com.fasterxml.jackson.core.jackson-databind@default:default"/>
<setEntry value="com.fasterxml.jackson.dataformat.jackson-dataformat-yaml@default:default"/>
<setEntry value="org.yaml.snakeyaml@default:default"/>
<setEntry value="io.netty.transport@default:default"/>
<setEntry value="io.netty.buffer@default:default"/>
<setEntry value="io.netty.common@default:default"/>
<setEntry value="io.netty.resolver@default:default"/>
<setEntry value="io.netty.transport-classes-epoll@default:default"/>
<setEntry value="io.netty.transport-native-unix-common@default:default"/>
<setEntry value="io.netty.transport-classes-kqueue@default:default"/>
<setEntry value="io.netty.codec@default:default"/>
<setEntry value="io.netty.handler@default:default"/>
<setEntry value="io.netty.resolver-dns@default:default"/>
<setEntry value="io.netty.codec-dns@default:default"/>
<setEntry value="io.netty.incubator.netty-incubator-transport-classes-io_uring@default:default"/>
<setEntry value="io.reactivex.rxjava3.rxjava@default:default"/>
<setEntry value="reactive-streams@default:default"/>
<setEntry value="javax.cache.api@default:default"/>
<setEntry value="com.github.haifengl.smile-core@default:default"/>
<setEntry value="com.github.haifengl.smile-core.source@default:default"/>
<setEntry value="com.github.haifengl.smile-data@default:default"/>
<setEntry value="com.github.haifengl.smile-data.source@default:default"/>
<setEntry value="com.github.haifengl.smile-graph@default:default"/>
<setEntry value="com.github.haifengl.smile-graph.source@default:default"/>
<setEntry value="com.github.haifengl.smile-math@default:default"/>
<setEntry value="com.github.haifengl.smile-math.source@default:default"/>
<setEntry value="com.google.gson@default:default"/>
<setEntry value="com.google.gson.source@default:default"/>
<setEntry value="jodd-bean@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy.source@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent@default:default"/>
<setEntry value="net.bytebuddy.byte-buddy-agent.source@default:default"/>
<setEntry value="org.jboss.marshalling.jboss-marshalling-osgi@default:default"/>
<setEntry value="io.projectreactor.reactor-core@default:default"/>
<setEntry value="com.diffplug.osgi.extension.sun.misc@default:default"/>
<setEntry value="com.google.protobuf@default:default"/>
<setEntry value="com.google.protobuf.source@default:default"/>
<setEntry value="com.sun.jna@default:default"/>
<setEntry value="com.sun.jna.source@default:default"/>
<setEntry value="com.sun.jna.platform@default:default"/>
<setEntry value="com.sun.jna.platform.source@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn@default:default"/>
<setEntry value="com.nulab-inc.zxcvbn.source@default:default"/>
</setAttribute>
<setAttribute key="selected_workspace_bundles">
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="com.sap.sailing.aiagent.gateway@6:true"/>
<setEntry value="com.sap.sailing.aiagent.interfaces@default:default"/>
<setEntry value="com.sap.sailing.aiagent.persistence@5:true"/>
<setEntry value="com.sap.sailing.aiagent@4:true"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.server@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@default:default"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.queclinkadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.vakarosadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:false"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.html.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.test.support@5:true"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sse.aicore@default:default"/>
<setEntry value="com.sap.sse.branding.sap@5:true"/>
<setEntry value="com.sap.sse.branding@default:default"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="elemental2@default:default"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
</setAttribute>
<setEntry value="com.sap.sailing.geocoding@default:default"/>
<setEntry value="com.sap.sailing.domain.common@default:default"/>
<setEntry value="com.sap.sailing.domain@default:default"/>
<setEntry value="com.sap.sailing.news@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.vakarosadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.windfinderadapter@4:true"/>
<setEntry value="com.sap.sailing.server@5:true"/>
<setEntry value="com.sap.sailing.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.server.gateway.interfaces@default:default"/>
<setEntry value="com.sap.sailing.declination@default:default"/>
<setEntry value="com.sap.sailing.domain.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.domain.swisstimingreplayadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.tractracadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.gwt.ui@6:true"/>
<setEntry value="com.sap.sailing.udpconnector@default:default"/>
<setEntry value="com.sap.sailing.simulator@default:default"/>
<setEntry value="com.sap.sailing.www@5:true"/>
<setEntry value="com.sap.sailing.resultimport@4:true"/>
<setEntry value="com.sap.sailing.kiworesultimport@4:true"/>
<setEntry value="com.sap.sailing.ess40.resultimport@4:true"/>
<setEntry value="com.sap.sailing.freg.resultimport@4:true"/>
<setEntry value="com.sap.sailing.barbados.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailwave.html.resultimport@4:true"/>
<setEntry value="com.sap.sailing.manage2sail.resultimport@4:true"/>
<setEntry value="com.sap.sailing.sailti.resultimport@4:true"/>
<setEntry value="com.sap.sailing.yachtscoring.resultimport@4:true"/>
<setEntry value="com.sap.sailing.velum.resultimport@4:true"/>
<setEntry value="com.sap.sailing.monitoring@7:true"/>
<setEntry value="com.sap.sailing.xrr.resultimport@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.server@4:true"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.persistence@default:default"/>
<setEntry value="com.sap.sailing.domain.racelogtrackingadapter@4:true"/>
<setEntry value="com.sap.sailing.domain.deckmanadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.oceanraceadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter@5:true"/>
<setEntry value="com.sap.sailing.domain.yellowbrickadapter.persistence@4:true"/>
<setEntry value="com.sap.sailing.xrr.structureimport@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization.shared.android@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.serialization@default:default"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.dashboards.gwt@6:true"/>
<setEntry value="com.sap.sailing.datamining@5:true"/>
<setEntry value="com.sap.sailing.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.polars@5:true"/>
<setEntry value="com.sap.sailing.windestimation@5:true"/>
<setEntry value="com.sap.sailing.polars.datamining@5:true"/>
<setEntry value="com.sap.sailing.domain.shared.android@default:default"/>
<setEntry value="com.sap.sailing.manage2sail@default:default"/>
<setEntry value="com.sap.sailing.polars.datamining.shared@default:default"/>
<setEntry value="com.sap.sailing.xrr.schema@default:default"/>
<setEntry value="com.sap.sailing.server.trackfiles@default:default"/>
<setEntry value="com.sap.sailing.competitorimport@default:default"/>
<setEntry value="com.sap.sailing.datamining.provider@default:default"/>
<setEntry value="com.sap.sailing.grib@default:default"/>
<setEntry value="com.sap.sailing.nmeaconnector@default:default"/>
<setEntry value="com.sap.sailing.domain.expeditionadapter@5:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.persistence@4:true"/>
<setEntry value="com.sap.sailing.expeditionconnector.common@default:default"/>
<setEntry value="com.sap.sailing.domain.bravoadapter@5:true"/>
<setEntry value="net.sf.marineapi@default:default"/>
<setEntry value="com.sap.sailing.routeconverterjava11extension@default:default"/>
<setEntry value="com.sap.sailing.server.interface@default:default"/>
<setEntry value="com.sap.sse.datamining.ui@default:default"/>
<setEntry value="com.sap.sailing.domain.igtimiadapter.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.server@5:true"/>
<setEntry value="com.sap.sailing.shared.server.gateway@5:true"/>
<setEntry value="com.sap.sailing.shared.persistence@default:default"/>
<setEntry value="com.sap.sailing.landscape@default:default"/>
<setEntry value="com.sap.sailing.landscape.gateway@5:true"/>
<setEntry value="com.sap.sailing.landscape.common@default:default"/>
<setEntry value="com.sap.sailing.landscape.ui@default:default"/>
<setEntry value="com.sap.sailing.hanaexport@5:true"/>
<setEntry value="com.sap.sailing.domain.queclinkadapter@5:true"/>
<setEntry value="com.sap.sailing.aiagent.interfaces@default:default"/>
<setEntry value="com.sap.sailing.aiagent@4:true"/>
<setEntry value="com.sap.sailing.aiagent.persistence@5:true"/>
<setEntry value="com.sap.sailing.aiagent.gateway@6:true"/>
<setEntry value="com.tractrac.clientmodule@default:default"/>
<setEntry value="com.sap.sse.gwt@default:default"/>
<setEntry value="com.google.gwt.servlet@default:default"/>
<setEntry value="com.sap.sse.security@default:default"/>
<setEntry value="com.sap.sse.security.ui@6:true"/>
<setEntry value="com.sap.sse.security.userstore.mongodb@4:true"/>
<setEntry value="com.sap.sse@default:default"/>
<setEntry value="com.sap.sse.common@default:default"/>
<setEntry value="com.sap.sse.datamining@default:default"/>
<setEntry value="com.sap.sse.datamining.annotations@default:default"/>
<setEntry value="com.sap.sse.datamining.shared@default:default"/>
<setEntry value="com.sap.sse.gwt.adminconsole@default:default"/>
<setEntry value="com.sap.sse.mongodb@default:default"/>
<setEntry value="com.sap.sse.operationaltransformation@default:default"/>
<setEntry value="com.sap.sse.replication@6:true"/>
<setEntry value="com.sap.sse.filestorage@4:true"/>
<setEntry value="com.sap.sse.shared.android@default:default"/>
<setEntry value="com.sap.sse.mail@5:true"/>
<setEntry value="com.sap.sse.threadmanager@default:default"/>
<setEntry value="com.sap.sse.security.common@default:default"/>
<setEntry value="org.json.simple@default:default"/>
<setEntry value="org.moxieapps.gwt.highcharts@default:default"/>
<setEntry value="com.googlecode.java-diff-utils@default:default"/>
<setEntry value="org.mp4parser.isoparser@default:default"/>
<setEntry value="com.sap.sse.replication.interfaces@default:default"/>
<setEntry value="com.sap.sse.security.datamining@5:true"/>
<setEntry value="com.sap.sse.security.persistence@default:default"/>
<setEntry value="com.sap.sse.security.interface@default:default"/>
<setEntry value="com.sap.sse.replication.persistence@default:default"/>
<setEntry value="com.sap.sse.landscape.common@default:default"/>
<setEntry value="com.sap.sse.landscape@default:default"/>
<setEntry value="com.sap.sse.landscape.aws@4:true"/>
<setEntry value="com.sap.sse.landscape.aws.common@default:default"/>
<setEntry value="com.sap.sse.landscape.aws.persistence@default:default"/>
<setEntry value="com.sap.sse.branding@default:default"/>
<setEntry value="com.sap.sse.branding.sap@5:true"/>
<setEntry value="com.sap.sse.aicore@default:default"/>
<setEntry value="elemental2@default:default"/>
<setEntry value="com.sap.sailing.server.gateway.test.support@5:true"/>
</setAttribute>
<booleanAttribute key="show_selected_only" value="false"/>
<booleanAttribute key="tracing" value="false"/>
<booleanAttribute key="useCustomFeatures" value="false"/>
@@ -136,6 +136,8 @@
<setEntry value="com.sun.activation.javax.activation@default:default"/>
<setEntry value="org.eclipse.equinox.common@2:true"/>
<setEntry value="org.eclipse.equinox.console@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api@default:default"/>
<setEntry value="org.eclipse.equinox.http.service.api.source@default:default"/>
<setEntry value="org.eclipse.equinox.launcher@default:default"/>
<setEntry value="org.eclipse.equinox.simpleconfigurator@2:true"/>
<setEntry value="org.eclipse.osgi@-1:true"/>
@@ -204,9 +206,22 @@
<setEntry value="com.sap.db.jdbc.source@default:default"/>
<setEntry value="org.osgi.service.component@default:default"/>
<setEntry value="org.osgi.service.cm@default:default"/>
<setEntry value="org.osgi.util.tracker@default:default"/>
<setEntry value="org.osgi.service.event@default:default"/>
<setEntry value="org.osgi.service.metatype@default:default"/>
<setEntry value="org.osgi.service.metatype.source@default:default"/>
<setEntry value="org.osgi.service.packageadmin@default:default"/>
<setEntry value="org.osgi.service.provisioning@default:default"/>
<setEntry value="org.osgi.service.provisioning.source@default:default"/>
<setEntry value="org.osgi.service.upnp@default:default"/>
<setEntry value="org.osgi.service.upnp.source@default:default"/>
<setEntry value="org.osgi.service.useradmin@default:default"/>
<setEntry value="org.osgi.service.useradmin.source@default:default"/>
<setEntry value="org.osgi.service.wireadmin@default:default"/>
<setEntry value="org.osgi.service.wireadmin.source@default:default"/>
<setEntry value="org.osgi.service.device@default:default"/>
<setEntry value="org.osgi.service.device.source@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard@default:default"/>
<setEntry value="org.osgi.service.http.whiteboard.source@default:default"/>
<setEntry value="org.osgi.service.url@default:default"/>
<setEntry value="redisson@default:default"/>
<setEntry value="com.esotericsoftware.kryo@default:default"/>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
<target name="Race Analysis Target" sequenceNumber="226">
<target name="Race Analysis Target" sequenceNumber="227">
<locations>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="slicer" includeSource="true" type="InstallableUnit">
<unit id="javax.ws.rs" version="1.1.1.v20130318-1750"/>
@@ -121,23 +121,39 @@
<repository location="https://download.eclipse.org/releases/2020-12"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="slicer" includeSource="true" type="InstallableUnit">
<unit id="org.eclipse.osgi" version="3.18.0.v20220516-2155"/>
<unit id="org.eclipse.osgi.source" version="3.18.0.v20220516-2155"/>
<unit id="org.eclipse.osgi.services" version="3.10.200.v20210723-0643"/>
<unit id="org.eclipse.osgi.services.source" version="3.10.200.v20210723-0643"/>
<unit id="org.eclipse.osgi.util" version="3.7.0.v20220427-2144"/>
<unit id="org.eclipse.osgi.util.source" version="3.7.0.v20220427-2144"/>
<unit id="org.osgi.util.promise" version="1.2.0.202109301733"/>
<unit id="org.osgi.util.promise.source" version="1.2.0.202109301733"/>
<unit id="org.eclipse.equinox.http.service.api" version="1.2.2.v20231218-2126"/>
<unit id="org.eclipse.equinox.http.service.api.source" version="1.2.2.v20231218-2126"/>
<unit id="org.eclipse.osgi" version="3.19.0.v20240213-1246"/>
<unit id="org.eclipse.osgi.source" version="3.19.0.v20240213-1246"/>
<unit id="org.eclipse.osgi.services" version="3.12.0.v20231218-2126"/>
<unit id="org.eclipse.osgi.services.source" version="3.12.0.v20231218-2126"/>
<unit id="org.eclipse.osgi.util" version="3.7.300.v20231104-1118"/>
<unit id="org.eclipse.osgi.util.source" version="3.7.300.v20231104-1118"/>
<unit id="org.osgi.util.promise" version="1.3.0.202212101352"/>
<unit id="org.osgi.util.promise.source" version="1.3.0.202212101352"/>
<unit id="org.osgi.util.function" version="1.2.0.202109301733"/>
<unit id="org.osgi.util.function.source" version="1.2.0.202109301733"/>
<unit id="org.osgi.util.measurement" version="1.0.2.201802012109"/>
<unit id="org.osgi.util.measurement.source" version="1.0.2.201802012109"/>
<unit id="org.osgi.util.position" version="1.0.1.201505202026"/>
<unit id="org.osgi.util.position.source" version="1.0.1.201505202026"/>
<unit id="org.osgi.service.metatype" version="1.4.1.202109301733"/>
<unit id="org.osgi.service.metatype.source" version="1.4.1.202109301733"/>
<unit id="org.osgi.service.provisioning" version="1.2.0.201505202024"/>
<unit id="org.osgi.service.provisioning.source" version="1.2.0.201505202024"/>
<unit id="org.osgi.service.upnp" version="1.2.1.202109301733"/>
<unit id="org.osgi.service.upnp.source" version="1.2.1.202109301733"/>
<unit id="org.osgi.service.device" version="1.1.1.202109301733"/>
<unit id="org.osgi.service.device.source" version="1.1.1.202109301733"/>
<unit id="org.osgi.service.http.whiteboard" version="1.1.1.202109301733"/>
<unit id="org.osgi.service.http.whiteboard.source" version="1.1.1.202109301733"/>
<unit id="org.osgi.service.wireadmin" version="1.0.2.202109301733"/>
<unit id="org.osgi.service.wireadmin.source" version="1.0.2.202109301733"/>
<unit id="org.osgi.service.useradmin" version="1.1.1.202109301733"/>
<unit id="org.osgi.service.useradmin.source" version="1.1.1.202109301733"/>
<unit id="org.osgi.util.xml" version="1.0.2.202109301733"/>
<unit id="org.osgi.util.xml.source" version="1.0.2.202109301733"/>
<repository location="https://download.eclipse.org/releases/2022-06"/>
<repository location="https://download.eclipse.org/releases/2024-03"/>
</location>
<location includeAllPlatforms="false" includeConfigurePhase="false" includeMode="slicer" includeSource="true" type="InstallableUnit">
<unit id="junit-jupiter-api" version="5.11.3"/>
@@ -269,6 +285,8 @@
<plugin id="org.eclipse.equinox.common.source"/>
<plugin id="org.eclipse.equinox.console"/>
<plugin id="org.eclipse.equinox.console.source"/>
<plugin id="org.eclipse.equinox.http.service.api"/>
<plugin id="org.eclipse.equinox.http.service.api.source"/>
<plugin id="org.eclipse.equinox.launcher"/>
<plugin id="org.eclipse.equinox.launcher.source"/>
<plugin id="org.eclipse.equinox.simpleconfigurator"/>
@@ -424,9 +442,22 @@
<plugin id="org.osgi.service.cm"/>
<plugin id="org.osgi.service.component"/>
<plugin id="org.osgi.service.packageadmin"/>
<plugin id="org.osgi.service.provisioning"/>
<plugin id="org.osgi.service.provisioning.source"/>
<plugin id="org.osgi.service.upnp"/>
<plugin id="org.osgi.service.upnp.source"/>
<plugin id="org.osgi.service.device"/>
<plugin id="org.osgi.service.device.source"/>
<plugin id="org.osgi.service.http.whiteboard"/>
<plugin id="org.osgi.service.http.whiteboard.source"/>
<plugin id="org.osgi.service.metatype"/>
<plugin id="org.osgi.service.metatype.source"/>
<plugin id="org.osgi.service.url"/>
<plugin id="org.osgi.service.useradmin"/>
<plugin id="org.osgi.service.useradmin.source"/>
<plugin id="org.osgi.service.wireadmin"/>
<plugin id="org.osgi.service.wireadmin.source"/>
<plugin id="org.osgi.service.event"/>
<plugin id="org.osgi.util.tracker"/>
<plugin id="org.osgi.util.promise"/>
<plugin id="org.osgi.util.promise.source"/>
<plugin id="org.osgi.util.function"/>
@@ -27,6 +27,11 @@
<ul class="bulletList">
<li>Tables with multi-selection support now have a select/de-select all checkbox in the table header.
This comes with general improvements in table selection/de-selection handling.</li>
<li>Users can now opt out of feature and community e-mails. This flag is available in
Data Mining as a dimension for filtering and grouping.</li>
<ii>When updates to user accounts are carried out using the API, not passing a property (such as
company affiliation or preferred locale) will no longer reset that value to <tt>null</tt>
but instead leave it unchanged.</ii>
<li>A new "Eraser" action has been added to the leaderboards table at the top of the
Connectors / Smartphone Tracking panel. If the leadeboard is a "Regatta" leaderboard
and the corresponding Regatta is configured to control tracking times from race
@@ -34,6 +39,10 @@
time specifications of the race logs of all races in the leaderboard that have valid
race start/finished times. This way, overly long or open tracking intervals can be
avoided.</li>
<li>Refreshing of bundles such as <tt>com.sap.sailing.datamining</tt> and <tt>com.sap.sailing.gwt.ui</tt>
now is possible again at runtime (intended, e.g., for development environments with large loaded
context of races), thanks to upgrading our Equinox OSGi runtime and adjusting how the
<tt>org.osgi.service.tracker</tt> bundle's packages are obtained.</li>
</ul>
<h2 class="articleSubheadline">March 2026</h2>
<ul class="bulletList">
@@ -2,7 +2,7 @@ dataMiningSettings=Data Mining Settings
runPredefinedQuery=Run Predefined Query
viewQueryDefinition=View Query Definition
selectPredefinedQuery=Select Predefined Query
errorRunningDataMiningQuery=An error occured running the query
errorRunningDataMiningQuery=An error occurred running the query
predefinedQueryRunner=Predefined Query Runner
useClassGetNameTooltip=More robust against changes in the code base, but the code snippet can only be used in the scope where the classes are available.
useClassGetName=Use Class.getName() for type names
+120 -15
View File
@@ -575,6 +575,20 @@
install-size="0"
version="1.4.200.v20200828-1034"
unpack="false"/>
<plugin
id="org.eclipse.equinox.http.service.api"
download-size="0"
install-size="0"
version="1.2.2.v20231218-2126"
unpack="false"/>
<plugin
id="org.eclipse.equinox.http.service.api.source"
download-size="0"
install-size="0"
version="1.2.2.v20231218-2126"
unpack="false"/>
<plugin
id="org.eclipse.equinox.launcher"
@@ -594,28 +608,28 @@
id="org.eclipse.osgi"
download-size="0"
install-size="0"
version="3.18.0.v20220516-2155"
version="3.19.0.v20240213-1246"
unpack="false"/>
<plugin
id="org.eclipse.osgi.source"
download-size="0"
install-size="0"
version="3.18.0.v20220516-2155"
version="3.19.0.v20240213-1246"
unpack="false"/>
<plugin
id="org.osgi.util.promise"
download-size="0"
install-size="0"
version="1.2.0.202109301733"
version="1.3.0.202212101352"
unpack="false"/>
<plugin
id="org.osgi.util.promise.source"
download-size="0"
install-size="0"
version="1.2.0.202109301733"
version="1.3.0.202212101352"
unpack="false"/>
<plugin
@@ -678,14 +692,14 @@
id="org.eclipse.osgi.services"
download-size="0"
install-size="0"
version="3.10.200.v20210723-0643"
version="3.12.0.v20231218-2126"
unpack="false"/>
<plugin
id="org.eclipse.osgi.services.source"
download-size="0"
install-size="0"
version="3.10.200.v20210723-0643"
version="3.12.0.v20231218-2126"
unpack="false"/>
<plugin
@@ -733,14 +747,14 @@
id="org.eclipse.osgi.util"
download-size="0"
install-size="0"
version="3.7.0.v20220427-2144"
version="3.7.300.v20231104-1118"
unpack="false"/>
<plugin
id="org.eclipse.osgi.util.source"
download-size="0"
install-size="0"
version="3.7.0.v20220427-2144"
version="3.7.300.v20231104-1118"
unpack="false"/>
<plugin
@@ -1052,13 +1066,6 @@
version="1.6.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.util.tracker"
download-size="0"
install-size="0"
version="1.5.4.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.event"
download-size="0"
@@ -1066,6 +1073,20 @@
version="1.4.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.metatype"
download-size="0"
install-size="0"
version="1.4.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.metatype.source"
download-size="0"
install-size="0"
version="1.4.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.packageadmin"
download-size="0"
@@ -1073,6 +1094,90 @@
version="1.2.1.202007221806"
unpack="false"/>
<plugin
id="org.osgi.service.provisioning"
download-size="0"
install-size="0"
version="1.2.0.201505202024"
unpack="false"/>
<plugin
id="org.osgi.service.provisioning.source"
download-size="0"
install-size="0"
version="1.2.0.201505202024"
unpack="false"/>
<plugin
id="org.osgi.service.upnp"
download-size="0"
install-size="0"
version="1.2.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.upnp.source"
download-size="0"
install-size="0"
version="1.2.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.useradmin"
download-size="0"
install-size="0"
version="1.1.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.useradmin.source"
download-size="0"
install-size="0"
version="1.1.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.wireadmin"
download-size="0"
install-size="0"
version="1.0.2.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.wireadmin.source"
download-size="0"
install-size="0"
version="1.0.2.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.device"
download-size="0"
install-size="0"
version="1.1.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.device.source"
download-size="0"
install-size="0"
version="1.1.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.http.whiteboard"
download-size="0"
install-size="0"
version="1.1.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.http.whiteboard.source"
download-size="0"
install-size="0"
version="1.1.1.202109301733"
unpack="false"/>
<plugin
id="org.osgi.service.url"
download-size="0"
@@ -2,6 +2,6 @@ s3Desc=Store files on Amazon S3. The resulting file name is a random UUID plus t
s3AccessIdDesc=Access ID (leave blank to use ~/.aws/credentials instead)
s3AccessKeyDesc=Secret Access Key (leave blank to use ~/.aws/credentials instead)
s3BucketNameDesc=Name of Bucket to use (has to already exist, and user needs sufficient permissions)
localDesc=Service for storing files in the local file system. Files get stored in localPath+fileName and can be accessed at baseUrl+fileName Note that the content lying in baseUrl must therefore be accessible remotely. This can for examplebe achieved by mounting a remote file system for example from static.sapsailing.com on the replicas to localPath.
localDesc=Service for storing files in the local file system. Files get stored in localPath+fileName and can be accessed at baseUrl+fileName Note that the content lying in baseUrl must therefore be accessible remotely. This can for example be achieved by mounting a remote file system for example from static.sapsailing.com on the replicas to localPath.
localBaseUrlDesc=Base URL + fileName = URL where uploaded file will be accessible
localLocalPathDesc=Local Path to use for file storage
@@ -44,9 +44,9 @@ explainReplicationServletPort=Servlet port number that is used to connect to reg
setUpStorageService=Please set up a file storage service first
usernameAndPasswordMustBothBeSet=Username and password must both be filled or empty
username=User name
explainUserName=Username to use for authentification on the master
explainUserName=Username to use for authentication on the master
password=Password
explainPassword=Password to use for authentification on the master
explainPassword=Password to use for authentication on the master
additionalInformation=Info
serverInformation=Server Information
serverName=Server Name: {0}
@@ -6,7 +6,7 @@ import com.google.gwt.view.client.ProvidesKey;
/**
* This {@link FlushableCellTable} provides the {@link FlushableCellTable#flush()}-method for the
* {@link SelectionCheckboxColumn}. So the {@link SelectionCheckboxColumn} can ensure that the selection state is
* displayed correct.
* displayed correctly.
*
* @author D064976
* @param <T>
@@ -3,6 +3,7 @@ package com.sap.sse.landscape.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
@@ -24,6 +25,7 @@ import org.json.simple.parser.ParseException;
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.landscape.Release;
import com.sap.sse.landscape.ReleaseRepository;
@@ -153,8 +155,8 @@ public class GithubReleasesRepository extends AbstractReleaseRepository implemen
} else {
logger.fine(()->"Need to fetch page with newest releases because last request was at "+
(lastFetchOfNewestReleases==null?"<never>":lastFetchOfNewestReleases));
lastFetchOfNewestReleases = now;
fillCacheWithNewestReleases();
lastFetchOfNewestReleases = now;
}
cachedReleasesIterator = releasesByPublishingTimePoint.descendingMap().values().iterator();
}
@@ -215,6 +217,11 @@ public class GithubReleasesRepository extends AbstractReleaseRepository implemen
* cache when this method is invoked.
* <p>
*
* If the {@code GITHUB_TOKEN} environment variable is set, it is used as a bearer token forthe Github requests,
* resulting in a higher rate limit. If no token is set, or if using the token results in a 401 response code
* (authentication failed), an unauthenticated request is tried instead.
* <p>
*
* The method makes no changes to the cache or any other state of this instance.
*
* @return the link to the next page in the returned pair's {@link Pair#getA() A component}, and the sequence of
@@ -222,7 +229,24 @@ public class GithubReleasesRepository extends AbstractReleaseRepository implemen
*/
private synchronized Pair<String, Iterable<Pair<TimePoint, GithubRelease>>> getReleasesFromPage(String pageURL) throws IOException, ParseException {
logger.info("Requesting releases page "+pageURL);
final URLConnection connection = HttpUrlConnectionHelper.redirectConnection(new URL(pageURL));
final URLConnection connection;
final String githubToken = System.getenv("GITHUB_TOKEN");
if (Util.hasLength(githubToken)) {
final HttpURLConnection authenticatedConnectionAttempt = (HttpURLConnection) HttpUrlConnectionHelper
.redirectConnectionWithBearerToken(new URL(pageURL), githubToken);
if (authenticatedConnectionAttempt.getResponseCode() == 401) {
try {
authenticatedConnectionAttempt.disconnect();
} catch (Exception e) {
logger.warning("Couldn't disconnect from Github: "+e.getMessage());
}
connection = HttpUrlConnectionHelper.redirectConnection(new URL(pageURL));
} else {
connection = authenticatedConnectionAttempt;
}
} else {
connection = HttpUrlConnectionHelper.redirectConnection(new URL(pageURL));
}
final InputStream index = (InputStream) connection.getContent();
final String xRatelimitRemaining = connection.getHeaderField("x-ratelimit-remaining");
logger.fine(()->""+xRatelimitRemaining+" requests left in this hour");
@@ -26,6 +26,7 @@ public class UserDTO extends
private String locale;
private List<AccountDTO> accounts;
private boolean emailValidated;
private boolean didOptOutOfFeatureAndCommunityEmails;
private List<StrippedUserGroupDTO> groups;
private TimePoint lockedUntil;
private SecurityInformationDTO securityInformation = new SecurityInformationDTO();
@@ -42,8 +43,8 @@ public class UserDTO extends
* @param groups may be {@code null} which is equivalent to passing an empty groups collection
*/
public UserDTO(String name, String email, String fullName, String company, String locale, boolean emailValidated,
List<AccountDTO> accounts, Iterable<RoleWithSecurityDTO> roles, StrippedUserGroupDTO defaultTenant,
Iterable<WildcardPermissionWithSecurityDTO> permissions,
boolean didOptOutOfFeatureAndCommunityEmails, List<AccountDTO> accounts, Iterable<RoleWithSecurityDTO> roles,
StrippedUserGroupDTO defaultTenant, Iterable<WildcardPermissionWithSecurityDTO> permissions,
Iterable<StrippedUserGroupDTO> groups, TimePoint lockedUntil) {
super(name, permissions);
this.defaultTenantForCurrentServer = defaultTenant;
@@ -52,6 +53,7 @@ public class UserDTO extends
this.company = company;
this.locale = locale;
this.emailValidated = emailValidated;
this.didOptOutOfFeatureAndCommunityEmails = didOptOutOfFeatureAndCommunityEmails;
this.accounts = accounts;
this.groups = new ArrayList<>();
Util.addAll(groups, this.groups);
@@ -72,7 +74,8 @@ public class UserDTO extends
final List<StrippedUserGroupDTO> groupsCopy = new ArrayList<StrippedUserGroupDTO>();
Util.addAll(this.groups, groupsCopy);
return new UserDTO(this.getName(), this.email, this.fullName, this.company, this.locale, this.emailValidated,
accountsCopy, rolesCopy, this.defaultTenantForCurrentServer, permissionsCopy, groupsCopy, lockedUntil);
this.didOptOutOfFeatureAndCommunityEmails, accountsCopy, rolesCopy, this.defaultTenantForCurrentServer,
permissionsCopy, groupsCopy, lockedUntil);
}
@Override
@@ -140,6 +143,10 @@ public class UserDTO extends
return emailValidated;
}
public boolean getDidOptOutOfFeatureAndCommunityEmails() {
return didOptOutOfFeatureAndCommunityEmails;
}
@Override
public final AccessControlListDTO getAccessControlList() {
return securityInformation.getAccessControlList();
@@ -97,6 +97,10 @@ public interface User extends SecurityUser<RoleDefinition, Role, UserGroup> {
* specific elements as UIs or notification mails.
*/
Locale getLocale();
boolean getDidOptOutOfFeatureAndCommunityEmails();
void setDidOptOutOfFeatureAndCommunityEmails(boolean didOptOutOfFeatureAndCommunityEmails);
void setLocale(Locale locale);
@@ -56,4 +56,5 @@ DataMiningReportsPreference=Data Mining Reports
NumberOfDataMiningQueries=Number of Data Mining Queries
NumberOfDataMiningReports=Number of Data Mining Reports
FullName=Full Name
EMail=E-Mail Address
EMail=E-Mail Address
DidOptOutOfFeatureAndCommunityEmails=Did opt out of Feature and Community Emails
@@ -56,4 +56,5 @@ DataMiningReportsPreference=Data-Mining Berichte
NumberOfDataMiningQueries=Anzahl Data-Mining Anfragen
NumberOfDataMiningReports=Anzahl Data-Mining Berichte
FullName=Ganzer Name
EMail=e-Mail Adresse
EMail=e-Mail Adresse
DidOptOutOfFeatureAndCommunityEmails=Benutzer hat sich von Feature- und Community-E-Mails abgemeldet
@@ -108,4 +108,9 @@ public interface HasUserContext {
final Session session = getSession();
return session == null ? null : TimePoint.now().until(TimePoint.of(session.getLastAccessTime()).plus(Duration.ofMillis(session.getTimeout())));
}
@Dimension(messageKey="DidOptOutOfFeatureAndCommunityEmails")
default boolean didOptOutOfFeatureAndCommunityEmails() {
return getUser().getDidOptOutOfFeatureAndCommunityEmails();
}
}
@@ -72,6 +72,8 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
private String passwordResetSecret;
private boolean emailValidated;
private boolean didOptOutOfFeatureAndCommunityEmails;
private final Map<AccountType, Account> accounts;
@@ -111,13 +113,14 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
public UserImpl(String name, String email, Map<String, UserGroup> defaultTenantForServer,
Collection<Account> accounts, UserGroupProvider userGroupProvider, TimedLock timedLock) {
this(name, email, /* fullName */ null, /* company */ null, /* locale */ null, /* is email validated */ false,
/* password reset secret */ null, /* validation secret */ null, defaultTenantForServer, accounts,
userGroupProvider, timedLock);
/* did opt out of feature and community emails */ false, /* password reset secret */ null, /* validation secret */ null,
defaultTenantForServer, accounts, userGroupProvider, timedLock);
}
public UserImpl(String name, String email, String fullName, String company, Locale locale, Boolean emailValidated,
String passwordResetSecret, String validationSecret, Map<String, UserGroup> defaultTenantForServer,
Collection<Account> accounts, UserGroupProvider userGroupProvider, TimedLock timedLock) {
public UserImpl(String name, String email, String fullName, String company, Locale locale, boolean emailValidated,
boolean didOptOutOfFeatureAndCommunityEmails, String passwordResetSecret, String validationSecret,
Map<String, UserGroup> defaultTenantForServer, Collection<Account> accounts,
UserGroupProvider userGroupProvider, TimedLock timedLock) {
super(name);
this.timedLock = timedLock;
this.defaultTenantForServer = defaultTenantForServer;
@@ -128,6 +131,7 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
this.passwordResetSecret = passwordResetSecret;
this.validationSecret = validationSecret;
this.emailValidated = emailValidated;
this.didOptOutOfFeatureAndCommunityEmails = didOptOutOfFeatureAndCommunityEmails;
this.accounts = new HashMap<>();
this.userGroupProvider = userGroupProvider;
for (Account a : accounts) {
@@ -252,6 +256,11 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
this.email = email;
}
@Override
public void setDidOptOutOfFeatureAndCommunityEmails(boolean didOptOutOfFeatureAndCommunityEmails) {
this.didOptOutOfFeatureAndCommunityEmails = didOptOutOfFeatureAndCommunityEmails;
}
/**
* The email address is set to not yet validated by resetting the
* {@link #emailValidated} flag. A new {@link #validationSecret} is generated and returned which
@@ -370,6 +379,9 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
builder.append("isEmailValidated()=");
builder.append(isEmailValidated());
builder.append(", ");
builder.append("didOptOutOfFeatureAndCommunityEmails()=");
builder.append(getDidOptOutOfFeatureAndCommunityEmails());
builder.append(", ");
if (getPermissions() != null) {
builder.append("getPermissions()=");
builder.append(getPermissions());
@@ -472,4 +484,9 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
public TimedLock getTimedLock() {
return timedLock;
}
@Override
public boolean getDidOptOutOfFeatureAndCommunityEmails() {
return this.didOptOutOfFeatureAndCommunityEmails;
}
}
@@ -273,7 +273,7 @@ public class PreferenceObjectBasedNotificationSetTest {
Map<String, UserGroup> defaultTenantForServer = new ConcurrentHashMap<>();
defaultTenantForServer.put(serverName, defaultTenantForSingleServer);
store.createUser(username, email, new TimedLockImpl());
store.updateUser(new UserImpl(username, email, null, null, null, true, null, null, defaultTenantForServer,
store.updateUser(new UserImpl(username, email, null, null, null, true, false, null, null, defaultTenantForServer,
Collections.emptySet(), /* userGroupProvider */ null, new TimedLockImpl()));
}
@@ -51,6 +51,7 @@ public class UserStoreWithPersistenceTest {
private final String fullName = "Arno Nym";
private final String company = "SAP SE";
private final String email = "anonymous@sapsailing.com";
private final boolean didOptOutOfFeatureAndCommunityEmails = false;
private final String serverName = "dummyServer";
private final String prefKey = "pk";
private final String prefValue = "pv";
@@ -107,8 +108,9 @@ public class UserStoreWithPersistenceTest {
UserGroupImpl defaultTenant = createUserGroup();
HashMap<String, UserGroup> defaultTenantForServers = new HashMap<>();
defaultTenantForServers.put(serverName, defaultTenant);
store.updateUser(new UserImpl(username, email, fullName, company, Locale.GERMAN, false, null, null,
defaultTenantForServers, Collections.emptySet(), /* userGroupProvider */ null, new TimedLockImpl()));
store.updateUser(new UserImpl(username, email, fullName, company, Locale.GERMAN, false,
didOptOutOfFeatureAndCommunityEmails, null, null, defaultTenantForServers, Collections.emptySet(),
/* userGroupProvider */ null, new TimedLockImpl()));
newStore();
User savedUser = store.getUserByName(username);
assertEquals(username, savedUser.getName());
@@ -63,9 +63,9 @@ public interface AuthenticationManager {
*/
void logout();
void updateUserProperties(String fullName, String company, String localeName, String defaultTenantIdAsString,
AsyncCallback<UserDTO> callback);
void updateUserProperties(String fullName, String company, String localeName, Boolean didOptOutFeatureAndCommunityEmails,
String defaultTenantIdAsString, AsyncCallback<UserDTO> callback);
/**
* Provide the {@link AuthenticationContext} for the current user
*
@@ -203,27 +203,27 @@ public class AuthenticationManagerImpl implements AuthenticationManager {
}
@Override
public void updateUserProperties(String fullName, String company, String localeName, String defaultTenantIdAsString,
final AsyncCallback<UserDTO> callback) {
public void updateUserProperties(String fullName, String company, String localeName,
Boolean didOptOutFeatureAndCommunityEmails, String defaultTenantIdAsString, final AsyncCallback<UserDTO> callback) {
final UserDTO currentUser = getAuthenticationContext().getCurrentUser();
final String username = currentUser.getName();
final String locale = currentUser.getLocale();
userManagementWriteService.updateUserProperties(username, fullName, company, localeName, defaultTenantIdAsString,
new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
userManagementWriteService.updateUserProperties(username, fullName, company, localeName,
didOptOutFeatureAndCommunityEmails, defaultTenantIdAsString, new AsyncCallback<UserDTO>() {
@Override
public void onFailure(Throwable caught) {
callback.onFailure(caught);
}
@Override
public void onSuccess(UserDTO result) {
refreshUserInfo();
callback.onSuccess(result);
if (!Util.equalsWithNull(locale, localeName)) {
redirectIfLocaleIsSetAndLocaleIsNotGivenInTheURL(localeName);
}
}
});
@Override
public void onSuccess(UserDTO result) {
refreshUserInfo();
callback.onSuccess(result);
if (!Util.equalsWithNull(locale, localeName)) {
redirectIfLocaleIsSetAndLocaleIsNotGivenInTheURL(localeName);
}
}
});
}
/**
@@ -18,10 +18,9 @@ import com.sap.sse.security.ui.client.premium.PaywallResolver;
public class AuthenticationContextImpl implements AuthenticationContext {
private final UserDTO currentUser;
private final static UserDTO ANONYMOUS = new UserDTO("Anonymous", "", "", "", null, false, new ArrayList<AccountDTO>(),
new ArrayList<RoleWithSecurityDTO>(), /* default tenant */ null,
new ArrayList<WildcardPermissionWithSecurityDTO>(),
/* groups */ null, /* lockedUntil */ null);
private final static UserDTO ANONYMOUS = new UserDTO("Anonymous", "", "", "", null, false, false,
new ArrayList<AccountDTO>(), new ArrayList<RoleWithSecurityDTO>(), /* default tenant */ null,
new ArrayList<WildcardPermissionWithSecurityDTO>(), /* groups */ null, /* lockedUntil */ null);
private final UserService userService;
private final PaywallResolver paywallResolver;
@@ -67,8 +67,15 @@ public interface UserManagementWriteService extends UserManagementService {
void updateSimpleUserEmail(String username, String newEmail, String validationBaseURL)
throws UserManagementException, MailException, org.apache.shiro.authz.UnauthorizedException;
/**
* @param username must not be null
* @param fullName when null, no update will be processed to the respective parameter
* @param company when null, no update will be processed to the respective parameter
* @param locale when null, no update will be processed to the respective parameter
* @param didOptOutOfFeatureAndCommunityEmails when null, no update will be processed to the respective parameter
*/
UserDTO updateUserProperties(String username, String fullName, String company, String localeName,
String defaultTenantIdAsString)
Boolean didOptOutOfFeatureAndCommunityEmails, String defaultTenantIdAsString)
throws UserManagementException, org.apache.shiro.authz.UnauthorizedException;
void resetPassword(String username, String eMailAddress, String baseURL)
@@ -51,8 +51,15 @@ public interface UserManagementWriteServiceAsync extends UserManagementServiceAs
void updateSimpleUserEmail(String username, String newEmail, String validationBaseURL, AsyncCallback<Void> callback);
/**
* @param username must not be null
* @param fullName when null, no update will be processed to the respective parameter
* @param company when null, no update will be processed to the respective parameter
* @param locale when null, no update will be processed to the respective parameter
* @param didOptOutOfFeatureAndCommunityEmails when null, no update will be processed to the respective parameter
*/
void updateUserProperties(String username, String fullName, String company, String localeName,
String defaultTenantIdAsString, AsyncCallback<UserDTO> callback);
Boolean didOptOutOfFeatureAndCommunityEmails, String defaultTenantIdAsString, AsyncCallback<UserDTO> callback);
void createRoleDefinition(String roleDefinitionIdAsString, String name, AsyncCallback<RoleDefinitionDTO> callback);
@@ -164,6 +164,32 @@ public class AccessControlledButtonPanel extends Composite {
return addAction(text, updatePermissionCheck, callback);
}
/**
* Adds a secured action button, which is only visible if the current user has any
* {@link UserService#hasCurrentUserPermissionToDeleteAnyObjectOfType(HasPermissions) update permission} for the
* {@link HasPermissions type} provided in this {@link AccessControlledButtonPanel}'s constructor.
*
* @param text
* the {@link String text} to show on the button
* @param selectionModel
* the {@link SetSelectionModel<T> selection model} of the table; used to enable/disable the remove
* button when the selection becomes non-empty/empty, respectively and to display the number of elements
* selected in case the selection contains more than one element
* @param callback
* the {@link Command callback} to execute on button click, if permission is granted
*
* @return the created {@link SelectedElementsCountingButton} instance with optional confirmation
*/
public <T extends Named> Button addUpdateAction(final String text, final SetSelectionModel<T> selectionModel,
final Command callback) {
if (selectionModel == null) {
throw new IllegalArgumentException("Selection model for an update action must not be null");
}
final ClickHandler handler = wrap(updatePermissionCheck, callback);
final Button button = new SelectedElementsCountingButton<T>(text, selectionModel, handler);
return resolveButtonVisibility(updatePermissionCheck, button);
}
/**
* Adds an action button, which's visibility depends on the provided {@link Supplier permission check}.
*
@@ -233,4 +233,5 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages {
String clientCurrentlyLockedForUserCreation();
String unlockedSuccessfully();
String failedToUnlock();
String optOutOfFeatureAndCommunityEmails();
}
@@ -239,4 +239,5 @@ lockedUntil=Locked until
passwordAuthenticationCurrentlyLockedForUser=Password authentication is currently locked for this user due to too many failed login attempts. Please try again later.
clientCurrentlyLockedForUserCreation=Client is currently locked for user creation after too many user creations by the same client. Please try again later.
unlockedSuccessfully=Unlocked successfully
failedToUnlock=Failed to unlock
failedToUnlock=Failed to unlock
optOutOfFeatureAndCommunityEmails=Opt out of Feature and Community Updates emails
@@ -238,4 +238,5 @@ lockedUntil=Gesperrt bis
passwordAuthenticationCurrentlyLockedForUser=Passwort-Authentifizierung ist für diesen Benutzer derzeit aufgrund zu vieler fehlgeschlagener Versuche gesperrt. Bitter später erneut versuchen.
clientCurrentlyLockedForUserCreation=Benutzererstellung für den aktuellen Client ist derzeit wegen zu vieler neuer Nutzer vom selben Client gesperrt. Bitte später erneut versuchen.
unlockedSuccessfully=Erfolgreich entsperrt.
failedToUnlock=Entsperren fehlgeschlagen
failedToUnlock=Entsperren fehlgeschlagen
optOutOfFeatureAndCommunityEmails=Abmeldung von E-Mails mit Funktions- und Community-Updates
@@ -66,7 +66,7 @@ public class EditUserRolesAndPermissionsDialog extends DataEntryDialog<Void> {
}
private UserDTO createUserAdapter(final String selectedUsername, final RolesAndPermissionsForUserDTO dto) {
return new UserDTO(selectedUsername, null, null, null, null, false, null, dto.getRoles(), null,
return new UserDTO(selectedUsername, null, null, null, null, false, false, null, dto.getRoles(), null,
dto.getPermissions(), null, null);
}
@@ -9,6 +9,7 @@ import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
@@ -49,6 +50,7 @@ public class UserEditDialog extends DataEntryDialog<UserDTO> {
private final TextBox fullName;
private final TextBox company;
private final TextBox email;
private final CheckBox optOutOfFeatureAndCommunityEmailsCheckbox;
private final VerticalPanel accountPanels;
private final UserService userService;
@@ -73,6 +75,9 @@ public class UserEditDialog extends DataEntryDialog<UserDTO> {
this.email = createTextBox(userToEdit.getEmail(), 70);
this.fullName = createTextBox(userToEdit.getFullName(), 70);
this.company = createTextBox(userToEdit.getCompany(), 70);
this.optOutOfFeatureAndCommunityEmailsCheckbox = new CheckBox(stringMessages.optOutOfFeatureAndCommunityEmails(),
userToEdit.getDidOptOutOfFeatureAndCommunityEmails());
optOutOfFeatureAndCommunityEmailsCheckbox.setValue(userToEdit.getDidOptOutOfFeatureAndCommunityEmails());
this.accountPanels = new VerticalPanel();
for (AccountDTO a : userToEdit.getAccounts()) {
DecoratorPanel accountPanelDecorator = new DecoratorPanel();
@@ -155,8 +160,8 @@ public class UserEditDialog extends DataEntryDialog<UserDTO> {
permissions.add((WildcardPermissionWithSecurityDTO) permission);
}
final UserDTO user = new UserDTO(userToEdit.getName(), email.getText(), fullName.getText(), company.getText(),
userToEdit.getLocale(), userToEdit.isEmailValidated(), userToEdit.getAccounts(),
userToEdit.getRoles(), userToEdit.getDefaultTenant(), permissions,
userToEdit.getLocale(), userToEdit.isEmailValidated(), optOutOfFeatureAndCommunityEmailsCheckbox.getValue(),
userToEdit.getAccounts(), userToEdit.getRoles(), userToEdit.getDefaultTenant(), permissions,
userToEdit.getUserGroups(), userToEdit.getLockedUntil());
return user;
}
@@ -172,6 +177,8 @@ public class UserEditDialog extends DataEntryDialog<UserDTO> {
result.setWidget(2, 1, email);
result.setWidget(3, 0, new Label(stringMessages.company()));
result.setWidget(3, 1, company);
result.setWidget(4, 0, new Label(stringMessages.optOutOfFeatureAndCommunityEmails()));
result.setWidget(4, 1, optOutOfFeatureAndCommunityEmailsCheckbox);
result.setWidget(4, 0, accountPanels);
return result;
}
@@ -20,6 +20,7 @@ import com.google.gwt.cell.client.SafeHtmlCell;
import com.google.gwt.core.client.Callback;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.cellview.client.AbstractCellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
@@ -97,6 +98,14 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> {
TextColumn<UserDTO> fullNameColumn = new AbstractSortableTextColumn<UserDTO>(user->user.getFullName(), userColumnListHandler);
TextColumn<UserDTO> emailColumn = new AbstractSortableTextColumn<UserDTO>(user->user.getEmail(), userColumnListHandler);
TextColumn<UserDTO> emailValidatedColumn = new AbstractSortableTextColumn<UserDTO>(user->user.isEmailValidated() ? stringMessages.yes() : stringMessages.no(), userColumnListHandler);
TextColumn<UserDTO> optOutColumn = new AbstractSortableTextColumn<UserDTO>(user->user.getDidOptOutOfFeatureAndCommunityEmails() ? stringMessages.yes() : stringMessages.no(), userColumnListHandler);
optOutColumn.setSortable(true);
userColumnListHandler.setComparator(optOutColumn, new Comparator<UserDTO>() {
@Override
public int compare(UserDTO r1, UserDTO r2) {
return Boolean.compare(r1.getDidOptOutOfFeatureAndCommunityEmails(), r2.getDidOptOutOfFeatureAndCommunityEmails());
}
});
TextColumn<UserDTO> companyColumn = new AbstractSortableTextColumn<UserDTO>(user->user.getCompany(), userColumnListHandler);
Column<UserDTO, SafeHtml> groupsColumn = new Column<UserDTO, SafeHtml>(new SafeHtmlCell()) {
@Override
@@ -177,6 +186,9 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> {
strings.add(t.getFullName());
strings.add(t.getEmail());
strings.add(t.getCompany());
if (t.getDidOptOutOfFeatureAndCommunityEmails()) {
strings.add(stringMessages.optOutOfFeatureAndCommunityEmails());
}
Util.addAll(Util.map(t.getRoles(), RoleWithSecurityDTO::getName), strings);
Util.addAll(Util.map(t.getUserGroups(), StrippedUserGroupDTO::getName), strings);
return strings;
@@ -195,6 +207,7 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> {
table.addColumn(fullNameColumn, stringMessages.name());
table.addColumn(emailColumn, stringMessages.email());
table.addColumn(emailValidatedColumn, stringMessages.validated());
table.addColumn(optOutColumn, composeOptOutColumnHeaderWithTooltipOnHover(stringMessages));
table.addColumn(companyColumn, stringMessages.company());
table.addColumn(groupsColumn, stringMessages.groups());
table.addColumn(rolesColumn, stringMessages.roles());
@@ -205,6 +218,16 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> {
table.ensureDebugId("UsersTable");
}
private SafeHtml composeOptOutColumnHeaderWithTooltipOnHover(StringMessages stringMessages) {
final String fullTitle = stringMessages.optOutOfFeatureAndCommunityEmails();
final String tooltip = new SafeHtmlBuilder().appendEscaped(fullTitle).toSafeHtml().asString();
final SafeHtml baseHtml = SafeHtmlUtils.fromString(fullTitle.substring(0, 10) + "...");
return new SafeHtmlBuilder()
.appendHtmlConstant("<span title=\"" + tooltip + "\">")
.append(baseHtml)
.appendHtmlConstant("</ span>").toSafeHtml();
}
private AccessControlledActionsColumn<UserDTO, DefaultActionsImagesBarCell> composeUserActionColumn(
StringMessages stringMessages, ErrorReporter errorReporter) {
final HasPermissions type = SecuredSecurityTypes.USER;
@@ -338,8 +361,8 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> {
final UserEditDialog dialog = new UserEditDialog(originalUser, new DialogCallback<UserDTO>() {
@Override
public void ok(final UserDTO user) {
getUserManagementWriteService().updateUserProperties(user.getName(), user.getFullName(), user.getCompany(),
user.getLocale(),
getUserManagementWriteService().updateUserProperties(user.getName(), user.getFullName(),
user.getCompany(), user.getLocale(), user.getDidOptOutOfFeatureAndCommunityEmails(),
user.getDefaultTenant() != null ? user.getDefaultTenant().getId().toString() : null,
new AsyncCallback<UserDTO>() {
@Override
@@ -91,8 +91,9 @@ public class SecurityDTOFactory {
.collect(Collectors.toList());
userDTO = new UserDTO(user.getName(), user.getEmail(), user.getFullName(), user.getCompany(),
user.getLocale() != null ? user.getLocale().toLanguageTag() : null, user.isEmailValidated(),
accountDTOs, createRolesDTOs(filteredRoles, fromOriginalToStrippedDownUser,
fromOriginalToStrippedDownUserGroup, securityService, user),
user.getDidOptOutOfFeatureAndCommunityEmails(), accountDTOs,
createRolesDTOs(filteredRoles, fromOriginalToStrippedDownUser, fromOriginalToStrippedDownUserGroup,
securityService, user),
/* default tenant filled in later */ null,
getSecuredPermissions(filteredPermissions, user, securityService),
createStrippedUserGroupDTOsFromUserGroups(securityService.getUserGroupsOfUser(user),

Some files were not shown because too many files have changed in this diff Show More