diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java index 9fbab85af9d..d3083658c20 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/windfinder/AvailableWindFinderSpotCollections.java @@ -22,6 +22,7 @@ public enum AvailableWindFinderSpotCollections { KORNATEN("kornaten"), MUEGGELSEE("mueggelsee"), TEGERNSEE("tegernsee"), + TORTOLA("tortola"), AUCKLAND("auckland"); private final String name; diff --git a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardDTOCalculationReuseCacheTest.java b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardDTOCalculationReuseCacheTest.java index 5dc9fa6df49..cdff4336d56 100644 --- a/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardDTOCalculationReuseCacheTest.java +++ b/java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/LeaderboardDTOCalculationReuseCacheTest.java @@ -1,14 +1,18 @@ package com.sap.sailing.domain.test; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.Collections; + import org.junit.Test; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.Position; import com.sap.sailing.domain.common.impl.DegreePosition; +import com.sap.sailing.domain.common.orc.ORCPerformanceCurveCourse; import com.sap.sailing.domain.common.tracking.GPSFixMoving; import com.sap.sailing.domain.leaderboard.caching.LeaderboardDTOCalculationReuseCache; import com.sap.sailing.domain.tracking.GPSFixTrack; @@ -31,4 +35,18 @@ public class LeaderboardDTOCalculationReuseCacheTest { when(trackedRace.getWind(p, now)).thenReturn(null); assertNull(cache.getWind(trackedRace, competitor, now)); } + + @Test + public void testRaceSpecificityOfTotalORCCourseCaching() { + final TimePoint now = MillisecondsTimePoint.now(); + final LeaderboardDTOCalculationReuseCache cache = new LeaderboardDTOCalculationReuseCache(now); + final TrackedRace trackedRace1 = mock(TrackedRace.class); + final ORCPerformanceCurveCourse totalCourseRace1 = mock(ORCPerformanceCurveCourse.class); + when(totalCourseRace1.getLegs()).thenReturn(Collections.emptySet()); + final TrackedRace trackedRace2 = mock(TrackedRace.class); + final ORCPerformanceCurveCourse totalCourseRace2 = mock(ORCPerformanceCurveCourse.class); + when(totalCourseRace2.getLegs()).thenReturn(Collections.emptySet()); + assertSame(totalCourseRace1, cache.getTotalCourse(trackedRace1, ()->totalCourseRace1)); + assertSame(totalCourseRace2, cache.getTotalCourse(trackedRace2, ()->totalCourseRace2)); + } } diff --git a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java index 55820d2e83f..cbc4ada5dee 100755 --- a/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java +++ b/java/com.sap.sailing.domain.tractracadapter/src/com/sap/sailing/domain/tractracadapter/impl/RaceCourseReceiver.java @@ -146,6 +146,13 @@ public class RaceCourseReceiver extends AbstractReceiverWithQueue(ttControlPointsForAllOriginalEventControlPoints.get(cp), passingInstructions)); i++; } diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java index 36020ec4700..4469f492498 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/leaderboard/caching/LeaderboardDTOCalculationReuseCache.java @@ -101,7 +101,7 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea * thereof. This course will have any tracked leg adapters replaced by fixed leg descriptions with a fixed TWA and * distance as obtained upon the first call for the {@link #timePoint} from the underlying {@link TrackedRace}. */ - private ORCPerformanceCurveCourse totalCourse; + private final ConcurrentHashMap totalCourse; private final ConcurrentHashMap, Position> approximateWaypointPositions; @@ -156,6 +156,7 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea approximateWaypointPositions = new ConcurrentHashMap<>(); this.performanceCurvesPerCompetitor = new ConcurrentHashMap<>(); this.impliedWindPerCompetitor = new ConcurrentHashMap<>(); + this.totalCourse = new ConcurrentHashMap<>(); this.timePoint = timePoint; } @@ -214,10 +215,7 @@ public class LeaderboardDTOCalculationReuseCache implements WindLegTypeAndLegBea @Override public ORCPerformanceCurveCourse getTotalCourse(TrackedRace raceContext, Supplier totalCourseSupplier) { - if (totalCourse == null) { - totalCourse = fixORCPerformanceCurveCourse(totalCourseSupplier.get(), /* cache */ this); - } - return totalCourse; + return totalCourse.computeIfAbsent(raceContext, key->fixORCPerformanceCurveCourse(totalCourseSupplier.get(), /* cache */ this)); } private ORCPerformanceCurveCourse fixORCPerformanceCurveCourse(ORCPerformanceCurveCourse course, ORCPerformanceCurveCache cache) { diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveCache.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveCache.java index aee55334ddf..e6b97502f06 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveCache.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/ORCPerformanceCurveCache.java @@ -17,11 +17,15 @@ import com.sap.sse.common.TimePoint; public interface ORCPerformanceCurveCache extends AverageWindOnLegCache { /** - * If not yet computed, computes a copy of the total course supplied by the {@code totalCourseSupplier} where - * any adapted leg that would query a live {@link TrackedLeg} for TWA and distance is replaced by a leg of - * type {@link ORCPerformanceCurveLegImpl} of type {@link ORCPerformanceCurveLegTypes#TWA} with its TWA and - * distance set to the values obtained for this cache's time point, computed once when this call is made - * and no total course has been cached in this object yet. + * If not yet computed, computes a copy of the total course supplied by the {@code totalCourseSupplier} where any + * adapted leg that would query a live {@link TrackedLeg} for TWA and distance is replaced by a leg of type + * {@link ORCPerformanceCurveLegImpl} of type {@link ORCPerformanceCurveLegTypes#TWA} with its TWA and distance set + * to the values obtained for this cache's time point, computed once when this call is made and no total course for + * the {@code raceContext} has been cached in this object yet. + * + * @param totalCourseSupplier + * computes the {@link ORCPerformanceCurveCourse} representing the total course for race represented by + * {@code raceContext}. */ ORCPerformanceCurveCourse getTotalCourse(TrackedRace raceContext, Supplier totalCourseSupplier); diff --git a/java/com.sap.sailing.feature.p2build/scripts/analyzeLaunch.sh b/java/com.sap.sailing.feature.p2build/scripts/analyzeLaunch.sh deleted file mode 100755 index 6e54a0d1415..00000000000 --- a/java/com.sap.sailing.feature.p2build/scripts/analyzeLaunch.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -target_bundles=$(cat "$1" | grep 'key="target_bundles"' | sed -e 's/^.* value="\([^"]*\)"\/>/\1/' | sed -e 's/,/\n/g' | sed -e 's/^\(.*\)@\(.*\):\(.*\)$/\1 \2 \3/') -workspace_bundles=$(cat "$1" | grep 'key="workspace_bundles"' | sed -e 's/^.* value="\([^"]*\)"\/>/\1/' | sed -e 's/,/\n/g' | sed -e 's/^\(.*\)@\(.*\):\(.*\)$/\1 \2 \3/') -echo " *** Target Bundles ***" -echo "$target_bundles" | sort -echo " *** Workspace Bundles ***" -echo "$workspace_bundles" | sort - diff --git a/java/com.sap.sailing.feature.p2build/scripts/analyzeProduct.sh b/java/com.sap.sailing.feature.p2build/scripts/analyzeProduct.sh index 0c22346e9a1..0d570e4ec2e 100755 --- a/java/com.sap.sailing.feature.p2build/scripts/analyzeProduct.sh +++ b/java/com.sap.sailing.feature.p2build/scripts/analyzeProduct.sh @@ -1,12 +1,21 @@ #!/bin/bash # Call like this: analyzeProduct.sh [ ...] -# Will output two lines in format -# -# +# Updates Eclipse .launch files with the bundles needed for starting an SAP Sailing server based on the current feature.xml. +# The .launch files must be in the workspace format that was introduced with Eclipse 2019-12. The script prints an error when no matching +# replacement section could be found. +# Will output two sections in format +# +# +# +# +# " else # contribute to workspace_bundles - workspace_bundles="${workspace_bundles},${bundle_spec_for_launch}" + workspace_bundles="${workspace_bundles}${NL}" fi done done echo ' *** Target Bundles ***' -echo "" +echo "${target_bundles}" echo ' *** Workspace Bundles ***' -echo "" +echo "${workspace_bundles}" # Now patch the .launch file if provided while [ "$2" != "" ]; do - echo "Patching $2 ..." - if echo "$2" | grep -q winddbTest; then - patched_workspace_bundles="${workspace_bundles},com.sap.sailing.server.gateway.test.support@default:default" + if grep -q key=\"target_bundles\" "$2"; then + echo "Not patching $2 ... please use script for eclipse 2019-09 or older" else - patched_workspace_bundles="${workspace_bundles}" + echo "Patching $2 ..." + if echo "$2" | grep -q winddbTest; then + patched_workspace_bundles="${workspace_bundles}${NL}${NL}" + else + patched_workspace_bundles="${workspace_bundles}" + fi + selected_target_bundles="${target_bundles}${NL}<\/setAttribute>" + patched_workspace_bundles="${patched_workspace_bundles}${NL}<\/setAttribute>" + # Used Perl CLI options: + #0 -> specifies the record separator, as you alread found out, it defaults to \0 so it does not terminate before the end of the text file. Ensures that the regular expression is applied over the whole file. + #p -> apply looping wrapper, see perl man page + #e -> denotes the (regular) expression that is goint ot be applied. + #i -> inplace editing of files + perl -i -p0e "s/.*?<\/setAttribute>/${selected_target_bundles}/s" "$2" + perl -i -p0e "s/.*?<\/setAttribute>/${patched_workspace_bundles}/s" "$2" + # remove eventuelly created bak files (this happens at least on windows platform) + rm -f "$2.bak" fi - sed -i 's/ reloadLeaderboardForTable(leaderboardDTO.getName()), stringMessages); leaderboardActionColumn.addAction(LeaderboardConfigImagesBarCell.ACTION_CHANGE_OWNERSHIP, CHANGE_OWNERSHIP, - config::openOwnershipDialog); + new Consumer() { + @Override + public void accept(StrippedLeaderboardDTOWithSecurity t) { + config.openOwnershipDialog(t); + } + }); final EditACLDialog.DialogConfig configACL = EditACLDialog.create( userService.getUserManagementService(), type, leaderboardDTO -> reloadLeaderboardForTable(leaderboardDTO.getName()), stringMessages); leaderboardActionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL, - configACL::openACLDialog); + new Consumer() { + @Override + public void accept(StrippedLeaderboardDTOWithSecurity t) { + configACL.openACLDialog(t); + } + }); leaderboardTable.addColumn(selectionCheckboxColumn, selectionCheckboxColumn.getHeader()); leaderboardTable.addColumn(linkColumn, stringMessages.name()); leaderboardTable.addColumn(leaderboardDisplayNameColumn, stringMessages.displayName()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java index 5b9d758a596..8610f22d924 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/TrackedRacesListComposite.java @@ -178,7 +178,6 @@ public class TrackedRacesListComposite extends AbstractTrackedRacesListComposite if (!userService.hasPermission(race, SecuredDomainType.TrackedRaceActions.EXPORT)) { canExportAll = false; } - } btnSetDelayToLive.setEnabled(canUpdateAll); btnRemoveRace.setEnabled(canDeleteAll); diff --git a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/TestEnvironmentConfiguration.java b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/TestEnvironmentConfiguration.java index d84bb52ee39..9891de7b908 100644 --- a/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/TestEnvironmentConfiguration.java +++ b/java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/TestEnvironmentConfiguration.java @@ -131,67 +131,51 @@ public class TestEnvironmentConfiguration { if (TestEnvironmentConfiguration.instance != null) { return TestEnvironmentConfiguration.instance; } - Document document = readTestConfiguration(); - Element testEnvironmentNode = document.getDocumentElement(); testEnvironmentNode.normalize(); - String contextRoot = XMLHelper.getContentTextNS(testEnvironmentNode, CONTEXT_ROOT, NAMESPACE_URI); String screenshotsFolder = XMLHelper.getContentTextNS(testEnvironmentNode, SCREENSHOTS_FOLDER, NAMESPACE_URI); Map systemProperties = createSystemProperties(testEnvironmentNode); List driverDefinitions = createDriverDefinitions(testEnvironmentNode); - return new TestEnvironmentConfiguration(contextRoot, screenshotsFolder, systemProperties, driverDefinitions); } private static synchronized Document readTestConfiguration() throws ParserConfigurationException, SAXException, IOException { String path = System.getProperty(TEST_ENVIRONMENT_CONFIGURATION); - SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFactory.newSchema(new StreamSource(TEST_ENVIRONMENT_SCHEMA)); - DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setNamespaceAware(true); builderFactory.setSchema(schema); - DocumentBuilder builder = builderFactory.newDocumentBuilder(); InputSource source = new InputSource(new FileInputStream(path)); - return builder.parse(source); } private static Map createSystemProperties(Element testEnvironmentNode) { Element systemPropertiesNode = XMLHelper.getElementNS(testEnvironmentNode, SYSTEM_PROPERTIES, NAMESPACE_URI); - if (systemPropertiesNode == null) { return Collections.emptyMap(); } - Map properties = new HashMap<>(); List systemPropertyNodes = XMLHelper.getElementsNS(systemPropertiesNode, SYSTEM_PROPERTY, NAMESPACE_URI); - for(Element systemPropertyNode : systemPropertyNodes) { String propertyName = XMLHelper.getContentTextNS(systemPropertyNode, PARAMETER_NAME, NAMESPACE_URI); String propertyValue = XMLHelper.getContentTextNS(systemPropertyNode, PARAMETER_VALUE, NAMESPACE_URI); - properties.put(propertyName, propertyValue); } - return properties; } private static List createDriverDefinitions(Element testEnvironmentNode) { List definitions = new LinkedList<>(); - List driverDefinitionNodes = XMLHelper.getElementsNS(testEnvironmentNode, DRIVER_DEFINITION, NAMESPACE_URI); - for (Element driverDefinitionNode : driverDefinitionNodes) { definitions.add(createDriverDefinition(driverDefinitionNode)); } - return definitions; } diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java index 748c6162eee..1ea5c45035d 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/AbstractJaxRsApiTest.java @@ -90,6 +90,7 @@ public abstract class AbstractJaxRsApiTest { doReturn(getSecurityService()).when(boatsResource).getSecurityService(); competitorsResource = spyResource(new DummyCompetitorsResource()); doReturn(getSecurityService()).when(competitorsResource).getSecurityService(); + doReturn(racingEventService).when(competitorsResource).getService(); doReturn(RaceLogTrackingAdapterFactory.INSTANCE.getAdapter(racingEventService.getBaseDomainFactory())) .when(leaderboardsResource).getRaceLogTrackingAdapter(); } diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/BoatResourceTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/BoatResourceTest.java index e0368332716..3488ebac8fd 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/BoatResourceTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/BoatResourceTest.java @@ -12,6 +12,7 @@ import com.sap.sailing.domain.base.impl.BoatClassImpl; import com.sap.sailing.domain.base.impl.DynamicBoat; import com.sap.sailing.server.gateway.deserialization.impl.BoatJsonDeserializer; import com.sap.sailing.server.gateway.deserialization.impl.Helpers; +import com.sap.sse.rest.StreamingOutputUtil; public class BoatResourceTest extends AbstractJaxRsApiTest { private final String id = "af855a56-9726-4a9c-a77e-da955bd289be"; @@ -28,12 +29,10 @@ public class BoatResourceTest extends AbstractJaxRsApiTest { @Test public void testGetBoatAsJson() throws Exception { - String jsonString = boatsResource.getBoat(id, null, null).getEntity().toString(); - + String jsonString = StreamingOutputUtil.getEntityAsString(boatsResource.getBoat(id, null, null).getEntity()); BoatJsonDeserializer boatJsonDeserializer = BoatJsonDeserializer.create(racingEventService.getBaseDomainFactory()); JSONObject jsonObject = Helpers.toJSONObjectSafe(JSONValue.parse(jsonString)); DynamicBoat boat = boatJsonDeserializer.deserialize(jsonObject); - assertTrue(boat.getId().equals(id)); assertTrue(boat.getName().equals(boatName)); assertTrue(boat.getSailID().equals(sailId)); diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/CompetitorsResourceTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/CompetitorsResourceTest.java index 7bad57e6289..7469b5af7a3 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/CompetitorsResourceTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/CompetitorsResourceTest.java @@ -1,6 +1,6 @@ package com.sap.sailing.server.gateway.test.jaxrs; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import java.util.Collections; @@ -14,6 +14,7 @@ import com.sap.sailing.domain.base.impl.NationalityImpl; import com.sap.sailing.domain.base.impl.PersonImpl; import com.sap.sailing.domain.base.impl.TeamImpl; import com.sap.sailing.server.gateway.deserialization.impl.Helpers; +import com.sap.sse.rest.StreamingOutputUtil; public class CompetitorsResourceTest extends AbstractJaxRsApiTest { private final String name = "Heiko KRĂ–GER"; @@ -31,12 +32,11 @@ public class CompetitorsResourceTest extends AbstractJaxRsApiTest { @Test public void testGetCompetitorAsJson() throws Exception { - String jsonString = competitorsResource.getCompetitor(id, null, null).getEntity().toString(); + String jsonString = StreamingOutputUtil.getEntityAsString(competitorsResource.getCompetitor(id, null, null).getEntity()); JSONObject json = Helpers.toJSONObjectSafe(JSONValue.parse(jsonString)); - assertTrue(json.get("id").equals(id)); - assertTrue(json.get("name").equals(name)); - assertTrue(json.get("nationality").equals(nationality)); - assertTrue(json.get("countryCode").equals(countryCode)); + assertEquals(id, json.get("id")); + assertEquals(name, json.get("name")); + assertEquals(nationality, json.get("nationality")); + assertEquals(countryCode, json.get("countryCode")); } - } diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/EventResourceTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/EventResourceTest.java index 04905fb595a..09cc79dd29d 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/EventResourceTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/EventResourceTest.java @@ -12,6 +12,7 @@ import java.text.ParseException; import java.util.Arrays; import java.util.UUID; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @@ -30,6 +31,7 @@ import com.sap.sailing.domain.common.ScoringSchemeType; import com.sap.sailing.domain.common.impl.DegreePosition; import com.sap.sailing.server.gateway.jaxrs.api.AbstractLeaderboardsResource; import com.sap.sse.InvalidDateException; +import com.sap.sse.rest.StreamingOutputUtil; public class EventResourceTest extends AbstractJaxRsApiTest { private String randomName; @@ -223,44 +225,44 @@ public class EventResourceTest extends AbstractJaxRsApiTest { return array.stream().filter(o -> ((JSONObject) o).get(attributeName).equals(value)).findFirst().isPresent(); } - private JSONObject getRegatta(String eventName) { + private JSONObject getRegatta(String eventName) throws WebApplicationException, IOException { Response regattasResponse = regattasResource.getRegatta(eventName, null); - return toJSONObject((String) regattasResponse.getEntity()); + return toJSONObject(StreamingOutputUtil.getEntityAsString(regattasResponse.getEntity())); } - private boolean isValidCreateEventResponse(Response response) { + private boolean isValidCreateEventResponse(Response response) throws WebApplicationException, IOException { String id = getIdFromCreateEventResponse(response); return validateUUID(id); } - private JSONArray getCourseAreasOfEvent(String strEventId) { + private JSONArray getCourseAreasOfEvent(String strEventId) throws WebApplicationException, IOException { JSONObject objEvent = getEvent(strEventId); JSONArray arrCourseAreas = getCourseAreas(objEvent); return arrCourseAreas; } - private JSONObject getEvent(String strEventId) { + private JSONObject getEvent(String strEventId) throws WebApplicationException, IOException { String jsonEvent = getEventAsString(strEventId); JSONObject objEvent = toJSONObject(jsonEvent); return objEvent; } - private boolean leaderBoardWithNameExists(String name) { + private boolean leaderBoardWithNameExists(String name) throws WebApplicationException, IOException { Response leaderboardResponse = getLeaderboard(name); JSONObject objLeaderboard = getLeaderboardAsJsonObject(leaderboardResponse); String strLeaderboardName = (String) objLeaderboard.get("name"); return strLeaderboardName.equals(name); } - private JSONObject getLeaderboardAsJsonObject(Response leaderboardResponse) { - String strLeaderboardGroup = (String) leaderboardResponse.getEntity(); + private JSONObject getLeaderboardAsJsonObject(Response leaderboardResponse) throws WebApplicationException, IOException { + String strLeaderboardGroup = StreamingOutputUtil.getEntityAsString(leaderboardResponse.getEntity()); JSONObject objLeaderboardGroup = toJSONObject(strLeaderboardGroup); return objLeaderboardGroup; } - private JSONObject getLeaderboardGroup(String strDefaultLeaderboardGroupName) { + private JSONObject getLeaderboardGroup(String strDefaultLeaderboardGroupName) throws WebApplicationException, IOException { Response leaderboardGroupsResponse = leaderboardGroupsResource.getLeaderboardGroup(strDefaultLeaderboardGroupName); - return toJSONObject(leaderboardGroupsResponse.getEntity().toString()); + return toJSONObject(StreamingOutputUtil.getEntityAsString(leaderboardGroupsResponse.getEntity())); } private JSONArray getLeaderboardGroups(JSONObject objEvent) { @@ -287,12 +289,12 @@ public class EventResourceTest extends AbstractJaxRsApiTest { } - private String getIdFromCreateEventResponse(Response createEventResponse) { - return (String) toJSONObject((String) createEventResponse.getEntity()).get("eventid"); + private String getIdFromCreateEventResponse(Response createEventResponse) throws WebApplicationException, IOException { + return (String) toJSONObject(StreamingOutputUtil.getEntityAsString(createEventResponse.getEntity())).get("eventid"); } - private String getEventAsString(String eventId) { - return (String) eventsResource.getEvent(eventId, null).getEntity(); + private String getEventAsString(String eventId) throws WebApplicationException, IOException { + return StreamingOutputUtil.getEntityAsString(eventsResource.getEvent(eventId, null).getEntity()); } } diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceTest.java index 1996d8a397c..9a720ff21f2 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/LeaderboardsResourceTest.java @@ -38,6 +38,7 @@ import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sailing.server.gateway.jaxrs.api.AbstractLeaderboardsResource; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.rest.StreamingOutputUtil; public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { private Regatta regatta; @@ -87,7 +88,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - String jsonString = (String) leaderboardReponse.getEntity(); + String jsonString = StreamingOutputUtil.getEntityAsString(leaderboardReponse.getEntity()); Object obj= JSONValue.parse(jsonString); JSONObject jsonObject = (JSONObject) obj; String jsonLeaderboardName = (String) jsonObject.get("name"); @@ -106,7 +107,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - String jsonString = (String) leaderboardReponse.getEntity(); + String jsonString = StreamingOutputUtil.getEntityAsString(leaderboardReponse.getEntity()); Object obj= JSONValue.parse(jsonString); JSONObject jsonObject = (JSONObject) obj; String jsonLeaderboardName = (String) jsonObject.get("name"); @@ -119,7 +120,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse2 = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - String jsonString2 = (String) leaderboardReponse2.getEntity(); + String jsonString2 = StreamingOutputUtil.getEntityAsString(leaderboardReponse2.getEntity()); obj= JSONValue.parse(jsonString2); jsonObject = (JSONObject) obj; resultTimePoint = parseTimepointFromJsonNumber((Long) jsonObject.get("resultTimepoint")); @@ -131,7 +132,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Live, null, null, /* competitorAndBoatIdsOnly */ false); - String jsonString = (String) leaderboardReponse.getEntity(); + String jsonString = StreamingOutputUtil.getEntityAsString(leaderboardReponse.getEntity()); Object obj= JSONValue.parse(jsonString); JSONObject jsonObject = (JSONObject) obj; String jsonLeaderboardName = (String) jsonObject.get("name"); @@ -153,7 +154,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - String jsonString = (String) leaderboardReponse.getEntity(); + String jsonString = StreamingOutputUtil.getEntityAsString(leaderboardReponse.getEntity()); Object obj= JSONValue.parse(jsonString); JSONObject jsonObject = (JSONObject) obj; String jsonLeaderboardName = (String) jsonObject.get("name"); @@ -167,7 +168,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse2 = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - String jsonString2 = (String) leaderboardReponse2.getEntity(); + String jsonString2 = StreamingOutputUtil.getEntityAsString(leaderboardReponse2.getEntity()); Object obj2= JSONValue.parse(jsonString2); JSONObject jsonObject2 = (JSONObject) obj2; String jsonLeaderboardName2 = (String) jsonObject2.get("name"); @@ -185,7 +186,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardResponse = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - String jsonString = (String) leaderboardResponse.getEntity(); + String jsonString = StreamingOutputUtil.getEntityAsString(leaderboardResponse.getEntity()); Object obj = JSONValue.parse(jsonString); JSONObject jsonObject = (JSONObject) obj; String jsonLeaderboardName = (String) jsonObject.get("name"); @@ -199,7 +200,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse2 = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - jsonString = (String) leaderboardReponse2.getEntity(); + jsonString = StreamingOutputUtil.getEntityAsString(leaderboardReponse2.getEntity()); obj= JSONValue.parse(jsonString); jsonObject = (JSONObject) obj; JSONArray jsonCompetitors = (JSONArray) jsonObject.get("competitors"); @@ -209,7 +210,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse3 = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, maxCompetitorsCount, null, /* competitorAndBoatIdsOnly */ false); - jsonString = (String) leaderboardReponse3.getEntity(); + jsonString = StreamingOutputUtil.getEntityAsString(leaderboardReponse3.getEntity()); obj= JSONValue.parse(jsonString); jsonObject = (JSONObject) obj; jsonCompetitors = (JSONArray) jsonObject.get("competitors"); @@ -219,7 +220,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { Response leaderboardReponse4 = leaderboardsResource.getLeaderboard(regatta.getName(), AbstractLeaderboardsResource.ResultStates.Final, null, null, /* competitorAndBoatIdsOnly */ false); - jsonString = (String) leaderboardReponse4.getEntity(); + jsonString = StreamingOutputUtil.getEntityAsString(leaderboardReponse4.getEntity()); obj= JSONValue.parse(jsonString); jsonObject = (JSONObject) obj; jsonCompetitors = (JSONArray) jsonObject.get("competitors"); @@ -234,7 +235,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { final boolean allowPartialImport = true; Response leaderboardResponse = importScores(validityTimePoint, comment, allowRaceDefaultsByOrder, allowPartialImport); assertEquals(Status.OK.getStatusCode(), leaderboardResponse.getStatus()); - final JSONObject jsonObject = (JSONObject) JSONValue.parse((String) leaderboardResponse.getEntity()); + final JSONObject jsonObject = (JSONObject) JSONValue.parse(StreamingOutputUtil.getEntityAsString(leaderboardResponse.getEntity())); assertNotNull(jsonObject); assertFalse((Boolean) jsonObject.get("complete")); assertEquals(comment, regattaLeaderboard.getScoreCorrection().getComment()); @@ -252,7 +253,7 @@ public class LeaderboardsResourceTest extends AbstractJaxRsApiTest { final boolean allowPartialImport = false; Response leaderboardResponse = importScores(validityTimePoint, comment, allowRaceDefaultsByOrder, allowPartialImport); assertEquals(Status.CONFLICT.getStatusCode(), leaderboardResponse.getStatus()); - final JSONObject jsonObject = (JSONObject) JSONValue.parse((String) leaderboardResponse.getEntity()); + final JSONObject jsonObject = (JSONObject) JSONValue.parse(StreamingOutputUtil.getEntityAsString(leaderboardResponse.getEntity())); assertNotNull(jsonObject); assertFalse((Boolean) jsonObject.get("complete")); assertEquals(null, regattaLeaderboard.getScoreCorrection().getComment()); diff --git a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java index 801410562d6..17067d6b832 100644 --- a/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java +++ b/java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java @@ -48,6 +48,7 @@ import com.sap.sailing.domain.ranking.OneDesignRankingMetric; import com.sap.sse.common.Color; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.rest.StreamingOutputUtil; import com.sap.sse.security.SecurityService; import com.sap.sse.security.interfaces.UserImpl; import com.sap.sse.security.shared.Account; @@ -124,17 +125,13 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { @Test public void testGetRegattas() throws Exception { Response regattasResponse = regattasResource.getRegattas(); - - String jsonString = (String) regattasResponse.getEntity(); + String jsonString = StreamingOutputUtil.getEntityAsString(regattasResponse.getEntity()); Object obj = JSONValue.parse(jsonString); JSONArray array = (JSONArray) obj; - assertTrue(array.size() == 2); - JSONObject firstElement = (JSONObject) array.get(0); String jsonName = (String) firstElement.get("name"); String jsonBoatClass = (String) firstElement.get("boatclass"); - assertTrue(closedRegattaName.equals(jsonName) || openRegattaName.equals(jsonName)); assertTrue(boatClassName.equals(jsonBoatClass)); } @@ -149,7 +146,7 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { @Test public void testGetRegatta() throws Exception { Response regattaResponse = regattasResource.getRegatta(closedRegattaName, null); - String jsonString = (String) regattaResponse.getEntity(); + String jsonString = StreamingOutputUtil.getEntityAsString(regattaResponse.getEntity()); assertNotNull(jsonString); String readRegattaName = (String) ((JSONObject) JSONValue.parse(jsonString)).get("name"); assertEquals(closedRegattaName, readRegattaName); @@ -162,31 +159,25 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { User user = new UserImpl("admin", "noreply@sapsailing.com", null, new ArrayList(0), null); setUser(user); when(securityService.getCurrentUser()).thenReturn(user); - Response response = regattasResource.createAndAddCompetitor(closedRegattaName, boatClassName, null, "GER", "#F00", flagImageUri, teamImageUri, null, null, null, competitorName1, competitorShortName1, null, deviceUuid, null); - assertTrue(response.getStatus() + ": " + response.getEntity().toString(), + assertTrue(response.getStatus() + ": " + StreamingOutputUtil.getEntityAsString(response.getEntity()), response.getStatus() == Status.OK.getStatusCode()); assertTrue(regattasResource.getService() == racingEventService); - response = regattasResource.createAndAddCompetitor(closedRegattaName, boatClassName, null, "GER", "#0F0", flagImageUri, teamImageUri, null, null, null, competitorName2, competitorShortName2, null, deviceUuid, null); - assertTrue(response.getStatus() + ": " + response.getEntity().toString(), + assertTrue(response.getStatus() + ": " + StreamingOutputUtil.getEntityAsString(response.getEntity()), response.getStatus() == Status.OK.getStatusCode()); - Regatta regatta = racingEventService.getRegattaByName(closedRegattaName); Iterator cit = regatta.getAllCompetitors().iterator(); Competitor readCompetitor = cit.next(); assertNotNull(readCompetitor); - assertTrue( - competitorName1.equals(readCompetitor.getName()) || competitorName2.equals(readCompetitor.getName())); + assertTrue(competitorName1.equals(readCompetitor.getName()) || competitorName2.equals(readCompetitor.getName())); readCompetitor = cit.next(); assertNotNull(readCompetitor); - assertTrue( - competitorName1.equals(readCompetitor.getName()) || competitorName2.equals(readCompetitor.getName())); - + assertTrue(competitorName1.equals(readCompetitor.getName()) || competitorName2.equals(readCompetitor.getName())); Iterator citForRemove = regatta.getAllCompetitors().iterator(); citForRemove.forEachRemaining(competitor -> regattasResource.removeCompetitor(closedRegattaName, competitor.getId().toString(), null)); @@ -201,7 +192,7 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { Response response = regattasResource.createAndAddCompetitor(openRegattaName, boatClassName, null, "GER", "#F00", flagImageUri, teamImageUri, null, null, null, competitorName1, competitorShortName1, null, deviceUuid, secret); - assertTrue(response.getStatus() + ": " + response.getEntity().toString(), + assertTrue(response.getStatus() + ": " + StreamingOutputUtil.getEntityAsString(response.getEntity()), response.getStatus() == Status.OK.getStatusCode()); assertTrue(regattasResource.getService() == racingEventService); @@ -213,29 +204,25 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { public void testCompetitorRegistrationAnonymousOnOpenRegattaWrongSecret() throws Exception { doReturn(securityService).when(regattasResource).getService(SecurityService.class); setUser(null); - Response response = regattasResource.createAndAddCompetitor(openRegattaName, boatClassName, null, "GER", "#F00", flagImageUri, teamImageUri, null, null, null, competitorName1, competitorShortName1, null, deviceUuid, "WRONGSECRET"); - assertTrue(response.getStatus() + ": " + response.getEntity().toString(), + assertTrue(response.getStatus() + ": " + StreamingOutputUtil.getEntityAsString(response.getEntity()), response.getStatus() == Status.FORBIDDEN.getStatusCode()); } @Test public void testCompetitorRegistrationAuthenticatedOnOpenRegatta() throws Exception { doReturn(securityService).when(regattasResource).getService(SecurityService.class); - User user = new UserImpl("max", "noreply@sapsailing.com", null, new ArrayList(0), null); setUser(user); Regatta regatta = racingEventService.getRegattaByName(openRegattaName); - Response response = regattasResource.createAndAddCompetitor(openRegattaName, boatClassName, null, "GER", "#F00", flagImageUri, teamImageUri, null, null, null, competitorName1, competitorShortName1, null, deviceUuid, secret); - assertTrue(response.getStatus() + ": " + response.getEntity().toString(), + assertTrue(response.getStatus() + ": " + StreamingOutputUtil.getEntityAsString(response.getEntity()), response.getStatus() == Status.OK.getStatusCode()); assertTrue(regattasResource.getService() == racingEventService); - regatta = racingEventService.getRegattaByName(openRegattaName); testResponseOfOpenRegattaCompetitorRegistration(regatta); } diff --git a/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF index 9b7b6336679..4f452f82515 100644 --- a/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF @@ -63,7 +63,8 @@ Require-Bundle: com.sap.sailing.domain, com.sun.xml.bind.jaxb-impl;bundle-version="2.3.0", com.sap.sailing.server.interface;bundle-version="1.0.0", org.mongodb.mongo-java-driver;bundle-version="3.6.4", - com.sap.sailing.shared.server + com.sap.sailing.shared.server, + com.sap.sailing.shared.server.gateway Bundle-ClassPath: . Web-ContextPath: /sailingserver Export-Package: com.sap.sailing.server.gateway, diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/AbstractJsonPostServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/AbstractJsonPostServlet.java index 2ba01682497..5bb69f0aef7 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/AbstractJsonPostServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/AbstractJsonPostServlet.java @@ -63,9 +63,7 @@ public abstract class AbstractJsonPostServlet extends Abstr for(String name : optionalParameters){ parameterValues.put(name, req.getParameter(name)); } - RequestT domainObject = null; - if (getRequestDeserializer() != null) { try { logger.fine("Post issued to " + this.getClass().getName()); @@ -82,7 +80,6 @@ public abstract class AbstractJsonPostServlet extends Abstr return; } } - ResponseT responseObject = null; try { responseObject = process(parameterValues, domainObject); @@ -92,11 +89,10 @@ public abstract class AbstractJsonPostServlet extends Abstr e.printStackTrace(); return; } - setJsonResponseHeader(resp); resp.setStatus(HttpServletResponse.SC_OK); if (getResponseSerializer() != null && responseObject != null) { - resp.getWriter().write(getResponseSerializer().serialize(responseObject).toJSONString()); + getResponseSerializer().serialize(responseObject).writeJSONString(resp.getWriter()); logger.fine(String.format("Created %s as result of gateway request", responseObject.toString())); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java index 4f734d7facd..8be4a8cc309 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/rc/AddEntryToRaceLogJsonPostServlet.java @@ -2,13 +2,13 @@ package com.sap.sailing.server.gateway.impl.rc; import java.io.BufferedReader; import java.io.IOException; +import java.io.Writer; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletConfig; import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -157,18 +157,18 @@ public class AddEntryToRaceLogJsonPostServlet extends AbstractJsonHttpServlet { Iterable eventsToSendBackToClient) throws IOException { JsonSerializer serializer = RaceLogEventSerializer.create(new CompetitorJsonSerializer(), new DeviceIdentifierJsonSerializer(deviceJsonServiceFinder)); - ServletOutputStream outputStream = response.getOutputStream(); + final Writer writer = response.getWriter(); boolean first = true; - outputStream.write('['); + writer.write('['); for (RaceLogEvent eventToSendBackToClient : eventsToSendBackToClient) { if (first) { first = false; } else { - outputStream.write(','); + writer.write(','); } - outputStream.write(serializer.serialize(eventToSendBackToClient).toJSONString().getBytes()); + serializer.serialize(eventToSendBackToClient).writeJSONString(writer); } - outputStream.write(']'); + writer.write(']'); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java index 042603ba79f..a84e1b1d487 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/AbstractSailingServerResource.java @@ -7,14 +7,9 @@ import java.util.Arrays; import java.util.Optional; import java.util.stream.StreamSupport; -import javax.servlet.ServletContext; -import javax.ws.rs.core.Context; - import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; -import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.base.RaceColumn; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.common.ScoreCorrectionProvider; @@ -22,38 +17,9 @@ import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapter; import com.sap.sailing.domain.racelogtracking.RaceLogTrackingAdapterFactory; import com.sap.sailing.domain.tracking.DynamicTrackedRegatta; import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.server.interfaces.RacingEventService; -import com.sap.sailing.shared.server.SharedSailingData; -import com.sap.sse.InvalidDateException; -import com.sap.sse.common.TimePoint; -import com.sap.sse.common.TypeBasedServiceFinderFactory; -import com.sap.sse.common.impl.MillisecondsTimePoint; -import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; -import com.sap.sse.replication.ReplicationService; -import com.sap.sse.security.SecurityService; -import com.sap.sse.util.DateParser; -import com.sun.jersey.api.core.ResourceContext; +import com.sap.sailing.shared.server.gateway.jaxrs.SharedAbstractSailingServerResource; -public abstract class AbstractSailingServerResource { - private static final String SLASH_ENCODING = "__"; - @Context ServletContext servletContext; - @Context ResourceContext resourceContext; - - protected ServletContext getServletContext() { - return servletContext; - } - - protected ResourceContext getResourceContext() { - return resourceContext; - } - - public T getService(Class clazz) { - final ServiceTracker tracker = getServiceTracker(clazz); - T service = tracker.getService(); - tracker.close(); - return service; - } - +public abstract class AbstractSailingServerResource extends SharedAbstractSailingServerResource { protected T[] getServices(Class clazz) { final ServiceTracker tracker = getServiceTracker(clazz); final Object[] objectServices = tracker.getServices(); @@ -71,40 +37,6 @@ public abstract class AbstractSailingServerResource { return tracker; } - protected BundleContext getBundleContext() { - final BundleContext context = (BundleContext) servletContext - .getAttribute(RestServletContainer.OSGI_RFC66_WEBBUNDLE_BUNDLECONTEXT_NAME); - return context; - } - - protected TypeBasedServiceFinderFactory getServiceFinderFactory () { - return new CachedOsgiTypeBasedServiceFinderFactory(getBundleContext()); - } - - public RacingEventService getService() { - @SuppressWarnings("unchecked") - ServiceTracker tracker = (ServiceTracker) servletContext.getAttribute(RestServletContainer.RACING_EVENT_SERVICE_TRACKER_NAME); - return tracker.getService(); - } - - protected SharedSailingData getSharedSailingData() { - @SuppressWarnings("unchecked") - ServiceTracker tracker = (ServiceTracker) servletContext.getAttribute(RestServletContainer.SHARED_SAILING_DATA_TRACKER_NAME); - return tracker.getService(); - } - - protected SecurityService getSecurityService() { - @SuppressWarnings("unchecked") - ServiceTracker tracker = (ServiceTracker) servletContext.getAttribute(RestServletContainer.SECURITY_SERVICE_TRACKER_NAME); - return tracker.getService(); - } - - protected ReplicationService getReplicationService() { - @SuppressWarnings("unchecked") - ServiceTracker tracker = (ServiceTracker) servletContext.getAttribute(RestServletContainer.REPLICATION_SERVICE_TRACKER_NAME); - return tracker.getService(); - } - private Iterable getScoreCorrectionProviders() { return Arrays.asList(getServices(ScoreCorrectionProvider.class)); } @@ -114,62 +46,6 @@ public abstract class AbstractSailingServerResource { filter(scp->scp.getName().equals(scoreCorrectionProviderName)).findAny(); } - protected Regatta findRegattaByName(String regattaName) { - Regatta regatta = getService().getRegattaByName(regattaName); - if (regatta == null && regattaName.contains(SLASH_ENCODING)) { - regatta = getService().getRegattaByName(regattaName.replaceAll(SLASH_ENCODING, "/")); - } - return regatta; - } - - protected RaceColumn findRaceColumnByName(Regatta regatta, String raceColumnName) { - RaceColumn raceColumn = regatta.getRaceColumnByName(raceColumnName); - if (raceColumn == null && raceColumnName.contains(SLASH_ENCODING)) { - raceColumn = regatta.getRaceColumnByName(raceColumnName.replaceAll(SLASH_ENCODING, "/")); - } - return raceColumn; - } - - protected Fleet findFleetByName(RaceColumn raceColumn, String fleetName) { - Fleet fleet = raceColumn.getFleetByName(fleetName); - if (fleet == null && fleetName.contains(SLASH_ENCODING)) { - fleet = raceColumn.getFleetByName(fleetName.replaceAll(SLASH_ENCODING, "/")); - } - return fleet; - } - - protected RaceDefinition findRaceByName(Regatta regatta, String raceName) { - RaceDefinition result = null; - if (regatta != null) { - result = regatta.getRaceByName(raceName); - if (result == null && raceName.contains(SLASH_ENCODING)) { - result = regatta.getRaceByName(raceName.replaceAll(SLASH_ENCODING, "/")); - } - } - return result; - } - - protected TimePoint parseTimePoint(String isoTime, Long timeAsMillis, TimePoint defaultTime) throws InvalidDateException { - TimePoint timePoint; - if (isoTime != null && isoTime.length() > 0) { - timePoint = new MillisecondsTimePoint(DateParser.parse(isoTime).getTime()); - } else { - timePoint = timeAsMillis != null ? new MillisecondsTimePoint(timeAsMillis) : defaultTime; - } - return timePoint; - } - - protected TrackedRace findTrackedRace(String regattaName, String raceName) { - Regatta regatta = findRegattaByName(regattaName); - final TrackedRace trackedRace; - if (regatta == null) { - trackedRace = null; - } else { - trackedRace = findTrackedRace(regatta, raceName); - } - return trackedRace; - } - protected TrackedRace findTrackedRace(Regatta regatta, String raceName) { final TrackedRace trackedRace; final RaceDefinition race = findRaceByName(regatta, raceName); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatClassesResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatClassesResource.java index dadaff88285..5b05244e17f 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatClassesResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatClassesResource.java @@ -28,7 +28,7 @@ public class BoatClassesResource extends AbstractSailingServerResource { final JSONObject jsonBoatClass = boatClassJsonSerializer.serialize(boatClass); result.add(jsonBoatClass); } - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(result)).build(); } @GET @@ -42,9 +42,8 @@ public class BoatClassesResource extends AbstractSailingServerResource { .entity("Could not find a boat with id '" + StringEscapeUtils.escapeHtml(boatClassName) + "'.") .type(MediaType.TEXT_PLAIN).build(); } else { - BoatClassJsonSerializer boatClassJsonSerializer = new BoatClassJsonSerializer(); - String jsonString = boatClassJsonSerializer.serialize(boatClass).toJSONString(); - response = Response.ok(jsonString).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + final BoatClassJsonSerializer boatClassJsonSerializer = new BoatClassJsonSerializer(); + response = Response.ok(streamingOutput(boatClassJsonSerializer.serialize(boatClass))).build(); } return response; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatsResource.java index 0a71577c203..b0838f8b74f 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/BoatsResource.java @@ -44,9 +44,7 @@ public class BoatsResource extends AbstractSailingServerResource { SecuredSecurityTypes.PublicReadableActions.READ_AND_READ_PUBLIC_ACTIONS); } BoatJsonSerializer boatJsonSerializer = BoatJsonSerializer.create(); - String jsonString = boatJsonSerializer.serialize(boat).toJSONString(); - response = Response.ok(jsonString).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + response = Response.ok(streamingOutput(boatJsonSerializer.serialize(boat))).build(); } return response; } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java index 6d37b3123c4..28a3174c403 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CompetitorsResource.java @@ -99,9 +99,7 @@ public class CompetitorsResource extends AbstractSailingServerResource { getSecurityService().checkCurrentUserHasOneOfExplicitPermissions(competitor, SecuredSecurityTypes.PublicReadableActions.READ_AND_READ_PUBLIC_ACTIONS); } - String jsonString = getCompetitorJSON(competitor).toJSONString(); - response = Response.ok(jsonString).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + response = Response.ok(streamingOutput(getCompetitorJSON(competitor))).build(); } return response; } @@ -125,8 +123,7 @@ public class CompetitorsResource extends AbstractSailingServerResource { TeamJsonSerializer teamJsonSerializer = new TeamJsonSerializer(new PersonJsonSerializer( new NationalityJsonSerializer())); JSONObject teamJson = teamJsonSerializer.serialize(team); - String json = teamJson.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(teamJson)).build(); } /** diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CountryCodesResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CountryCodesResource.java index 8fae7a8f496..364bd69d700 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CountryCodesResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CountryCodesResource.java @@ -3,7 +3,6 @@ package com.sap.sailing.server.gateway.jaxrs.api; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.json.simple.JSONArray; @@ -26,6 +25,6 @@ public class CountryCodesResource extends AbstractSailingServerResource { for (final CountryCode cc : factory.getAll()) { result.add(serializer.serialize(cc)); } - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(result)).build(); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CourseConfigurationResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CourseConfigurationResource.java index bc1029d2df8..1865b5a5b89 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CourseConfigurationResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/CourseConfigurationResource.java @@ -47,13 +47,13 @@ import com.sap.sailing.domain.coursetemplate.ControlPointWithMarkConfiguration; import com.sap.sailing.domain.coursetemplate.CourseConfiguration; import com.sap.sailing.domain.coursetemplate.CourseTemplate; import com.sap.sailing.domain.coursetemplate.FreestyleMarkConfiguration; -import com.sap.sailing.domain.coursetemplate.MarkRole; import com.sap.sailing.domain.coursetemplate.MarkConfiguration; import com.sap.sailing.domain.coursetemplate.MarkConfigurationRequestAnnotation; import com.sap.sailing.domain.coursetemplate.MarkConfigurationResponseAnnotation; import com.sap.sailing.domain.coursetemplate.MarkConfigurationVisitor; import com.sap.sailing.domain.coursetemplate.MarkPairWithConfiguration; import com.sap.sailing.domain.coursetemplate.MarkPropertiesBasedMarkConfiguration; +import com.sap.sailing.domain.coursetemplate.MarkRole; import com.sap.sailing.domain.coursetemplate.MarkTemplateBasedMarkConfiguration; import com.sap.sailing.domain.coursetemplate.RegattaMarkConfiguration; import com.sap.sailing.domain.coursetemplate.WaypointWithMarkConfiguration; @@ -175,7 +175,7 @@ public class CourseConfigurationResource extends AbstractSailingServerResource { .createCourseConfigurationFromRegatta(courseBase, regatta, raceColumnByName.getTrackedRace(fleetByName), tags); final JSONObject jsonResult = getCourseConfigurationJsonSerializer().serialize(courseConfiguration); - return Response.ok(jsonResult.toJSONString()).build(); + return Response.ok(streamingOutput(jsonResult)).build(); } @GET @@ -199,8 +199,7 @@ public class CourseConfigurationResource extends AbstractSailingServerResource { } final CourseConfiguration courseConfiguration = getService().getCourseAndMarkConfigurationFactory() .createCourseConfigurationFromTemplate(courseTemplate, regatta, tags, optionalNumberOfLaps); - String jsonString = getCourseConfigurationJsonSerializer().serialize(courseConfiguration).toJSONString(); - return Response.ok(jsonString).build(); + return Response.ok(streamingOutput(getCourseConfigurationJsonSerializer().serialize(courseConfiguration))).build(); } @@ -236,8 +235,8 @@ public class CourseConfigurationResource extends AbstractSailingServerResource { regatta, getService().getCourseAndMarkConfigurationFactory() .createCourseTemplateAndUpdatedConfiguration(courseConfiguration, tags, optionalUserGroupForNonDefaultMarkPropertiesOwnership)); - final String jsonString = getCourseConfigurationJsonSerializer().serialize(courseTemplate).toJSONString(); - return Response.ok(jsonString).build(); + return Response + .ok(streamingOutput(getCourseConfigurationJsonSerializer().serialize(courseTemplate))).build(); } private CourseConfiguration annotateWithLastKnownPositionInformation( @@ -401,8 +400,7 @@ public class CourseConfigurationResource extends AbstractSailingServerResource { final CourseConfiguration courseConfigurationResult = getService().getCourseAndMarkConfigurationFactory() .createCourseConfigurationFromRegatta(course, regatta, raceColumnByName.getTrackedRace(fleetByName), /* tagsToFilterMarkProperties */ null); - final String jsonString = getCourseConfigurationJsonSerializer().serialize(courseConfigurationResult).toJSONString(); - return Response.ok(jsonString).build(); + return Response.ok(streamingOutput(getCourseConfigurationJsonSerializer().serialize(courseConfigurationResult))).build(); } private synchronized JsonSerializer> getCourseConfigurationJsonSerializer() { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java index ead2bc6a9c4..4ab10dc74ff 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/DataMiningResource.java @@ -306,7 +306,9 @@ public class DataMiningResource extends AbstractSailingServerResource { } jsonResult.put("resultUnit", resultUnit != null && !resultUnit.isEmpty() ? resultUnit : "None"); jsonResult.put("results", resultValuesToJSON(result, numberExtractor, resultPlaces)); - response = Response.ok(jsonResult.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response + .ok(streamingOutput(jsonResult)) + .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } catch (NotJsonSerializableException e) { response = getNotSerializableErrorResponse(e.getNotSerializableClass()); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java index 473182ab70e..d98568051c2 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/EventsResource.java @@ -198,7 +198,7 @@ public class EventsResource extends AbstractSailingServerResource { eventAndLeaderboardGroupAndLeaderboard.getC().getRegatta().getRegistrationLinkSecret()); jsonResponse.put("leaderboard", eventAndLeaderboardGroupAndLeaderboard.getC().getName()); } - response = ok(jsonResponse.toJSONString(), MediaType.APPLICATION_JSON); + response = Response.ok(streamingOutput(jsonResponse)).build(); } return response; } @@ -334,9 +334,7 @@ public class EventsResource extends AbstractSailingServerResource { new VenueJsonSerializer(new CourseAreaJsonSerializer()), new LeaderboardGroupBaseJsonSerializer(), new TrackingConnectorInfoJsonSerializer()); JSONObject eventJson = eventSerializer.serialize(event); - - String json = eventJson.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(eventJson)).build(); } return response; } @@ -375,9 +373,7 @@ public class EventsResource extends AbstractSailingServerResource { filterByLeaderboard, filterByDayOffset, clientTimeZoneOffset, getService()); JSONObject raceStatesJson = eventRaceStatesSerializer.serialize( new Pair>(event, getService().getLeaderboards().values())); - String json = raceStatesJson.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + response = Response.ok(streamingOutput(raceStatesJson)).build(); } else { response = Response.status(Status.FORBIDDEN).build(); } @@ -710,10 +706,6 @@ public class EventsResource extends AbstractSailingServerResource { }); } - private Response ok(String message, String mediaType) { - return Response.ok(message).header("Content-Type", mediaType + ";charset=UTF-8").build(); - } - private Response getBadEventErrorResponse(String eventId) { return Response.status(Status.NOT_FOUND) .entity("Could not find an event with id '" + StringEscapeUtils.escapeHtml(eventId) + "'.") diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java index 628d57af444..41365f11db3 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/FileStorageResource.java @@ -14,7 +14,6 @@ import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.Status; @@ -71,17 +70,16 @@ public class FileStorageResource extends AbstractSailingServerResource { final JSONObject result = new JSONObject(); Response response; try { - getService().getFileStorageManagementService().getActiveFileStorageService() - .removeFile(new URI(uri)); + getService().getFileStorageManagementService().getActiveFileStorageService().removeFile(new URI(uri)); result.put("status", Status.OK.name()); - response = Response.ok().entity(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(result)).build(); } catch (NoCorrespondingServiceRegisteredException | OperationFailedException | InvalidPropertiesException | URISyntaxException | IOException e) { final String errorMessage = "Could not delete file with URI "+uri+": "+e.getMessage(); logger.log(Level.WARNING, "Could not delete file with URI "+uri, e); result.put("status", Status.BAD_REQUEST.name()); result.put("message", errorMessage); - response = Response.status(Status.BAD_REQUEST).entity(result.toJSONString()).build(); + response = Response.status(Status.BAD_REQUEST).entity(streamingOutput(result)).build(); } catch (UnauthorizedException e) { response = Response.status(Status.UNAUTHORIZED).entity(e.getMessage()).build(); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/GPSFixesResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/GPSFixesResource.java index b458e34cc59..6eb9da05ee0 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/GPSFixesResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/GPSFixesResource.java @@ -75,6 +75,6 @@ public class GPSFixesResource extends AbstractSailingServerResource { } catch (NoCorrespondingServiceRegisteredException e) { logger.log(Level.WARNING, "Could not store fix for device " + device); } - return Response.ok(answer.toJSONString()).build(); + return Response.ok(streamingOutput(answer)).build(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java index e1ca6487a58..cccf3e69b02 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardGroupsResource.java @@ -220,9 +220,7 @@ public class LeaderboardGroupsResource extends AbstractSailingServerResource { } } } - String json = jsonLeaderboardGroup.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + response = Response.ok(streamingOutput(jsonLeaderboardGroup)).build(); } else { response = Response.status(Status.FORBIDDEN).build(); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java index 3c08c42b62c..867dc8f4b03 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/LeaderboardsResource.java @@ -3,7 +3,6 @@ package com.sap.sailing.server.gateway.jaxrs.api; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; -import java.io.StringWriter; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Collections; @@ -186,8 +185,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { jsonLeaderboards.add(leaderboardName.getKey()); } } - String json = jsonLeaderboards.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonLeaderboards)).build(); } @GET @@ -218,12 +216,8 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { jsonLeaderboard = getLeaderboardJson(resultState, maxCompetitorsCount, requestTimePoint, leaderboard, timePoint, /* race column names */ null, /* race detail names */ null, competitorAndBoatIdsOnly, /* showOnlyActiveRacesForCompetitorIds */ null, skip); - StringWriter sw = new StringWriter(); - jsonLeaderboard.writeJSONString(sw); - String json = sw.getBuffer().toString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); - } catch (NoWindException | InterruptedException | ExecutionException | IOException e) { + response = Response.ok(streamingOutput(jsonLeaderboard)).build(); + } catch (NoWindException | InterruptedException | ExecutionException e) { response = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()) .type(MediaType.TEXT_PLAIN).build(); } @@ -567,8 +561,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { } JSONObject json = CompetitorsResource.getCompetitorJSON(competitor); json.put("displayName", leaderboard.getDisplayName(competitor)); - response = Response.ok(json.toJSONString()) - .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(json)).build(); } return response; } @@ -676,7 +669,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { raceLog.add(new RaceLogEndOfTrackingEventImpl(endOfTracking, author, raceLog.getCurrentPassId())); jsonResult.put("endoftracking", endOfTracking == null ? null : endOfTracking.asMillis()); } - result = Response.ok(jsonResult.toJSONString()).build(); + result = Response.ok(streamingOutput(jsonResult)).build(); } else { result = leaderboardAndRaceColumnAndFleetAndResponse.getResponse(); } @@ -717,7 +710,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { correctWindDirectionByMagneticDeclination == null ? true : correctWindDirectionByMagneticDeclination, getService().getPermissionAwareRaceTrackingHandler()); jsonResult.put("regatta", raceHandle.getRegatta().getName()); - result = Response.ok(jsonResult.toJSONString()).build(); + result = Response.ok(streamingOutput(jsonResult)).build(); } else { result = leaderboardAndRaceColumnAndFleetAndResponse.getResponse(); } @@ -817,7 +810,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { new ControlPointJsonSerializer( new MarkJsonSerializer(), new GateJsonSerializer(new MarkJsonSerializer()))))).serialize(autoCourse)); - result = Response.ok(jsonResult.toJSONString()).build(); + result = Response.ok(streamingOutput(jsonResult)).build(); } } else { result = leaderboardAndRaceColumnAndFleetAndResponse.getResponse(); @@ -1107,7 +1100,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { } @GET - @Produces(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8") @Path("{leaderboardName}/marks") public Response getMarksForRace(@PathParam("leaderboardName") String leaderboardName, @QueryParam(RaceLogServletConstants.PARAMS_RACE_COLUMN_NAME) String raceColumnName, @@ -1176,7 +1169,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { } JSONObject result = new JSONObject(); result.put("marks", array); - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(result)).build(); } @GET @@ -1213,8 +1206,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { responseJson.put("passId", result.getB()); responseJson.put("racingProcedureType", result.getC()==null?null:result.getC().name()); } - return Response.status(Status.OK) - .entity(responseJson.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(responseJson)).build(); } @PUT @@ -1255,8 +1247,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { racingProcedure==null?null:RacingProcedureType.valueOf(racingProcedure)); final JSONObject responseJson = new JSONObject(); responseJson.put("startTimeAsMillis", effectiveStartTime.asMillis()); - return Response.status(Status.OK) - .entity(responseJson.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(responseJson)).build(); } /** @@ -1379,7 +1370,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { } @GET - @Produces(MediaType.APPLICATION_JSON) + @Produces("application/json;charset=UTF-8") @Path("{leaderboardName}/marks/{markId}") public Response getMark(@PathParam("leaderboardName") String leaderboardName, @PathParam("markId") String markId, @@ -1416,7 +1407,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { final TimePoint now = MillisecondsTimePoint.now(); Position lastKnownPosition = getService().getMarkPosition(mark, (LeaderboardThatHasRegattaLike) leaderboard, now); final JSONObject result = markWithPositionSerializer.serialize(new Pair<>(mark, lastKnownPosition)); - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(result)).build(); } private final MarkJsonSerializer markSerializer = new MarkJsonSerializer(); @@ -1479,7 +1470,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { * @param raceColumnName optional; if omitted, all race column factors in the leaderboard will be reported, otherwise only the one requested */ @GET - @Produces(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8") @Path("{leaderboardName}/racecolumnfactors") public Response getRaceColumnFactors(@PathParam("leaderboardName") String leaderboardName, @QueryParam(RaceLogServletConstants.PARAMS_RACE_COLUMN_NAME) String raceColumnName) { final Response response; @@ -1505,7 +1496,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { .type(MediaType.TEXT_PLAIN).build(); } else { final JSONObject json = getJsonForColumnFactors(leaderboard, raceColumns); - response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(json)).build(); } } return response; @@ -1538,7 +1529,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { * after the change. This may be useful to validate the impact the change had on the resulting column factor */ @POST - @Produces(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8") @Path("{leaderboardName}/racecolumnfactors") public Response setExplicitRaceColumnFactor(@PathParam("leaderboardName") String leaderboardName, @QueryParam(RaceLogServletConstants.PARAMS_RACE_COLUMN_NAME) String raceColumnName, @QueryParam("explicit_factor") Double explicitFactor) { @@ -1559,7 +1550,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { } else { raceColumn.setFactor(explicitFactor); final JSONObject json = getJsonForColumnFactors(leaderboard, Collections.singleton(raceColumn)); - response = Response.ok(json.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(json)).build(); } } return response; @@ -1767,7 +1758,7 @@ public class LeaderboardsResource extends AbstractLeaderboardsResource { response = Response.status(Status.BAD_REQUEST); } } - return response.entity(result.toJSONString()).build(); + return response.entity(streamingOutput(result)).build(); } private JSONArray applyMatchedEntriesToLeaderboardScoreCorrections(Leaderboard leaderboard, diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MarkResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MarkResource.java index cf6bc3e3c07..a2352665863 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MarkResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MarkResource.java @@ -154,8 +154,7 @@ public class MarkResource extends AbstractSailingServerResource { regattaLog.add(event); JSONObject answer = new JSONObject(); answer.put(MARK_ID, markId.toString()); - response = Response.ok(answer.toJSONString()) - .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(answer)).build(); } return response; } @@ -285,8 +284,7 @@ public class MarkResource extends AbstractSailingServerResource { new CourseJsonSerializer(new CourseBaseJsonSerializer( new WaypointJsonSerializer(new ControlPointJsonSerializer(new MarkJsonSerializer(), new GateJsonSerializer(new MarkJsonSerializer()))))).serialize(updatedPublishedCourse)); - return Response.ok(jsonResult.toJSONString()) - .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonResult)).build(); } @POST diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataImportResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataImportResource.java index f5a7f354aa9..722d9af96f4 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataImportResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/MasterDataImportResource.java @@ -63,7 +63,7 @@ public class MasterDataImportResource extends AbstractSailingServerResource { jsonResponse.put("exportWind", exportWind); jsonResponse.put("exportDeviceConfigs", exportDeviceConfigs); jsonResponse.put("exportTrackedRacesAndStartTracking", exportTrackedRacesAndStartTracking); - response = Response.ok(jsonResponse.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(jsonResponse)).build(); } catch (UnauthorizedException e) { response = Response.status(Status.UNAUTHORIZED).build(); logger.warning(e.getMessage() + " for user: " + getSecurityService().getCurrentUser()); diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java index 0cb7346f2c4..ad0a5723010 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RegattasResource.java @@ -1,5 +1,8 @@ package com.sap.sailing.server.gateway.jaxrs.api; +import java.io.BufferedWriter; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.io.Serializable; import java.net.URI; import java.net.URISyntaxException; @@ -33,6 +36,7 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.StreamingOutput; import org.apache.commons.lang.StringEscapeUtils; import org.apache.shiro.SecurityUtils; @@ -289,8 +293,7 @@ public class RegattasResource extends AbstractSailingServerResource { new ColorJsonSerializer())); JsonSerializer regattaSerializer = new RegattaJsonSerializer(seriesJsonSerializer, null, null, getSecurityService()); JSONObject serializedRegatta = regattaSerializer.serialize(regatta); - String json = serializedRegatta.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(serializedRegatta)).build(); } return response; } @@ -349,8 +352,7 @@ public class RegattasResource extends AbstractSailingServerResource { JsonSerializer regattaSerializer = new RegattaJsonSerializer(seriesJsonSerializer, null, null, getSecurityService()); JSONObject serializedRegatta = regattaSerializer.serialize(regatta); - String json = serializedRegatta.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(serializedRegatta)).build(); } return response; } @@ -378,8 +380,7 @@ public class RegattasResource extends AbstractSailingServerResource { new PersonJsonSerializer(nationalityJsonSerializer)), boatJsonSerializer, /* serializeNonPublicFields */ false); JsonSerializer regattaSerializer = new RegattaJsonSerializer(null, competitorJsonSerializer, boatJsonSerializer, getSecurityService()); JSONObject serializedRegatta = regattaSerializer.serialize(regatta); - String json = serializedRegatta.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(serializedRegatta)).build(); } return response; } @@ -407,8 +408,7 @@ public class RegattasResource extends AbstractSailingServerResource { } else { JsonSerializer raceEntriesSerializer = new RaceEntriesJsonSerializer(getSecurityService()); JSONObject serializedRaceEntries = raceEntriesSerializer.serialize(race); - String json = serializedRaceEntries.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(serializedRaceEntries)).build(); } } return response; @@ -631,7 +631,7 @@ public class RegattasResource extends AbstractSailingServerResource { } } regatta.registerCompetitor(competitor); - response = Response.ok(CompetitorJsonSerializer.create().serialize(competitor).toJSONString()) + response = Response.ok(streamingOutput(CompetitorJsonSerializer.create().serialize(competitor))) .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); if (checkInCompetitor) { final DeviceIdentifier device = new SmartphoneUUIDIdentifierImpl(UUID.fromString(deviceUuid)); @@ -644,7 +644,6 @@ public class RegattasResource extends AbstractSailingServerResource { } else { response = getBadRegattaRegistrationTypeErrorResponse(regattaName); } - return response; } @@ -819,7 +818,7 @@ public class RegattasResource extends AbstractSailingServerResource { response = getBadRaceErrorResponse(regattaName, raceName); } else { TrackedRace trackedRace = findTrackedRace(regattaName, raceName); - + getSecurityService().checkCurrentUserExplicitPermissions(trackedRace, SecuredDomainType.TrackedRaceActions.EXPORT); TimePoint from; TimePoint to; try { @@ -837,7 +836,6 @@ public class RegattasResource extends AbstractSailingServerResource { return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not parse the 'to' time.") .type(MediaType.TEXT_PLAIN).build(); } - JSONObject jsonRace = new JSONObject(); jsonRace.put("name", trackedRace.getRace().getName()); jsonRace.put("regatta", regatta.getName()); @@ -908,11 +906,8 @@ public class RegattasResource extends AbstractSailingServerResource { } if (earlierFix != null && (fix == null || earlierFix.getTimePoint().until(from) .compareTo(to.until(fix.getTimePoint())) <= 0)) { - addCompetitorFixToJsonFixes(jsonFixes, earlierFix, tack); // the earlier fix is - // closer to the - // interval's - // beginning than fix - // is to its end + // the earlier fix is closer to the interval's beginning than fix is to its end + addCompetitorFixToJsonFixes(jsonFixes, earlierFix, tack); } else if (fix != null) { addCompetitorFixToJsonFixes(jsonFixes, fix, tack); } @@ -926,9 +921,7 @@ public class RegattasResource extends AbstractSailingServerResource { } } jsonRace.put("competitors", jsonCompetitors); - - String json = jsonRace.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok((StreamingOutput) (OutputStream output)->jsonRace.writeJSONString(new BufferedWriter(new OutputStreamWriter(output)))).build(); } } return response; @@ -976,6 +969,7 @@ public class RegattasResource extends AbstractSailingServerResource { return getBadRaceErrorResponse(regattaName, raceName); } TrackedRace trackedRace = findTrackedRace(regattaName, raceName); + getSecurityService().checkCurrentUserExplicitPermissions(trackedRace, SecuredDomainType.TrackedRaceActions.EXPORT); TimePoint from; TimePoint to; try { @@ -1051,8 +1045,7 @@ public class RegattasResource extends AbstractSailingServerResource { jsonMarks.add(jsonMark); } jsonRace.put("marks", jsonMarks); - String json = jsonRace.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonRace)).build(); } private JSONObject addMarkFixToJsonFixes(JSONArray jsonFixes, GPSFix fix) { @@ -1157,8 +1150,7 @@ public class RegattasResource extends AbstractSailingServerResource { final LineDetails startLineDetails = optionalTrackedRace.getStartLine(timePointForStartLine); jsonCourse = new CourseBaseWithGeometryJsonSerializer(waypointSerializer).serialize(new Triple<>(course, geometry, startLineDetails)); } - String json = jsonCourse.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(jsonCourse)).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); return response; } @@ -1246,8 +1238,7 @@ public class RegattasResource extends AbstractSailingServerResource { targetTime = trackedRace.getEstimatedTimeToComplete(timePoint); final TargetTimeInfoSerializer serializer = new TargetTimeInfoSerializer(new WindJsonSerializer(new PositionJsonSerializer())); JSONObject jsonCourse = serializer.serialize(targetTime); - String json = jsonCourse.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(jsonCourse)).build(); } catch (NotEnoughDataHasBeenAddedException | NoWindException e) { response = getNotEnoughDataAvailabeErrorResponse(regattaName, raceName); } @@ -1311,8 +1302,7 @@ public class RegattasResource extends AbstractSailingServerResource { } else { try { JSONObject jsonStartAnalysis = getStartAnalysis(trackedRace, regatta); - String json = jsonStartAnalysis.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(jsonStartAnalysis)).build(); } catch (NoWindException | InterruptedException | ExecutionException e) { response = Response.status(Status.INTERNAL_SERVER_ERROR) .entity("Error computing start analysis for race '" + StringEscapeUtils.escapeHtml(raceName) + "' in regatta '" + StringEscapeUtils.escapeHtml(regattaName) + "': "+ @@ -1411,10 +1401,7 @@ public class RegattasResource extends AbstractSailingServerResource { response = getBadRaceErrorResponse(regattaName, raceName); } else { JSONObject jsonRaceTimes = getRaceTimesJSONForRaceName(raceName, regatta); - - String json = jsonRaceTimes.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + response = Response.ok(streamingOutput(jsonRaceTimes)).build(); } } return response; @@ -1555,8 +1542,7 @@ public class RegattasResource extends AbstractSailingServerResource { TrackedRace trackedRace = findTrackedRace(regattaName, raceName); RaceWindJsonSerializer serializer = new RaceWindJsonSerializer(); JSONObject jsonWindTracks = serializer.serialize(trackedRace); - String json = jsonWindTracks.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonWindTracks)).build(); } } return response; @@ -1591,6 +1577,7 @@ public class RegattasResource extends AbstractSailingServerResource { .type(MediaType.TEXT_PLAIN).build(); } else { TrackedRace trackedRace = findTrackedRace(regattaName, raceName); + getSecurityService().checkCurrentUserExplicitPermissions(trackedRace, SecuredDomainType.TrackedRaceActions.EXPORT); TimePoint from; TimePoint to; try { @@ -1618,8 +1605,7 @@ public class RegattasResource extends AbstractSailingServerResource { windSource, windSourceId); JSONObject jsonWindTracks = serializer.serialize(trackedRace); - String json = jsonWindTracks.toJSONString(); - response = Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + response = Response.ok(streamingOutput(jsonWindTracks)).build(); } } } @@ -1727,8 +1713,7 @@ public class RegattasResource extends AbstractSailingServerResource { BearingJsonSerializer serializer = new BearingJsonSerializer(); JSONObject jsonBearing = serializer.serialize(trackedRace.getDirectionFromStartToNextMark(timePoint) .getFrom()); - String json = jsonBearing.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonBearing)).build(); } } return response; @@ -1756,8 +1741,7 @@ public class RegattasResource extends AbstractSailingServerResource { getSecurityService().checkCurrentUserReadPermission(trackedRace); AbstractTrackedRaceDataJsonSerializer serializer = new MarkPassingsJsonSerializer(/* use now-livedelay as time point for mark ranks */ null); JSONObject jsonMarkPassings = serializer.serialize(trackedRace); - String json = jsonMarkPassings.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonMarkPassings)).build(); } } return response; @@ -1831,8 +1815,7 @@ public class RegattasResource extends AbstractSailingServerResource { ManeuversJsonSerializer serializer = new ManeuversJsonSerializer( new ManeuverJsonSerializer(new GPSFixJsonSerializer(), new DistanceJsonSerializer())); JSONObject jsonMarkPassings = serializer.serialize(data); - String json = jsonMarkPassings.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonMarkPassings)).build(); } } } @@ -1879,8 +1862,7 @@ public class RegattasResource extends AbstractSailingServerResource { getNullableValueFromDefault(startAfterFinishLineInSeconds), getNullableValueFromDefault(endAfterFinishLineInSeconds)); JSONObject jsonMarkPassings = serializer.serialize(trackedRace); - String json = jsonMarkPassings.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonMarkPassings)).build(); } } return response; @@ -1925,8 +1907,7 @@ public class RegattasResource extends AbstractSailingServerResource { getNullableValueFromDefault(startAfterFinishLineInSeconds), getNullableValueFromDefault(endAfterFinishLineInSeconds)); JSONObject jsonMarkPassings = serializer.serialize(trackedRace); - String json = jsonMarkPassings.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonMarkPassings)).build(); } } return response; @@ -1962,8 +1943,7 @@ public class RegattasResource extends AbstractSailingServerResource { jsonRace.put("courseName", race.getCourse() != null ? race.getCourse().getName() : ""); jsonRace.put("id", race.getId().toString()); } - String json = jsonRaceResults.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonRaceResults)).build(); } return response; } @@ -2122,8 +2102,7 @@ public class RegattasResource extends AbstractSailingServerResource { course.unlockAfterRead(); } jsonRaceResults.put("legs", jsonLegs); - String json = jsonRaceResults.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonRaceResults)).build(); } } return response; @@ -2257,8 +2236,7 @@ public class RegattasResource extends AbstractSailingServerResource { } } jsonLiveData.put("competitors", jsonCompetitors); - String json = jsonLiveData.toJSONString(); - return Response.ok(json).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(jsonLiveData)).build(); } } return response; @@ -2672,8 +2650,7 @@ public class RegattasResource extends AbstractSailingServerResource { + item.getId() + "; type: " + item.getClass().getName()); } }); - return Response.ok(result.toJSONString()) - .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + return Response.ok(streamingOutput(result)).build(); } else { throw new IllegalStateException("Regatta named " + regattaName + " could not be resolved"); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RemoteServerReferenceResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RemoteServerReferenceResource.java index e58b0510a48..9c607ab0977 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RemoteServerReferenceResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/RemoteServerReferenceResource.java @@ -53,7 +53,7 @@ public class RemoteServerReferenceResource extends AbstractSailingServerResource jsonResponse.put("remoteServerNameAdded", serverRef.getName()); jsonResponse.put("remoteServerUrlAdded", serverRef.getURL().toString()); jsonResponse.put("remoteServerEventsAdded", getRemoteEventsList(serverRef)); - response = Response.ok(jsonResponse.toJSONString()) + response = Response.ok(streamingOutput(jsonResponse)) .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } catch (UnauthorizedException e) { response = returnUnauthorized(e); @@ -91,7 +91,7 @@ public class RemoteServerReferenceResource extends AbstractSailingServerResource jsonResponse.put("remoteServerNameRemoved", serverRef.getName()); jsonResponse.put("remoteServerUrlRemoved", serverRef.getURL().toString()); jsonResponse.put("remoteServerEventsRemoved", remoteEventList); - response = Response.ok(jsonResponse.toJSONString()) + response = Response.ok(streamingOutput(jsonResponse)) .header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); } } catch (UnauthorizedException e) { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatisticsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatisticsResource.java index a90462231a5..39da351eee1 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatisticsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatisticsResource.java @@ -16,7 +16,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.json.simple.JSONArray; -import org.json.simple.JSONAware; import com.sap.sailing.domain.statistics.Statistics; import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource; @@ -65,7 +64,7 @@ public class StatisticsResource extends AbstractSailingServerResource { return integerYears; } - private Response getJsonResponse(JSONAware json) { - return Response.ok(json.toJSONString()).header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_JSON_UTF8).build(); + private Response getJsonResponse(JSONArray jsonArray) { + return Response.ok(streamingOutput(jsonArray)).header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_JSON_UTF8).build(); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatusResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatusResource.java index d85dc008826..07c65bdb27d 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatusResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/StatusResource.java @@ -4,7 +4,6 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.json.simple.JSONObject; @@ -33,6 +32,6 @@ public class StatusResource extends AbstractSailingServerResource { (replicationStatus == null || replicationStatus.isAvailable()); result.put("available", available); return Response.status(available ? HttpServletResponse.SC_OK : HttpServletResponse.SC_SERVICE_UNAVAILABLE). - entity(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8").build(); + entity(streamingOutput(result)).build(); } } \ No newline at end of file diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedEventsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedEventsResource.java index 8a0b4912a07..df26cab7eec 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedEventsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedEventsResource.java @@ -86,8 +86,7 @@ public class TrackedEventsResource extends AbstractSailingServerResource { // storage was empty -> respond with empty list final JSONObject resultEvents = new JSONObject(); resultEvents.put(KEY_TRACKED_EVENTS, result); - final String jsonString = resultEvents.toJSONString(); - builder = Response.ok(jsonString).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8"); + builder = Response.ok(streamingOutput(resultEvents)); } else { builder = Response.status(Status.UNAUTHORIZED); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedRaceListResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedRaceListResource.java index c9f2b0cfdd2..fd528491727 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedRaceListResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackedRaceListResource.java @@ -16,9 +16,9 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.StreamingOutput; import org.json.simple.JSONArray; -import org.json.simple.JSONAware; import org.json.simple.JSONObject; import com.sap.sailing.domain.anniversary.DetailedRaceInfo; @@ -51,7 +51,7 @@ public class TrackedRaceListResource extends AbstractSailingServerResource { if (detailedRaceInfo == null) { return Response.status(Status.NOT_FOUND).header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_JSON_UTF8).build(); } - return getJsonResponse(detailedRaceListJsonSerializer.serialize(detailedRaceInfo)); + return getJsonResponse(streamingOutput(detailedRaceListJsonSerializer.serialize(detailedRaceInfo))); } /** @@ -88,7 +88,7 @@ public class TrackedRaceListResource extends AbstractSailingServerResource { remote.put(DetailedRaceInfoJsonSerializer.FIELD_RACES, list); json.add(remote); } - return getJsonResponse(json); + return getJsonResponse(streamingOutput(json)); } /** @@ -120,7 +120,7 @@ public class TrackedRaceListResource extends AbstractSailingServerResource { raceInfo.put("raceinfo", simpleRaceListJsonSerializer.serialize(current)); json.add(raceInfo); } - return getJsonResponse(json); + return getJsonResponse(streamingOutput(json)); } private Map getDistinctRaces(boolean includeRemotes) { @@ -132,7 +132,7 @@ public class TrackedRaceListResource extends AbstractSailingServerResource { return distinctRaces; } - private Response getJsonResponse(JSONAware json) { - return Response.ok(json.toJSONString()).header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_JSON_UTF8).build(); + private Response getJsonResponse(StreamingOutput json) { + return Response.ok(json).header(HEADER_NAME_CONTENT_TYPE, CONTENT_TYPE_JSON_UTF8).build(); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java index 53633cad4e6..a73773762f4 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TrackingDevicesResource.java @@ -8,7 +8,6 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.json.simple.JSONArray; @@ -32,8 +31,7 @@ public class TrackingDevicesResource extends AbstractSailingServerResource { new DeviceIdentifierJsonSerializer( getServiceFinderFactory().createServiceFinder(DeviceIdentifierJsonHandler.class))); final JSONObject result = serializer.serialize(calculateDeviceStatus(deviceUUID)); - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + return Response.ok(streamingOutput(result)).build(); } @GET @@ -46,8 +44,7 @@ public class TrackingDevicesResource extends AbstractSailingServerResource { for (UUID deviceUUID : deviceUUIDs) { result.add(serializer.serialize(calculateDeviceStatus(deviceUUID))); } - return Response.ok(result.toJSONString()).header("Content-Type", MediaType.APPLICATION_JSON + ";charset=UTF-8") - .build(); + return Response.ok(streamingOutput(result)).build(); } private TrackingDeviceStatus calculateDeviceStatus(UUID deviceUUID) { diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/UserGroupsResource.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/UserGroupsResource.java index 7b7b6b6537a..815c07d9394 100644 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/UserGroupsResource.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/UserGroupsResource.java @@ -42,7 +42,7 @@ public class UserGroupsResource extends AbstractSailingServerResource { groupJson.put("name", group.getName()); groups.add(groupJson); } - response = Response.ok(root.toJSONString()).build(); + response = Response.ok(streamingOutput(root)).build(); } else { response = Response.status(401).build(); } @@ -70,7 +70,7 @@ public class UserGroupsResource extends AbstractSailingServerResource { roles.add(role); } root.put("roles", roles); - response = Response.ok(root.toJSONString()).build(); + response = Response.ok(streamingOutput(root)).build(); } else { response = Response.status(401).build(); } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/orc/ORCCertificateImportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/orc/ORCCertificateImportServlet.java index 384b89ceb70..44b4d84f26a 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/orc/ORCCertificateImportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/orc/ORCCertificateImportServlet.java @@ -70,14 +70,14 @@ public class ORCCertificateImportServlet extends AbstractFileUploadServlet { final JSONObject errorResponse = new JSONObject(); errorResponse.put(ORCCertificateUploadConstants.STATUS, "ERROR"); errorResponse.put(ORCCertificateUploadConstants.MESSAGE, "Error trying to import ORC certificates: "+e.getMessage()); - resp.getOutputStream().print(errorResponse.toJSONString()); + errorResponse.writeJSONString(resp.getWriter()); resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); } catch (ParseException e) { logger.log(Level.INFO, "User "+SessionUtils.getPrincipal()+" was trying to analyze ORC certificates, but the certificates failed to parse", e); final JSONObject errorResponse = new JSONObject(); errorResponse.put(ORCCertificateUploadConstants.STATUS, "ERROR"); errorResponse.put(ORCCertificateUploadConstants.MESSAGE, "Unable to parse certificate selection: "+e.getMessage()); - resp.getOutputStream().print(errorResponse.toJSONString()); + errorResponse.writeJSONString(resp.getWriter()); resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); } finally { resp.setContentType("text/html;charset=UTF-8"); @@ -110,7 +110,7 @@ public class ORCCertificateImportServlet extends AbstractFileUploadServlet { } jsonResponse.put(ORCCertificateUploadConstants.CERTIFICATES, certificatesAsJson); jsonResponse.put(ORCCertificateUploadConstants.STATUS, "OK"); - resp.getWriter().write(jsonResponse.toJSONString()); + jsonResponse.writeJSONString(resp.getWriter()); } } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImportServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImportServlet.java index d2ed5969f9b..04df50594c1 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImportServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/windimport/AbstractWindImportServlet.java @@ -57,7 +57,7 @@ public abstract class AbstractWindImportServlet extends SailingServerHttpServlet windImportResult.error = e.toString(); } response.setContentType("text/html;charset=UTF-8"); - response.getWriter().append(windImportResult.json().toJSONString()); + windImportResult.json().writeJSONString(response.getWriter()); } private UploadRequest readRequest(HttpServletRequest req) throws FileUploadException, ParseException { diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorPositionsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorPositionsGetDoc.html index d7de1d95fba..b6b67ddcede 100644 --- a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorPositionsGetDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceCompetitorPositionsGetDoc.html @@ -14,6 +14,8 @@ Description:

Gets all GPS positions of the competitors of a race.
All slashes contained within the {regattaname} and {racename} parameters must be replaced by "__" (double underscore).

+The request must be authenticated with a user who has the TRACKED_RACE:EXPORT permission for the race for +which the data is requested.
diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceMarkPositionsGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceMarkPositionsGetDoc.html index a18193541a9..187ff790fd9 100644 --- a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceMarkPositionsGetDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceMarkPositionsGetDoc.html @@ -14,6 +14,8 @@ Description:

Gets all GPS positions of the course marks of a race.
All slashes contained within the {regattaname} and {racename} parameters must be replaced by "__" (double underscore).

+The request must be authenticated with a user who has the TRACKED_RACE:EXPORT permission for the race for +which the data is requested.
diff --git a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceWindGetDoc.html b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceWindGetDoc.html index 674f9729a75..75bcffa6b5a 100644 --- a/java/com.sap.sailing.server.gateway/webservices/api/v1/raceWindGetDoc.html +++ b/java/com.sap.sailing.server.gateway/webservices/api/v1/raceWindGetDoc.html @@ -14,6 +14,8 @@ Description:

Gets all GPS positions and data values for the wind of a race.
All slashes contained within the {regattaname} and {racename} parameters must be replaced by "__" (double underscore).

+The request must be authenticated with a user who has the TRACKED_RACE:EXPORT permission for the race for +which the data is requested.
diff --git a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF index 692a6edfa51..e6b2b4c9257 100644 --- a/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.replication.test/META-INF/MANIFEST.MF @@ -38,5 +38,6 @@ Require-Bundle: com.sap.sailing.server, com.sap.sse.security.testsupport, com.sap.sailing.domain.racelogtrackingadapter, com.sap.sailing.shared.server, - com.sap.sailing.resultimport + com.sap.sailing.resultimport, + com.sap.sailing.shared.server.gateway Automatic-Module-Name: com.sap.sailing.server.replication.test diff --git a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF index 96501225e28..9c0f7268a93 100644 --- a/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.test/META-INF/MANIFEST.MF @@ -26,7 +26,8 @@ Require-Bundle: com.sap.sailing.domain, com.sap.sailing.server.testsupport, com.sun.jersey;bundle-version="1.17.0", com.sap.sse.security.testsupport, - com.sap.sailing.domain.racelogtrackingadapter + com.sap.sailing.domain.racelogtrackingadapter, + com.sap.sailing.shared.server.gateway Import-Package: com.sap.sailing.server.gateway.jaxrs, com.sap.sailing.server.gateway.jaxrs.spi, com.sap.sse.security.userstore.mongodb, diff --git a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/TaggingServiceTest.java b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/TaggingServiceTest.java index d7863e6bf03..a8c495c190c 100644 --- a/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/TaggingServiceTest.java +++ b/java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/TaggingServiceTest.java @@ -5,8 +5,6 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import java.io.IOException; -import java.net.MalformedURLException; import java.util.List; import java.util.Locale; import java.util.logging.Logger; @@ -47,11 +45,9 @@ import com.sap.sailing.server.tagging.TaggingServiceImpl; import com.sap.sailing.server.testsupport.SecurityBundleTestWrapper; import com.sap.sse.common.TimePoint; import com.sap.sse.common.impl.MillisecondsTimePoint; -import com.sap.sse.common.mail.MailException; import com.sap.sse.mongodb.MongoDBService; import com.sap.sse.security.SecurityService; import com.sap.sse.security.shared.HasPermissions.DefaultActions; -import com.sap.sse.security.shared.UserGroupManagementException; import com.sap.sse.security.shared.UserManagementException; import com.sap.sse.security.shared.WildcardPermission; @@ -85,8 +81,7 @@ public class TaggingServiceTest { private static SubjectThreadState threadState; @BeforeClass - public synchronized static void setUpClass() - throws MalformedURLException, IOException, InterruptedException, UserManagementException, MailException, UserGroupManagementException { + public synchronized static void setUpClass() throws Exception { logger.info("current thread: "+Thread.currentThread()); MongoDBService.INSTANCE.getDB().drop(); // setup racing service and racelog @@ -103,13 +98,11 @@ public class TaggingServiceTest { securityService.createSimpleUser(username, email, password, fullName, company, Locale.ENGLISH, null, securityService.getDefaultTenantForCurrentUser()); ThreadContext.unbindSubject(); // ensure that a new subject is created that knows the current security manager - subject = SecurityUtils.getSubject(); subject.login(new UsernamePasswordToken(username, password)); threadState = new SubjectThreadState(subject); // setup tagging service taggingService = Mockito.spy(new TaggingServiceImpl(racingService)); - Mockito.doReturn(securityService).when(racingService).getSecurityService(); Mockito.doReturn(taggingService).when(racingService).getTaggingService(); } diff --git a/java/com.sap.sailing.server.testsupport/src/com/sap/sailing/server/testsupport/SecurityBundleTestWrapper.java b/java/com.sap.sailing.server.testsupport/src/com/sap/sailing/server/testsupport/SecurityBundleTestWrapper.java index 88fda4c35ae..44e79c55aed 100755 --- a/java/com.sap.sailing.server.testsupport/src/com/sap/sailing/server/testsupport/SecurityBundleTestWrapper.java +++ b/java/com.sap.sailing.server.testsupport/src/com/sap/sailing/server/testsupport/SecurityBundleTestWrapper.java @@ -7,8 +7,6 @@ import org.apache.shiro.SecurityUtils; import com.sap.sse.security.SecurityService; import com.sap.sse.security.impl.Activator; import com.sap.sse.security.impl.SecurityServiceImpl; -import com.sap.sse.security.shared.UserGroupManagementException; -import com.sap.sse.security.shared.UserManagementException; import com.sap.sse.security.userstore.mongodb.AccessControlStoreImpl; import com.sap.sse.security.userstore.mongodb.UserStoreImpl; import com.sap.sse.util.ServiceTrackerFactory; @@ -16,22 +14,26 @@ import com.sap.sse.util.ServiceTrackerFactory; public class SecurityBundleTestWrapper { private static final Logger logger = Logger.getLogger(SecurityBundleTestWrapper.class.getName()); - public SecurityService initializeSecurityServiceForTesting() throws UserGroupManagementException, UserManagementException, InterruptedException { + public SecurityService initializeSecurityServiceForTesting() throws Exception { final SecurityService securityService; if (Activator.getContext() == null) { logger.info("Setup for TaggingServiceTest in a non-OSGi environment"); final UserStoreImpl store = new UserStoreImpl("defaultTenant"); + store.ensureDefaultRolesExist(); + store.ensureServerGroupExists(); final AccessControlStoreImpl accessControlStoreImpl = new AccessControlStoreImpl(store); Activator.setTestStores(store, accessControlStoreImpl); securityService = new SecurityServiceImpl(store, accessControlStoreImpl); + ((SecurityServiceImpl) securityService).clearState(); + securityService.initialize(); SecurityUtils.setSecurityManager(securityService.getSecurityManager()); Activator.setSecurityService(securityService); } else { logger.info("Creating dummy UserStoreImpl to trigger loading of userstore mongodb bundle"); new UserStoreImpl("defaultTenant"); // only to trigger bundle loading and activation so that security service can find the bundle and its original user store logger.info("Setup for TaggingServiceTest in an OSGi environment"); - // Note: This timeout of 2 minutes is just for debugging purposes and should not be used in production! - securityService = ServiceTrackerFactory.createAndOpen(Activator.getContext(), SecurityService.class).waitForService(120 * 1000); + // Note: This timeout of 3 minutes is just for debugging purposes and should not be used in production! + securityService = ServiceTrackerFactory.createAndOpen(Activator.getContext(), SecurityService.class).waitForService(180 * 1000); } return securityService; } diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy OSX).launch b/java/com.sap.sailing.server/SailingServer (No Proxy OSX).launch index 9aafc3a2f86..d0830cc69e6 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy OSX).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy OSX).launch @@ -11,6 +11,7 @@ + @@ -29,10 +30,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy).launch b/java/com.sap.sailing.server/SailingServer (No Proxy).launch index b30d4ab46e6..d66051e767f 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy).launch @@ -112,7 +112,7 @@ - + @@ -159,7 +159,7 @@ - + @@ -189,8 +189,8 @@ - - + + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch index 20923280a11..e65dccb16c4 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Cached MTB).launch @@ -182,6 +182,7 @@ + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Igtimi Local Test).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Igtimi Local Test).launch index 6d9cbf74bc3..3c0aafb3106 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Igtimi Local Test).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Igtimi Local Test).launch @@ -11,6 +11,7 @@ + @@ -31,10 +32,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Java11).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Java11).launch index 78af2fe21ef..5854cf79900 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Java11).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Java11).launch @@ -11,6 +11,7 @@ + @@ -31,10 +32,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Java11, JFR Recording).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Java11, JFR Recording).launch index 555b761a598..43978fc09fc 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Java11, JFR Recording).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Java11, JFR Recording).launch @@ -1,40 +1,219 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch index 2263694bcc2..ff559808c02 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch @@ -10,6 +10,7 @@ + @@ -22,11 +23,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch index e542d8163b0..f26cf4efd5c 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch @@ -10,23 +10,202 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate SS and SSD).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate SS and SSD).launch index 05981685eb0..510ebc647ef 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate SS and SSD).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate SS and SSD).launch @@ -10,6 +10,7 @@ + @@ -24,11 +25,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch index e42be423ebf..02e1cbf2026 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate dev).launch @@ -10,6 +10,7 @@ + @@ -22,11 +23,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch index c09d02aeb8b..26dbf774ddf 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, auto-replicate).launch @@ -10,6 +10,7 @@ + @@ -24,11 +25,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch index 1f4382fbb33..7317010a924 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890).launch @@ -10,6 +10,7 @@ + @@ -22,11 +23,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890, auto-replicate from replica at 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890, auto-replicate from replica at 8889).launch index 9ab0d7de54a..d57783947ac 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890, auto-replicate from replica at 8889).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8890, auto-replicate from replica at 8889).launch @@ -10,6 +10,7 @@ + @@ -22,11 +23,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch index dc928839e90..9637715c717 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Remote Debug SAP VM).launch @@ -10,22 +10,201 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, bundesliga2-2017 DB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, bundesliga2-2017 DB).launch index a8de4eee4af..8406d2ac3fd 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, bundesliga2-2017 DB).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, bundesliga2-2017 DB).launch @@ -11,6 +11,7 @@ + @@ -31,10 +32,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, debranding active).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, debranding active).launch index 2a78e4b10bc..ae0761f4488 100644 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, debranding active).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, debranding active).launch @@ -32,8 +32,186 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch index c5d5764e2a3..576879a8311 100755 --- a/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch +++ b/java/com.sap.sailing.server/SailingServer (No Proxy, winddbTest).launch @@ -10,6 +10,7 @@ + @@ -28,10 +29,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889, Polar & Wind estimation Import from 8888).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889, Polar & Wind estimation Import from 8888).launch index f6348129654..cbcf53593b5 100755 --- a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889, Polar & Wind estimation Import from 8888).launch +++ b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889, Polar & Wind estimation Import from 8888).launch @@ -10,6 +10,7 @@ + @@ -22,11 +23,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/tagging/TagDTODeSerializer.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/tagging/TagDTODeSerializer.java index dac92ef298b..914a4b8f770 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/tagging/TagDTODeSerializer.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/tagging/TagDTODeSerializer.java @@ -112,17 +112,6 @@ public class TagDTODeSerializer { return deserializeTags(jsonArray.toJSONString()); } - /** - * Serializes single {@link TagDTO tag} to json object. - * - * @param tag - * tag to be seriaized - * @return json object - */ - public String serializeTag(TagDTO tag) { - return serialize(tag).toJSONString(); - } - /** * Serializes list of {@link TagDTO tags} to json array. * diff --git a/java/com.sap.sailing.shared.persistence/src/com/sap/sailing/shared/persistence/impl/DomainObjectFactoryImpl.java b/java/com.sap.sailing.shared.persistence/src/com/sap/sailing/shared/persistence/impl/DomainObjectFactoryImpl.java index f3f09ee786f..8d324e03271 100755 --- a/java/com.sap.sailing.shared.persistence/src/com/sap/sailing/shared/persistence/impl/DomainObjectFactoryImpl.java +++ b/java/com.sap.sailing.shared.persistence/src/com/sap/sailing/shared/persistence/impl/DomainObjectFactoryImpl.java @@ -123,7 +123,9 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { try { final Document deviceIdDocument = dbObject.get(FieldNames.MARK_PROPERTIES_TRACKING_DEVICE_IDENTIFIER.name(), Document.class); final DeviceIdentifier deviceIdentifier = deviceIdDocument == null ? null : loadDeviceId(deviceIdentifierServiceFinder, deviceIdDocument); - builder.withDeviceId(deviceIdentifier); + if (deviceIdentifier != null) { + builder.withDeviceId(deviceIdentifier); + } } catch (TransformationException | NoCorrespondingServiceRegisteredException e) { logger.log(Level.WARNING, "Could not load deviceId for MarkProperties", e); } diff --git a/java/com.sap.sailing.shared.server.gateway/META-INF/MANIFEST.MF b/java/com.sap.sailing.shared.server.gateway/META-INF/MANIFEST.MF index b060f0f2abe..382bb403704 100644 --- a/java/com.sap.sailing.shared.server.gateway/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.shared.server.gateway/META-INF/MANIFEST.MF @@ -53,3 +53,4 @@ Require-Bundle: com.sap.sailing.domain, Bundle-ClassPath: . Web-ContextPath: /sharedsailingserver Automatic-Module-Name: com.sap.sailing.shared.server.gateway +Export-Package: com.sap.sailing.shared.server.gateway.jaxrs diff --git a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/AbstractSailingServerResource.java b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/SharedAbstractSailingServerResource.java similarity index 97% rename from java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/AbstractSailingServerResource.java rename to java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/SharedAbstractSailingServerResource.java index 1afcba2889f..f045c592403 100644 --- a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/AbstractSailingServerResource.java +++ b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/SharedAbstractSailingServerResource.java @@ -23,11 +23,12 @@ import com.sap.sse.common.TypeBasedServiceFinderFactory; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.osgi.CachedOsgiTypeBasedServiceFinderFactory; import com.sap.sse.replication.ReplicationService; +import com.sap.sse.rest.StreamingOutputUtil; import com.sap.sse.security.SecurityService; import com.sap.sse.util.DateParser; import com.sun.jersey.api.core.ResourceContext; -public abstract class AbstractSailingServerResource { +public abstract class SharedAbstractSailingServerResource extends StreamingOutputUtil { private static final String SLASH_ENCODING = "__"; @Context ServletContext servletContext; @Context ResourceContext resourceContext; diff --git a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/CourseTemplateResource.java b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/CourseTemplateResource.java index 45f3e734a7e..91c2db1341f 100644 --- a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/CourseTemplateResource.java +++ b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/CourseTemplateResource.java @@ -24,11 +24,11 @@ import com.sap.sailing.server.gateway.deserialization.JsonDeserializer; import com.sap.sailing.server.gateway.deserialization.impl.CourseTemplateJsonDeserializer; import com.sap.sailing.server.gateway.serialization.JsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.CourseTemplateJsonSerializer; -import com.sap.sailing.shared.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.shared.server.gateway.jaxrs.SharedAbstractSailingServerResource; import com.sun.jersey.api.client.ClientResponse.Status; @Path("/v1/coursetemplates") -public class CourseTemplateResource extends AbstractSailingServerResource { +public class CourseTemplateResource extends SharedAbstractSailingServerResource { private final JsonSerializer courseTemplateSerializer; @@ -58,8 +58,7 @@ public class CourseTemplateResource extends AbstractSailingServerResource { for (CourseTemplate courseTemplate : courseTemplateList) { result.add(courseTemplateSerializer.serialize(courseTemplate)); } - final String json = result.toJSONString(); - return Response.ok(json).build(); + return Response.ok(streamingOutput(result)).build(); } @GET @@ -70,10 +69,8 @@ public class CourseTemplateResource extends AbstractSailingServerResource { if (courseTemplate == null) { return getCourseTemplateNotFoundErrorResponse(); } - - final JSONObject serializedMarkedProperties = courseTemplateSerializer.serialize(courseTemplate); - final String json = serializedMarkedProperties.toJSONString(); - return Response.ok(json).build(); + final JSONObject serializedMarkProperties = courseTemplateSerializer.serialize(courseTemplate); + return Response.ok(streamingOutput(serializedMarkProperties)).build(); } @POST @@ -95,9 +92,8 @@ public class CourseTemplateResource extends AbstractSailingServerResource { deserializedCourseTemplate.getDefaultMarkRolesForMarkTemplates(), deserializedCourseTemplate.getDefaultMarkTemplatesForMarkRoles(), deserializedCourseTemplate.getRepeatablePart(), deserializedCourseTemplate.getTags(), deserializedCourseTemplate.getOptionalImageURL(), deserializedCourseTemplate.getDefaultNumberOfLaps()); - final JSONObject serializedMarkedProperties = courseTemplateSerializer.serialize(createdCourseTemplate); - final String jsonResult = serializedMarkedProperties.toJSONString(); - return Response.ok(jsonResult).build(); + final JSONObject serializedMarkProperties = courseTemplateSerializer.serialize(createdCourseTemplate); + return Response.ok(streamingOutput(serializedMarkProperties)).build(); } @DELETE diff --git a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkPropertiesResource.java b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkPropertiesResource.java index a763447c569..171b1a76e73 100644 --- a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkPropertiesResource.java +++ b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkPropertiesResource.java @@ -35,14 +35,14 @@ import com.sap.sailing.server.gateway.serialization.impl.DeviceIdentifierJsonSer import com.sap.sailing.server.gateway.serialization.impl.MarkPropertiesJsonSerializer; import com.sap.sailing.server.gateway.serialization.racelog.tracking.DeviceIdentifierJsonHandler; import com.sap.sailing.server.gateway.serialization.racelog.tracking.impl.PlaceHolderDeviceIdentifierJsonHandler; -import com.sap.sailing.shared.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.shared.server.gateway.jaxrs.SharedAbstractSailingServerResource; import com.sap.sse.common.Color; import com.sap.sse.common.TypeBasedServiceFinder; import com.sap.sse.common.impl.RGBColor; import com.sun.jersey.api.client.ClientResponse.Status; @Path("/v1/markproperties") -public class MarkPropertiesResource extends AbstractSailingServerResource { +public class MarkPropertiesResource extends SharedAbstractSailingServerResource { private JsonSerializer markPropertiesSerializer; public MarkPropertiesResource() { @@ -65,8 +65,7 @@ public class MarkPropertiesResource extends AbstractSailingServerResource { for (MarkProperties markProperties : markPropertiesList) { result.add(getMarkPropertiesSerializer().serialize(markProperties)); } - final String json = result.toJSONString(); - return Response.ok(json).build(); + return Response.ok(streamingOutput(result)).build(); } @GET @@ -77,9 +76,8 @@ public class MarkPropertiesResource extends AbstractSailingServerResource { if (markProperties == null) { return getMarkPropertiesNotFoundErrorResponse(); } - final JSONObject serializedMarkedProperties = getMarkPropertiesSerializer().serialize(markProperties); - final String json = serializedMarkedProperties.toJSONString(); - return Response.ok(json).build(); + final JSONObject serializedMarkProperties = getMarkPropertiesSerializer().serialize(markProperties); + return Response.ok(streamingOutput(serializedMarkProperties)).build(); } @POST @@ -129,9 +127,8 @@ public class MarkPropertiesResource extends AbstractSailingServerResource { final Position fixedPosition = new DegreePosition(latDeg, lonDeg); getSharedSailingData().setFixedPositionForMarkProperties(createdMarkProperties, fixedPosition); } - final JSONObject serializedMarkedProperties = getMarkPropertiesSerializer().serialize(createdMarkProperties); - final String json = serializedMarkedProperties.toJSONString(); - return Response.ok(json).build(); + final JSONObject serializedMarkProperties = getMarkPropertiesSerializer().serialize(createdMarkProperties); + return Response.ok(streamingOutput(serializedMarkProperties)).build(); } @PUT @@ -153,9 +150,8 @@ public class MarkPropertiesResource extends AbstractSailingServerResource { } else { getSharedSailingData().clearPositioningForMarkProperties(markProperties); } - final JSONObject serializedMarkedProperties = getMarkPropertiesSerializer().serialize(markProperties); - final String json = serializedMarkedProperties.toJSONString(); - return Response.ok(json).build(); + final JSONObject serializedMarkProperties = getMarkPropertiesSerializer().serialize(markProperties); + return Response.ok(streamingOutput(serializedMarkProperties)).build(); } @PUT @@ -206,9 +202,8 @@ public class MarkPropertiesResource extends AbstractSailingServerResource { positioningInformation = null; } getSharedSailingData().updateMarkProperties(markPropertiesUUID, markPropertiesBuilder.build(), positioningInformation, tags); - final JSONObject serializedMarkedProperties = getMarkPropertiesSerializer().serialize(markProperties); - final String json = serializedMarkedProperties.toJSONString(); - return Response.ok(json).build(); + final JSONObject serializedMarkProperties = getMarkPropertiesSerializer().serialize(markProperties); + return Response.ok(streamingOutput(serializedMarkProperties)).build(); } @DELETE diff --git a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkRoleResource.java b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkRoleResource.java index a408830bd0c..87bf33110f7 100644 --- a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkRoleResource.java +++ b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkRoleResource.java @@ -18,11 +18,11 @@ import org.json.simple.JSONObject; import com.sap.sailing.domain.coursetemplate.MarkRole; import com.sap.sailing.server.gateway.serialization.JsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.MarkRoleJsonSerializer; -import com.sap.sailing.shared.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.shared.server.gateway.jaxrs.SharedAbstractSailingServerResource; import com.sun.jersey.api.client.ClientResponse.Status; @Path("/v1/markroles") -public class MarkRoleResource extends AbstractSailingServerResource { +public class MarkRoleResource extends SharedAbstractSailingServerResource { private final JsonSerializer markRoleSerializer; @@ -47,8 +47,7 @@ public class MarkRoleResource extends AbstractSailingServerResource { for (MarkRole markRole : markRolesList) { result.add(markRoleSerializer.serialize(markRole)); } - final String json = result.toJSONString(); - return Response.ok(json).build(); + return Response.ok(streamingOutput(result)).build(); } @GET @@ -60,8 +59,7 @@ public class MarkRoleResource extends AbstractSailingServerResource { return getMarkRoleNotFoundErrorResponse(); } final JSONObject serializedMarkRole = markRoleSerializer.serialize(markRole); - final String json = serializedMarkRole.toJSONString(); - return Response.ok(json).build(); + return Response.ok(streamingOutput(serializedMarkRole)).build(); } @POST @@ -72,7 +70,6 @@ public class MarkRoleResource extends AbstractSailingServerResource { } final MarkRole markRole = getSharedSailingData().createMarkRole(name, shortName); final JSONObject serializedMarkRole = markRoleSerializer.serialize(markRole); - final String json = serializedMarkRole.toJSONString(); - return Response.ok(json).build(); + return Response.ok(streamingOutput(serializedMarkRole)).build(); } } diff --git a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkTemplateResource.java b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkTemplateResource.java index 9fcfd4efb0e..e58f7955c3c 100644 --- a/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkTemplateResource.java +++ b/java/com.sap.sailing.shared.server.gateway/src/com/sap/sailing/shared/server/gateway/jaxrs/api/MarkTemplateResource.java @@ -20,13 +20,13 @@ import com.sap.sailing.domain.coursetemplate.MarkTemplate; import com.sap.sailing.domain.coursetemplate.impl.MarkTemplateImpl; import com.sap.sailing.server.gateway.serialization.JsonSerializer; import com.sap.sailing.server.gateway.serialization.impl.MarkTemplateJsonSerializer; -import com.sap.sailing.shared.server.gateway.jaxrs.AbstractSailingServerResource; +import com.sap.sailing.shared.server.gateway.jaxrs.SharedAbstractSailingServerResource; import com.sap.sse.common.Color; import com.sap.sse.common.impl.RGBColor; import com.sun.jersey.api.client.ClientResponse.Status; @Path("/v1/marktemplates") -public class MarkTemplateResource extends AbstractSailingServerResource { +public class MarkTemplateResource extends SharedAbstractSailingServerResource { private Response getBadMarkTemplateValidationErrorResponse(String errorText) { return Response.status(Status.BAD_REQUEST).entity(StringEscapeUtils.escapeHtml(errorText) + ".") @@ -59,9 +59,8 @@ public class MarkTemplateResource extends AbstractSailingServerResource { return getMarkTemplateNotFoundErrorResponse(); } JsonSerializer markTemplateSerializer = new MarkTemplateJsonSerializer(); - final JSONObject serializedMarkedTemplate = markTemplateSerializer.serialize(markTemplate); - final String json = serializedMarkedTemplate.toJSONString(); - return Response.ok(json).build(); + final JSONObject serializedMarkTemplate = markTemplateSerializer.serialize(markTemplate); + return Response.ok(streamingOutput(serializedMarkTemplate)).build(); } @POST @@ -74,7 +73,6 @@ public class MarkTemplateResource extends AbstractSailingServerResource { return getBadMarkTemplateValidationErrorResponse("name must be given"); } final String effectiveShortName = shortName == null || shortName.isEmpty() ? name : shortName; - Color color = null; if (rgbColor != null && rgbColor.length() > 0) { try { @@ -87,13 +85,10 @@ public class MarkTemplateResource extends AbstractSailingServerResource { if (markType != null && markType.length() > 0) { type = MarkType.valueOf(markType); } - final MarkTemplate markTemplate = new MarkTemplateImpl(name, effectiveShortName, color, shape, pattern, type); final MarkTemplate createdMarkTemplate = getSharedSailingData().createMarkTemplate(markTemplate); JsonSerializer markTemplateSerializer = new MarkTemplateJsonSerializer(); - final JSONObject serializedMarkedTemplate = markTemplateSerializer.serialize(createdMarkTemplate); - final String json = serializedMarkedTemplate.toJSONString(); - return Response.ok(json).build(); + final JSONObject serializedMarkTemplate = markTemplateSerializer.serialize(createdMarkTemplate); + return Response.ok(streamingOutput(serializedMarkTemplate)).build(); } - } diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 17d3e33c183..6b87390a5e1 100755 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -43,6 +43,13 @@ added it will also be possible to load those races again on the importing side even if they are temporarily removed again or should fail to load. +
  • The TRACKED_RACE:EXPORT permission is now required on a tracked race in order to export + raw position data for competitors and marks, as well as for obtaining the detailed wind fixes through + the REST API. +
  • +
  • Good news for using the SAP Sailing Analytics with WindFinder support in the Caribbean and in particular + the British Virgin Islands (BVIs): "tortola" was added to the list of supported WindFinder spot collections. +
  • March 2020

      diff --git a/java/com.sap.sse.debranding/META-INF/MANIFEST.MF b/java/com.sap.sse.debranding/META-INF/MANIFEST.MF index c2a3e538351..c78b35ed0da 100644 --- a/java/com.sap.sse.debranding/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.debranding/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: javax.servlet;version="3.1.0", javax.servlet.http;version="3.1.0", + javax.ws.rs.core;version="1.1.1", org.apache.http Bundle-ClassPath: . Bundle-ActivationPolicy: lazy diff --git a/java/com.sap.sse.debranding/src/com/sap/sse/debranding/ClientConfigurationServlet.java b/java/com.sap.sse.debranding/src/com/sap/sse/debranding/ClientConfigurationServlet.java index 3aa53f96415..b1da779bda8 100644 --- a/java/com.sap.sse.debranding/src/com/sap/sse/debranding/ClientConfigurationServlet.java +++ b/java/com.sap.sse.debranding/src/com/sap/sse/debranding/ClientConfigurationServlet.java @@ -12,6 +12,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; import org.apache.commons.io.IOUtils; import org.apache.http.HttpStatus; @@ -82,6 +83,7 @@ public class ClientConfigurationServlet extends HttpServlet { final String servletPath = req.getServletPath(); final byte[] cachedPage; final String pageKey = generateKey(servletPath, deBrandingActive); + resp.setContentType(MediaType.TEXT_HTML); if ((cachedPage = cache.get(pageKey)) != null) { IOUtils.write(cachedPage, resp.getOutputStream()); } else { diff --git a/java/com.sap.sse.replication.interfaces/src/com/sap/sse/replication/FullyInitializedReplicableTracker.java b/java/com.sap.sse.replication.interfaces/src/com/sap/sse/replication/FullyInitializedReplicableTracker.java index 6f73ba480dd..4613f575c43 100755 --- a/java/com.sap.sse.replication.interfaces/src/com/sap/sse/replication/FullyInitializedReplicableTracker.java +++ b/java/com.sap.sse.replication.interfaces/src/com/sap/sse/replication/FullyInitializedReplicableTracker.java @@ -99,22 +99,26 @@ public class FullyInitializedReplicableTracker> exten if (replicationServiceTracker != null) { final CountDownLatch latch = new CountDownLatch(1); // counted down either by the direct check or the listener final ReplicationService replicationService = replicationServiceTracker.waitForService(timeoutInMillis); - final ReplicationStartingListener replicationStartingListener = newIsReplicationStarting->{ - if (!newIsReplicationStarting) { + if (replicationService != null) { + final ReplicationStartingListener replicationStartingListener = newIsReplicationStarting->{ + if (!newIsReplicationStarting) { + latch.countDown(); + } + }; + replicationService.addReplicationStartingListener(replicationStartingListener); + if (!replicationService.isReplicationStarting()) { latch.countDown(); } - }; - replicationService.addReplicationStartingListener(replicationStartingListener); - if (!replicationService.isReplicationStarting()) { - latch.countDown(); - } - if (timeoutInMillis == 0) { - latch.await(); - result = true; + if (timeoutInMillis == 0) { + latch.await(); + result = true; + } else { + result = latch.await(timeoutInMillis, TimeUnit.MILLISECONDS); + } + replicationService.removeReplicationStartingListener(replicationStartingListener); } else { - result = latch.await(timeoutInMillis, TimeUnit.MILLISECONDS); + result = false; // replication service tracker was set, but the service didn't show up within the timeout period } - replicationService.removeReplicationStartingListener(replicationStartingListener); } else { result = true; } diff --git a/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java b/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java index e4d82deb2e4..a33d28ac227 100755 --- a/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java +++ b/java/com.sap.sse.replication/src/com/sap/sse/replication/impl/ReplicationServlet.java @@ -235,7 +235,7 @@ public class ReplicationServlet extends AbstractHttpServlet { result.put("replicables", replicablesJSON); result.put("available", status.isAvailable()); resp.setContentType("application/json;charset=UTF-8"); - resp.getWriter().print(result.toJSONString()); + result.writeJSONString(resp.getWriter()); if (status.isAvailable()) { resp.setStatus(HttpServletResponse.SC_OK); } else { diff --git a/java/com.sap.sse.security.test/src/com/sap/sse/security/jaxrs/api/SecurityResourceTest.java b/java/com.sap.sse.security.test/src/com/sap/sse/security/jaxrs/api/SecurityResourceTest.java index 706bebe68d4..f359f386cec 100755 --- a/java/com.sap.sse.security.test/src/com/sap/sse/security/jaxrs/api/SecurityResourceTest.java +++ b/java/com.sap.sse.security.test/src/com/sap/sse/security/jaxrs/api/SecurityResourceTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.IOException; import java.util.Locale; import javax.ws.rs.core.Response; @@ -24,6 +25,7 @@ import org.junit.Test; import com.sap.sailing.domain.common.media.MediaTrack; import com.sap.sse.common.mail.MailException; +import com.sap.sse.rest.StreamingOutputUtil; import com.sap.sse.security.BearerAuthenticationToken; import com.sap.sse.security.SecurityService; import com.sap.sse.security.impl.Activator; @@ -234,8 +236,8 @@ public class SecurityResourceTest { } } - private String getOrCreateAccessToken() throws ParseException { - String responseJsonString = (String) servlet.respondWithAccessTokenForUser(USERNAME).getEntity(); + private String getOrCreateAccessToken() throws ParseException, IOException { + String responseJsonString = StreamingOutputUtil.getEntityAsString(servlet.respondWithAccessTokenForUser(USERNAME).getEntity()); JSONObject responseJson = (JSONObject) new JSONParser().parse(responseJsonString); assertEquals(USERNAME, responseJson.get("username")); String accessToken = (String) responseJson.get("access_token"); @@ -243,9 +245,9 @@ public class SecurityResourceTest { return accessToken; } - private String createAccessToken() throws ParseException { + private String createAccessToken() throws ParseException, IOException { assertEquals(Response.Status.OK.getStatusCode(), servlet.respondToRemoveAccessTokenForUser(USERNAME).getStatus()); - String responseJsonString = (String) servlet.respondWithAccessTokenForUser(USERNAME).getEntity(); + String responseJsonString = StreamingOutputUtil.getEntityAsString(servlet.respondWithAccessTokenForUser(USERNAME).getEntity()); JSONObject responseJson = (JSONObject) new JSONParser().parse(responseJsonString); assertEquals(USERNAME, responseJson.get("username")); String accessToken = (String) responseJson.get("access_token"); @@ -258,7 +260,7 @@ public class SecurityResourceTest { } @Test - public void createAccessTokenAndAuthenticate() throws ParseException, UserManagementException { + public void createAccessTokenAndAuthenticate() throws ParseException, UserManagementException, IOException { String accessToken = getOrCreateAccessToken(); User user = service.getUserByAccessToken(accessToken); assertNotNull(user); @@ -280,7 +282,7 @@ public class SecurityResourceTest { } @Test - public void ensureOldBearerTokenIsInvalidatedByObtainingNewOne() throws ParseException { + public void ensureOldBearerTokenIsInvalidatedByObtainingNewOne() throws ParseException, IOException { String accessToken = getOrCreateAccessToken(); createAccessToken(); User user = service.getUserByAccessToken(accessToken); @@ -288,7 +290,7 @@ public class SecurityResourceTest { } @Test - public void ensureOldBearerTokenIsInvalidatedByRequestingItsRemoval() throws ParseException { + public void ensureOldBearerTokenIsInvalidatedByRequestingItsRemoval() throws ParseException, IOException { String accessToken = getOrCreateAccessToken(); removeAccessToken(); User user = service.getUserByAccessToken(accessToken); diff --git a/java/com.sap.sse.security/META-INF/MANIFEST.MF b/java/com.sap.sse.security/META-INF/MANIFEST.MF index 43b2ae5da5f..f14bd6aa455 100644 --- a/java/com.sap.sse.security/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.security/META-INF/MANIFEST.MF @@ -29,7 +29,6 @@ Require-Bundle: javax.servlet;bundle-version="3.1.0", com.sap.sse.common, com.sap.sse.operationaltransformation, com.sap.sse.security.common, - com.sap.sse, com.sap.sse.mail, com.sap.sse.shared.android, com.sap.sse.replication.interfaces;visibility:=reexport, diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java b/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java index 4ea95e463dc..78ef54412b9 100755 --- a/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java @@ -296,9 +296,9 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat this.mailServiceTracker = mailServiceTracker; this.hasPermissionsProvider = hasPermissionsProvider; cacheManager = loadReplicationCacheManagerContents(); - Factory factory = new WebIniSecurityManagerFactory(shiroConfiguration); + final Factory factory = new WebIniSecurityManagerFactory(shiroConfiguration); logger.info("Loaded shiro.ini file from: classpath:shiro.ini"); - StringBuilder logMessage = new StringBuilder("[urls] section from Shiro configuration:"); + final StringBuilder logMessage = new StringBuilder("[urls] section from Shiro configuration:"); final Section urlsSection = shiroConfiguration.getSection("urls"); if (urlsSection != null) { for (Entry e : urlsSection.entrySet()) { @@ -310,7 +310,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat } logger.info(logMessage.toString()); System.setProperty("java.net.useSystemProxies", "true"); - CachingSecurityManager securityManager = (CachingSecurityManager) factory.getInstance(); + final CachingSecurityManager securityManager = (CachingSecurityManager) factory.getInstance(); logger.info("Created: " + securityManager); SecurityUtils.setSecurityManager(securityManager); this.securityManager = securityManager; @@ -366,7 +366,6 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat private void initEmptyStore() { final AdminRole adminRolePrototype = AdminRole.getInstance(); RoleDefinition adminRoleDefinition = getRoleDefinition(adminRolePrototype.getId()); - adminRoleDefinition = getRoleDefinition(adminRolePrototype.getId()); assert adminRoleDefinition != null; try { isInitialOrMigration = false; diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/AbstractSecurityResource.java b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/AbstractSecurityResource.java index 8b7d4b8bd67..17d39e771eb 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/AbstractSecurityResource.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/AbstractSecurityResource.java @@ -5,9 +5,10 @@ import javax.ws.rs.core.Context; import org.osgi.util.tracker.ServiceTracker; +import com.sap.sse.rest.StreamingOutputUtil; import com.sap.sse.security.SecurityService; -public abstract class AbstractSecurityResource { +public abstract class AbstractSecurityResource extends StreamingOutputUtil { @Context ServletContext servletContext; diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/OwnershipResource.java b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/OwnershipResource.java index 68e99b80601..9af20f5efb0 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/OwnershipResource.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/OwnershipResource.java @@ -1,5 +1,8 @@ package com.sap.sse.security.jaxrs.api; +import java.io.BufferedWriter; +import java.io.OutputStream; +import java.io.OutputStreamWriter; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -17,6 +20,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; import javax.ws.rs.core.Response.Status; import org.apache.shiro.SecurityUtils; @@ -124,7 +128,7 @@ public class OwnershipResource extends AbstractSecurityResource { result.put(KEY_GROUP_ID, existingOwnership == null || existingOwnership.getAnnotation().getTenantOwner() == null ? null : existingOwnership.getAnnotation().getTenantOwner().getId().toString()); result.put(KEY_USERNAME, existingOwnership == null || existingOwnership.getAnnotation().getUserOwner() == null ? null : existingOwnership.getAnnotation().getUserOwner().getName()); result.put(KEY_DISPLAY_NAME, existingOwnership == null || existingOwnership.getDisplayNameOfAnnotatedObject() == null ? null : existingOwnership.getDisplayNameOfAnnotatedObject()); - return Response.ok(result.toJSONString()).build(); + return Response.ok((StreamingOutput) (OutputStream output)->result.writeJSONString(new BufferedWriter(new OutputStreamWriter(output)))).build(); } @Path("{objectType}/{typeRelativeObjectId}/acl") @@ -151,7 +155,7 @@ public class OwnershipResource extends AbstractSecurityResource { actionsForGroup.put(KEY_ACTIONS, actions); } } - return Response.ok(result.toJSONString()).build(); + return Response.ok((StreamingOutput) (OutputStream output)->result.writeJSONString(new BufferedWriter(new OutputStreamWriter(output)))).build(); } @Path("{objectType}/{typeRelativeObjectId}/acl") diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/RoleResource.java b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/RoleResource.java index 6f7d2d4d058..d0ac15fce7d 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/RoleResource.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/RoleResource.java @@ -57,7 +57,7 @@ public class RoleResource extends AbstractSecurityResource { jsonResult.put(KEY_PERMISSIONS, new JSONArray()); jsonResult.put(KEY_ROLE_ID, role.getId().toString()); jsonResult.put(KEY_ROLE_NAME, role.getName()); - resp = Response.status(Status.CREATED).entity(jsonResult.toJSONString()).build(); + resp = Response.status(Status.CREATED).entity(streamingOutput(jsonResult)).build(); } return resp; } @@ -175,7 +175,7 @@ public class RoleResource extends AbstractSecurityResource { jsonResult.put(KEY_PERMISSIONS, jsonPermissions); jsonResult.put(KEY_ROLE_ID, roleId); jsonResult.put(KEY_ROLE_NAME, roleDefinition.getName()); - resp = Response.ok(jsonResult.toJSONString()).build(); + resp = Response.ok(streamingOutput(jsonResult)).build(); } } catch (IllegalArgumentException e) { resp = Response.status(Status.BAD_REQUEST).entity("Invalid roleId.").build(); diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/SecurityResource.java b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/SecurityResource.java index 2a51eee8ca5..dcb47a768a3 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/SecurityResource.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/SecurityResource.java @@ -54,7 +54,7 @@ public class SecurityResource extends AbstractSecurityResource { result.put("principal", subject.getPrincipal().toString()); result.put("authenticated", subject.isAuthenticated()); result.put("remembered", subject.isRemembered()); - return Response.ok(result.toJSONString(), MediaType.APPLICATION_JSON_TYPE).build(); + return Response.ok(streamingOutput(result), MediaType.APPLICATION_JSON_TYPE).build(); } /** @@ -183,7 +183,7 @@ public class SecurityResource extends AbstractSecurityResource { result.put("fullName", user.getFullName()); result.put("email", user.getEmail()); result.put("company", user.getCompany()); - return Response.ok(result.toJSONString()).build(); + return Response.ok(streamingOutput(result)).build(); } else { return Response.status(Status.UNAUTHORIZED).build(); } @@ -333,6 +333,6 @@ public class SecurityResource extends AbstractSecurityResource { } } response.put("access_token", accessToken); - return Response.ok(response.toJSONString(), MediaType.APPLICATION_JSON_TYPE).build(); + return Response.ok(streamingOutput(response), MediaType.APPLICATION_JSON_TYPE).build(); } } \ No newline at end of file diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/UserGroupResource.java b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/UserGroupResource.java index edb7926e832..acb6272b6d6 100644 --- a/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/UserGroupResource.java +++ b/java/com.sap.sse.security/src/com/sap/sse/security/jaxrs/api/UserGroupResource.java @@ -77,7 +77,7 @@ public class UserGroupResource extends AbstractSecurityResource { } else { if (getService().hasCurrentUserReadPermission(usergroup)) { final JSONObject jsonResult = convertUserGroupToJson(usergroup); - response = Response.ok(jsonResult.toJSONString()).build(); + response = Response.ok(streamingOutput(jsonResult)).build(); } else { response = Response.status(Status.UNAUTHORIZED).build(); } @@ -141,7 +141,7 @@ public class UserGroupResource extends AbstractSecurityResource { if (group == null) { response = Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not create user group.").build(); } else { - response = Response.status(Status.CREATED).entity(convertUserGroupToJson(group).toJSONString()).build(); + response = Response.status(Status.CREATED).entity(streamingOutput(convertUserGroupToJson(group))).build(); } } diff --git a/java/com.sap.sse.threadmanager/META-INF/MANIFEST.MF b/java/com.sap.sse.threadmanager/META-INF/MANIFEST.MF index 7fb367aed15..031e2c6225a 100644 --- a/java/com.sap.sse.threadmanager/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.threadmanager/META-INF/MANIFEST.MF @@ -14,7 +14,8 @@ Require-Bundle: com.sun.jersey;bundle-version="1.17.0", com.sap.sse.security.common, com.sap.sse.security.userstore.mongodb, com.sap.sse, - com.sap.sse.common + com.sap.sse.common, + com.sap.sse.shared.android Import-Package: javax.ws.rs;version="1.1.1", javax.ws.rs.core, org.osgi.framework;version="1.8.0" diff --git a/java/com.sap.sse.threadmanager/src/com/sap/sse/threadmanager/ThreadManager.java b/java/com.sap.sse.threadmanager/src/com/sap/sse/threadmanager/ThreadManager.java index 73066ab3b5a..cb68c35166c 100644 --- a/java/com.sap.sse.threadmanager/src/com/sap/sse/threadmanager/ThreadManager.java +++ b/java/com.sap.sse.threadmanager/src/com/sap/sse/threadmanager/ThreadManager.java @@ -13,8 +13,10 @@ import javax.ws.rs.core.Response.Status; import org.json.simple.JSONArray; import org.json.simple.JSONObject; +import com.sap.sse.rest.StreamingOutputUtil; + @Path("/threads") -public class ThreadManager { +public class ThreadManager extends StreamingOutputUtil { @Context ServletContext servletContext; @Path("") @@ -56,12 +58,11 @@ public class ThreadManager { found = true; } } - String json = result.toJSONString(); if (!found) { result.put("status", "Not found"); - response = Response.status(Status.NOT_FOUND).entity(json).build(); + response = Response.status(Status.NOT_FOUND).entity(streamingOutput(result)).build(); } else { - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(streamingOutput(result), MediaType.APPLICATION_JSON).build(); } return response; } @@ -83,12 +84,11 @@ public class ThreadManager { found = true; } } - String json = result.toJSONString(); if (!found) { result.put("status", "Not found"); - response = Response.status(Status.NOT_FOUND).entity(json).build(); + response = Response.status(Status.NOT_FOUND).entity(streamingOutput(result)).build(); } else { - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(streamingOutput(result), MediaType.APPLICATION_JSON).build(); } return response; } @@ -109,12 +109,11 @@ public class ThreadManager { found = true; } } - String json = result.toJSONString(); if (!found) { result.put("status", "Not found"); - response = Response.status(Status.NOT_FOUND).entity(json).build(); + response = Response.status(Status.NOT_FOUND).entity(streamingOutput(result)).build(); } else { - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(streamingOutput(result), MediaType.APPLICATION_JSON).build(); } return response; } @@ -136,12 +135,11 @@ public class ThreadManager { found = true; } } - String json = result.toJSONString(); if (!found) { result.put("status", "Not found"); - response = Response.status(Status.NOT_FOUND).entity(json).build(); + response = Response.status(Status.NOT_FOUND).entity(streamingOutput(result)).build(); } else { - response = Response.ok(json, MediaType.APPLICATION_JSON).build(); + response = Response.ok(streamingOutput(result), MediaType.APPLICATION_JSON).build(); } return response; } diff --git a/java/com.sap.sse/META-INF/MANIFEST.MF b/java/com.sap.sse/META-INF/MANIFEST.MF index 7baf293be28..c75ed1cf2ba 100644 --- a/java/com.sap.sse/META-INF/MANIFEST.MF +++ b/java/com.sap.sse/META-INF/MANIFEST.MF @@ -13,6 +13,7 @@ Export-Package: com.sap.sse, com.sap.sse.pairinglist, com.sap.sse.pairinglist.impl, com.sap.sse.qrcode, + com.sap.sse.rest, com.sap.sse.util, com.sap.sse.util.graph, com.sap.sse.util.impl, @@ -27,6 +28,7 @@ Require-Bundle: com.sap.sse.common, org.apache.httpcomponents.httpcore;bundle-version="4.2.5" Import-Package: javax.servlet;version="3.1.0", javax.servlet.http;version="3.1.0", + javax.ws.rs.core;version="1.1.1", org.osgi.framework;version="1.8.0", org.osgi.util.tracker;version="1.5.1" Automatic-Module-Name: com.sap.sse diff --git a/java/com.sap.sse/src/com/sap/sse/rest/StreamingOutputUtil.java b/java/com.sap.sse/src/com/sap/sse/rest/StreamingOutputUtil.java new file mode 100755 index 00000000000..bb32485795c --- /dev/null +++ b/java/com.sap.sse/src/com/sap/sse/rest/StreamingOutputUtil.java @@ -0,0 +1,55 @@ +package com.sap.sse.rest; + +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; + +import javax.ws.rs.core.StreamingOutput; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; + +public class StreamingOutputUtil { + protected StreamingOutput streamingOutput(JSONObject jsonObject) { + return new StreamingOutput() { + @Override + public void write(OutputStream output) throws IOException { + BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter( + output, "UTF8")); + jsonObject.writeJSONString(bufferedWriter); + bufferedWriter.flush(); + } + }; + } + + protected StreamingOutput streamingOutput(JSONArray jsonArray) { + return new StreamingOutput() { + @Override + public void write(OutputStream output) throws IOException { + BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter( + output, "UTF8")); + jsonArray.writeJSONString(bufferedWriter); + bufferedWriter.flush(); + } + }; + } + + /** + * If the {@code entity} is a {@link StreamingOutput}, the stream will first be read and then converted to a + * {@link String}. Otherwise, the {@link Object#toString()} method is used to convert the {@code entity} into a + * string. + */ + public static String getEntityAsString(Object entity) throws IOException { + final String result; + if (entity instanceof StreamingOutput) { + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ((StreamingOutput) entity).write(bos); + return bos.toString("UTF8"); + } else { + result = entity.toString(); + } + return result; + } +} diff --git a/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF b/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF index c80bd73e7de..1cb98d67764 100644 --- a/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF +++ b/java/com.tractrac.clientmodule/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: TracTrac Client module Bundle-SymbolicName: com.tractrac.clientmodule -Bundle-Version: 3.13.1 +Bundle-Version: 3.13.3 Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-ClassPath: ., lib/TracAPI.jar diff --git a/java/com.tractrac.clientmodule/README.txt b/java/com.tractrac.clientmodule/README.txt index dd310b44c70..4f85157219d 100644 --- a/java/com.tractrac.clientmodule/README.txt +++ b/java/com.tractrac.clientmodule/README.txt @@ -16,6 +16,32 @@ It contains also some files: - test.sh -> script that compiles the code in the src folder, creates the test.jar library and execute the code of the example. - Manifest.txt -> manifest used to create the test.jar file +******************************************** + TracAPI 3.13.3 +******************************************** +This is a final version. The only difference with the previous version is the JDK used to compile the sources. +It keeps the backward compatibility. + + Release date: 01/05/2020 + Build number: dfa0d7732ebb374236628868810547d28a357f92 + + 1) Bugs + + - The previous version was compiled using Java 13 (Reported by Axel Uhl, 01/05/2020) + +******************************************** + TracAPI 3.13.2 +******************************************** +This is a final version. It adds fixes some features. It keeps the backward compatibility. + +Release date: 30/04/2020 +Build number: 242936347afa7ec28fc8b61996caf92693ab11af + +1) Bugs + + - Checking if a control exists before to add it to the route (Reported by Axel Uhl, 24/03/2020) + - The EventFactory has to synchronize the access to the "Map of IControls" (Reported by Axel Uhl, 30/04/2020) + ******************************************** TracAPI 3.13.1 ******************************************** diff --git a/java/com.tractrac.clientmodule/lib/TracAPI-src.jar b/java/com.tractrac.clientmodule/lib/TracAPI-src.jar index d12b4c8ce9f..4cf5caf8978 100644 Binary files a/java/com.tractrac.clientmodule/lib/TracAPI-src.jar and b/java/com.tractrac.clientmodule/lib/TracAPI-src.jar differ diff --git a/java/com.tractrac.clientmodule/lib/TracAPI.jar b/java/com.tractrac.clientmodule/lib/TracAPI.jar index 8bd14fbfa72..59eff949063 100644 Binary files a/java/com.tractrac.clientmodule/lib/TracAPI.jar and b/java/com.tractrac.clientmodule/lib/TracAPI.jar differ diff --git a/java/com.tractrac.clientmodule/pom.xml b/java/com.tractrac.clientmodule/pom.xml index 1d189185bb2..a97d6416809 100755 --- a/java/com.tractrac.clientmodule/pom.xml +++ b/java/com.tractrac.clientmodule/pom.xml @@ -8,6 +8,6 @@ 1.0.0-SNAPSHOT com.tractrac.clientmodule - 3.13.1 + 3.13.3 eclipse-plugin diff --git a/wiki/info/landscape/support-email.md b/wiki/info/landscape/support-email.md index 2337917bec0..9ec05242da2 100644 --- a/wiki/info/landscape/support-email.md +++ b/wiki/info/landscape/support-email.md @@ -1,14 +1,54 @@ -# Set Up of Support E Mail Address support@sapsailing.com with AWS SES/SNS/Lambda +## Email Accounts and Email Forwarding -We use AWS SES for all e-mail services, inbound and outbound. See also [Amazon Simple Email Service (SES) Set-Up](wiki/info/landscape/mail-relaying) for details on the general SES set-up. We have established ``support@sapsailing.com`` now as another inbound e-mail address that stores the incoming email messages in a S3 bucket called ``SupportMails``. After being stored, they will notify a SNS topic called ``SupportMailStoredInS3``. +### 1. General Information +We currently use two different methods to handle incoming emails. One is a full-fletched email account, including a mailbox and 50GB storage quota. Those come at a price of currently 4$ per user per month [Amazon WorkMail Pricing](https://aws.amazon.com/workmail/pricing/). It also includes a Webmailer. -From there a Lambda function picks them up, modifies the original headers and sends out the Email to a JSON array of recipients, configurable in the ``MailRecipientsJSON`` environment variable of the ``support-email-forwarding-python`` Lambda. +The second is a simple email forwarder, using a [Amazon Simple Email Service (SES) Set-Up](wiki/info/landscape/mail-relaying) rule to handle incoming emails and forward them to a specified list of recipients. -The Lambda preserves the original ``From`` and ``To`` headers by adding the value to new headers called ``X-From`` and ``X-To``. In addition it sets the ``Reply-To`` header field to the initial ``From`` value if blank. The new ``From`` value is configured in the ``MailSender`` environment variable, currently set to: ``SES Email Forwarder ``. +#### When to use what +If you need a working email, including inbox, IMAP access etc., account then proceed with a Workmail account. If you just want to forward emails for a given user (e.g. no-reply) then use the lambda method. -The role that is created to execute the Lambda needs to have a policy set that can access SES and write logs. See also [https://aws.amazon.com/blogs/messaging-and-targeting/forward-incoming-email-to-an-external-destination/](https://aws.amazon.com/blogs/messaging-and-targeting/forward-incoming-email-to-an-external-destination/) +### 2. WorkMail + +#### Configuration +We created a WorkMail organization (sapsailing). Also the following DNS entries for sapsailing.com have been modified: +Created: +`CNAME autodiscover.sapsailing.com. autodiscover.mail.eu-west-1.awsapps.com` +`TXT _dmarc.sapsailing.com. "v=DMARC1;p=quarantine;pct=100;fo=1"` + +Modified: +before: +`TXT sapsailing.com "v=spf1 mx ip4:54.229.94.254 include:mail.zendesk.com include:servers.mcsv.net -all"` +after: +`TXT sapsailing.com "v=spf1 mx ip4:54.229.94.254 include:amazonses.com include:mail.zendesk.com include:servers.mcsv.net -all"` + +There is a user created in WorkMail, ``support@sapsailing.com``. For this user we created a redirect for all incoming emails, using the [webmail access](https://sapsailing.awsapps.com/mail) and following the instructions provided here [Working with email rules](https://docs.aws.amazon.com/workmail/latest/userguide/email-rules.html). + +#### Create new user or change existing +Simply follow the instructions here: [Managing user accounts](https://docs.aws.amazon.com/workmail/latest/adminguide/manage-users.html). + +### 3. Lambda Forwarder + +#### current set-up description +We have established a couple of email addresses to use the ``email-forwarder-python`` Lambda to handle incoming emails. Therefore there is a SES rule that stores incoming emails for those addresses to a S3 bucket called ``emails-for-sapsailing-com`` and notifies the SNS topic ``email-forwarder-for-sapsailing-com``. + +From there a Lambda function picks them up, modifies the original headers and sends out the Email to a JSON array of recipients, configurable in the ``MailRecipientsJSON`` environment variable of the ``email-forwarder-python`` Lambda. + +The Lambda preserves the original ``From`` and ``To`` headers by adding the value to new headers called ``X-From`` and ``X-To``. In addition it sets the ``Reply-To`` header field to the initial ``From`` value if blank. The new ``From`` value is configurable in the ``MailSender`` environment variable. + +The role ``lambda-email-forwarder-role`` is created to execute the Lambda. The policy ``lambda-email-forward-policy`` is attached to that role. See also [https://aws.amazon.com/blogs/messaging-and-targeting/forward-incoming-email-to-an-external-destination/](https://aws.amazon.com/blogs/messaging-and-targeting/forward-incoming-email-to-an-external-destination/) for further information about the whole setup. + +In addition there is an alarm ``Email-Forwarding-Failed-Alarm`` configured, which posts to ``email-forwarder-for-sapsailing-com-alarms`` topic. The relevant files have been committed to our git as ``configuration/mail_forward.py`` for the Lambda's code, and as ``configuration/mail_forward_policy.json`` for the security policy for the IAM role used for the Lambda. -## Changing the List of Recipients -Go to [https://eu-west-1.console.aws.amazon.com/lambda/home?region=eu-west-1#/functions/support-email-forwarding-python?tab=configuration](https://eu-west-1.console.aws.amazon.com/lambda/home?region=eu-west-1#/functions/support-email-forwarding-python?tab=configuration) and edit the ``MailRecipientsJSON`` environment variable accordingly. E.g.: ``["yourfirstemail@yourdomain.com", "yoursecondemail@yourseconddomain.com"]`` \ No newline at end of file +#### Change the list of recipients +Go to [https://eu-west-1.console.aws.amazon.com/lambda/home?region=eu-west-1#/functions/email-forwarder-python?tab=configuration](https://eu-west-1.console.aws.amazon.com/lambda/home?region=eu-west-1#/functions/email-forwarder-python?tab=configuration) and edit the ``MailRecipientsJSON`` environment variable accordingly. So if you want to change the recipient list for support@sapsailing.com change the JSON array to the desired list. +``{"support@sapsailing.com": ["oldrecipient1@abc.de", "newrecipient2@abc.de"]}`` + +#### Add a new forwarded address +The method described above is extensible. You can configure new email addresses to be forwarded by the forwarder. To do so you need to create a new rule in the default rule set for Email Receiving in the SES console [https://eu-west-1.console.aws.amazon.com/ses/home?region=eu-west-1#rule-set:default-rule-set](https://eu-west-1.console.aws.amazon.com/ses/home?region=eu-west-1#rule-set:default-rule-set). You need to specify the email address that you want to forward, store it in the S3 bucket mentioned above and use the address as object prefix. After that you need to add the desired recipients for that address to the MailRecipientsJSON in the lambda configuration. You may also add a key,value pair in the MailSenderJSON to specify a name from which you want to send the email, however this is not mandatory as the forwarder will default to the forwarded address. + +#### Limitations +The email forwarder forwards 'To', 'Cc' and 'Bcc' headers, however not every use case for normal emails is handled. Keep in mind that this is not a email account, but rather a simple forwarder to be used for service accounts. +A known limitation is that the forwarding is not working correct if the original email handled by the fowarder contains two different email addresses handled by the forwarder in the recipients. \ No newline at end of file