b0f844514d7b2bcefc6c12dfe20f9d1a008c3dde
java/com.sap.sailing.polars/src/com/sap/sailing/polars/impl/PolarDataServiceImpl.java
| ... | ... | @@ -74,6 +74,13 @@ public class PolarDataServiceImpl extends AbstractReplicableWithObjectInputStrea |
| 74 | 74 | resetState(); |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | + public PolarDataServiceImpl filterToBoatClasses(Iterable<BoatClass> boatClassesToFilterTo) { |
|
| 78 | + final PolarDataMiner filteredPolarDataMiner = polarDataMiner.filterToBoatClasses(boatClassesToFilterTo); |
|
| 79 | + final PolarDataServiceImpl filteredService = new PolarDataServiceImpl(); |
|
| 80 | + filteredService.polarDataMiner = filteredPolarDataMiner; |
|
| 81 | + return filteredService; |
|
| 82 | + } |
|
| 83 | + |
|
| 77 | 84 | @Override |
| 78 | 85 | public void resetState() { |
| 79 | 86 | PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createBackendPolarSettings(); |
java/com.sap.sailing.polars/src/com/sap/sailing/polars/jaxrs/api/PolarDataResource.java
| ... | ... | @@ -2,11 +2,13 @@ package com.sap.sailing.polars.jaxrs.api; |
| 2 | 2 | |
| 3 | 3 | import java.io.IOException; |
| 4 | 4 | import java.io.OutputStream; |
| 5 | +import java.util.List; |
|
| 5 | 6 | import java.util.logging.Logger; |
| 6 | 7 | |
| 7 | 8 | import javax.ws.rs.GET; |
| 8 | 9 | import javax.ws.rs.Path; |
| 9 | 10 | import javax.ws.rs.Produces; |
| 11 | +import javax.ws.rs.QueryParam; |
|
| 10 | 12 | import javax.ws.rs.WebApplicationException; |
| 11 | 13 | import javax.ws.rs.core.Response; |
| 12 | 14 | import javax.ws.rs.core.StreamingOutput; |
| ... | ... | @@ -14,9 +16,12 @@ import javax.ws.rs.core.StreamingOutput; |
| 14 | 16 | import org.apache.shiro.SecurityUtils; |
| 15 | 17 | import org.apache.shiro.subject.Subject; |
| 16 | 18 | |
| 19 | +import com.sap.sailing.domain.base.BoatClass; |
|
| 17 | 20 | import com.sap.sailing.domain.common.security.SecuredDomainType; |
| 21 | +import com.sap.sailing.polars.impl.PolarDataServiceImpl; |
|
| 18 | 22 | import com.sap.sailing.polars.jaxrs.AbstractPolarResource; |
| 19 | 23 | import com.sap.sse.ServerInfo; |
| 24 | +import com.sap.sse.common.Util; |
|
| 20 | 25 | import com.sap.sse.security.shared.HasPermissions.DefaultActions; |
| 21 | 26 | import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; |
| 22 | 27 | |
| ... | ... | @@ -26,7 +31,7 @@ public class PolarDataResource extends AbstractPolarResource { |
| 26 | 31 | |
| 27 | 32 | @GET |
| 28 | 33 | @Produces("application/octet-stream;charset=UTF-8") |
| 29 | - public Response getRegressions() throws IOException { |
|
| 34 | + public Response getRegressions(@QueryParam("boatClassName") final List<String> boatClassNames) throws IOException { |
|
| 30 | 35 | final Subject subject = SecurityUtils.getSubject(); |
| 31 | 36 | logger.info("Polar Data requested by "+ (subject.getPrincipal() == null ? "anonymous user" : subject.getPrincipal().toString())); |
| 32 | 37 | subject.checkPermission(SecuredDomainType.POLAR_DATA.getStringPermissionForTypeRelativeIdentifier(DefaultActions.READ, |
| ... | ... | @@ -34,7 +39,24 @@ public class PolarDataResource extends AbstractPolarResource { |
| 34 | 39 | return Response.ok(new StreamingOutput() { |
| 35 | 40 | @Override |
| 36 | 41 | public void write(OutputStream output) throws IOException, WebApplicationException { |
| 37 | - getPolarDataServiceImpl().serializeForInitialReplication(output); |
|
| 42 | + PolarDataServiceImpl polarDataService = getPolarDataServiceImpl(); |
|
| 43 | + @SuppressWarnings("unchecked") |
|
| 44 | + final Iterable<BoatClass>[] boatClassesToFilterTo = new Iterable[1]; |
|
| 45 | + if (boatClassNames == null || boatClassNames.isEmpty()) { |
|
| 46 | + boatClassesToFilterTo[0] = null; |
|
| 47 | + } else { |
|
| 48 | + try { |
|
| 49 | + polarDataService.runWithDomainFactory(domainFactory->{ |
|
| 50 | + boatClassesToFilterTo[0] = Util.map(boatClassNames, bcn->domainFactory.getBoatClass(bcn)); |
|
| 51 | + }); |
|
| 52 | + } catch (InterruptedException e) { |
|
| 53 | + throw new RuntimeException(e); |
|
| 54 | + } |
|
| 55 | + } |
|
| 56 | + if (boatClassesToFilterTo[0] != null) { |
|
| 57 | + polarDataService = polarDataService.filterToBoatClasses(boatClassesToFilterTo[0]); |
|
| 58 | + } |
|
| 59 | + polarDataService.serializeForInitialReplication(output); |
|
| 38 | 60 | } |
| 39 | 61 | }).header("Content-Type", "application/octet-stream").build(); |
| 40 | 62 | } |
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/CubicRegressionPerCourseProcessor.java
| ... | ... | @@ -18,11 +18,13 @@ import com.sap.sailing.domain.common.Tack; |
| 18 | 18 | import com.sap.sailing.domain.common.polars.NotEnoughDataHasBeenAddedException; |
| 19 | 19 | import com.sap.sailing.domain.polars.PolarsChangedListener; |
| 20 | 20 | import com.sap.sse.common.Speed; |
| 21 | +import com.sap.sse.common.Util; |
|
| 21 | 22 | import com.sap.sse.datamining.components.AdditionalResultDataBuilder; |
| 22 | 23 | import com.sap.sse.datamining.components.Processor; |
| 23 | 24 | import com.sap.sse.datamining.factories.GroupKeyFactory; |
| 24 | 25 | import com.sap.sse.datamining.impl.components.GroupedDataEntry; |
| 25 | 26 | import com.sap.sse.datamining.shared.GroupKey; |
| 27 | +import com.sap.sse.datamining.shared.impl.GenericGroupKey; |
|
| 26 | 28 | |
| 27 | 29 | /** |
| 28 | 30 | * Groups incoming fixes by boatclass and legtype into {@link AngleAndSpeedRegression} instances and |
| ... | ... | @@ -45,6 +47,40 @@ public class CubicRegressionPerCourseProcessor implements |
| 45 | 47 | */ |
| 46 | 48 | private transient ConcurrentMap<BoatClass, Set<PolarsChangedListener>> listeners; |
| 47 | 49 | |
| 50 | + public CubicRegressionPerCourseProcessor filterToBoatClasses(Iterable<BoatClass> boatClasses) { |
|
| 51 | + final Set<BoatClass> allowedBoatClasses = Util.asSet(boatClasses); |
|
| 52 | + final CubicRegressionPerCourseProcessor filteredProcessor = new CubicRegressionPerCourseProcessor(); |
|
| 53 | + for (final Map.Entry<GroupKey, AngleAndSpeedRegression> entry : regressions.entrySet()) { |
|
| 54 | + GroupKey key = entry.getKey(); |
|
| 55 | + BoatClass boatClass = extractBoatClass(key); |
|
| 56 | + if (boatClass != null && allowedBoatClasses.contains(boatClass)) { |
|
| 57 | + filteredProcessor.regressions.put(key, entry.getValue()); |
|
| 58 | + } |
|
| 59 | + } |
|
| 60 | + return filteredProcessor; |
|
| 61 | + } |
|
| 62 | + |
|
| 63 | + private BoatClass extractBoatClass(GroupKey key) { |
|
| 64 | + final BoatClass result; |
|
| 65 | + if (key.hasSubKeys()) { |
|
| 66 | + // In the compound key, BoatClass is the second dimension (index 1) |
|
| 67 | + GroupKey boatClassKey = key.getKeys().get(1); |
|
| 68 | + if (boatClassKey instanceof GenericGroupKey) { |
|
| 69 | + Object value = ((GenericGroupKey<?>) boatClassKey).getValue(); |
|
| 70 | + if (value instanceof BoatClass) { |
|
| 71 | + result = (BoatClass) value; |
|
| 72 | + } else { |
|
| 73 | + result = null; |
|
| 74 | + } |
|
| 75 | + } else { |
|
| 76 | + result = null; |
|
| 77 | + } |
|
| 78 | + } else { |
|
| 79 | + result = null; |
|
| 80 | + } |
|
| 81 | + return result; |
|
| 82 | + } |
|
| 83 | + |
|
| 48 | 84 | @Override |
| 49 | 85 | public boolean canProcessElements() { |
| 50 | 86 | return true; |
| ... | ... | @@ -109,7 +145,6 @@ public class CubicRegressionPerCourseProcessor implements |
| 109 | 145 | |
| 110 | 146 | private GroupKey createGroupKey(final BoatClass boatClass, final LegType legType) { |
| 111 | 147 | LegTypePolarClusterKey key = new LegTypePolarClusterKey() { |
| 112 | - |
|
| 113 | 148 | @Override |
| 114 | 149 | public BoatClass getBoatClass() { |
| 115 | 150 | return boatClass; |
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataDimensionCollectionFactory.java
| ... | ... | @@ -40,7 +40,6 @@ public class PolarDataDimensionCollectionFactory { |
| 40 | 40 | Collection<Function<?>> dimensions = new ArrayList<>(); |
| 41 | 41 | FunctionFactory functionFactory = new FunctionFactory(); |
| 42 | 42 | addTackAndLegTypeDimensions(dimensions, functionFactory); |
| 43 | - |
|
| 44 | 43 | addPolarBaseDimension(dimensions, functionFactory); |
| 45 | 44 | return dimensions; |
| 46 | 45 | } |
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/PolarDataMiner.java
| ... | ... | @@ -136,6 +136,13 @@ public class PolarDataMiner { |
| 136 | 136 | throw new RuntimeException(e); |
| 137 | 137 | } |
| 138 | 138 | } |
| 139 | + |
|
| 140 | + public PolarDataMiner filterToBoatClasses(Iterable<BoatClass> boatClasses) { |
|
| 141 | + return new PolarDataMiner(backendPolarSheetGenerationSettings, |
|
| 142 | + cubicRegressionPerCourseProcessor.filterToBoatClasses(boatClasses), |
|
| 143 | + speedRegressionPerAngleClusterProcessor.filterToBoatClasses(boatClasses), |
|
| 144 | + angleClusterGroup); |
|
| 145 | + } |
|
| 139 | 146 | |
| 140 | 147 | private void setUpWorkflow() throws ClassCastException, NoSuchMethodException, SecurityException { |
| 141 | 148 | Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>(); |
java/com.sap.sailing.polars/src/com/sap/sailing/polars/mining/SpeedRegressionPerAngleClusterProcessor.java
| ... | ... | @@ -23,6 +23,7 @@ import com.sap.sailing.polars.regression.IncrementalLeastSquares; |
| 23 | 23 | import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImpl; |
| 24 | 24 | import com.sap.sse.common.Bearing; |
| 25 | 25 | import com.sap.sse.common.Speed; |
| 26 | +import com.sap.sse.common.Util; |
|
| 26 | 27 | import com.sap.sse.common.Util.Pair; |
| 27 | 28 | import com.sap.sse.common.impl.DegreeBearingImpl; |
| 28 | 29 | import com.sap.sse.datamining.components.AdditionalResultDataBuilder; |
| ... | ... | @@ -32,6 +33,7 @@ import com.sap.sse.datamining.data.ClusterGroup; |
| 32 | 33 | import com.sap.sse.datamining.factories.GroupKeyFactory; |
| 33 | 34 | import com.sap.sse.datamining.impl.components.GroupedDataEntry; |
| 34 | 35 | import com.sap.sse.datamining.shared.GroupKey; |
| 36 | +import com.sap.sse.datamining.shared.impl.GenericGroupKey; |
|
| 35 | 37 | |
| 36 | 38 | /** |
| 37 | 39 | * Holds one speed regression per BoatClass, WindSpeed, Beat Angle Range combination and provides means for adding and |
| ... | ... | @@ -63,6 +65,49 @@ public class SpeedRegressionPerAngleClusterProcessor implements |
| 63 | 65 | this.angleClusterGroup = angleClusterGroup; |
| 64 | 66 | } |
| 65 | 67 | |
| 68 | + public SpeedRegressionPerAngleClusterProcessor filterToBoatClasses(Iterable<BoatClass> boatClasses) { |
|
| 69 | + final Set<BoatClass> allowedBoatClasses = Util.asSet(boatClasses); |
|
| 70 | + final SpeedRegressionPerAngleClusterProcessor filteredProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup); |
|
| 71 | + synchronized (regressions) { |
|
| 72 | + for (Map.Entry<GroupKey, IncrementalLeastSquares> entry : regressions.entrySet()) { |
|
| 73 | + GroupKey key = entry.getKey(); |
|
| 74 | + BoatClass boatClass = extractBoatClass(key); |
|
| 75 | + if (boatClass != null && allowedBoatClasses.contains(boatClass)) { |
|
| 76 | + filteredProcessor.regressions.put(key, entry.getValue()); |
|
| 77 | + } |
|
| 78 | + } |
|
| 79 | + } |
|
| 80 | + synchronized (fixCountPerBoatClass) { |
|
| 81 | + for (Map.Entry<BoatClass, Long> entry : fixCountPerBoatClass.entrySet()) { |
|
| 82 | + if (allowedBoatClasses.contains(entry.getKey())) { |
|
| 83 | + filteredProcessor.fixCountPerBoatClass.put(entry.getKey(), entry.getValue()); |
|
| 84 | + } |
|
| 85 | + } |
|
| 86 | + } |
|
| 87 | + return filteredProcessor; |
|
| 88 | + } |
|
| 89 | + |
|
| 90 | + private BoatClass extractBoatClass(GroupKey key) { |
|
| 91 | + final BoatClass result; |
|
| 92 | + if (key.hasSubKeys()) { |
|
| 93 | + // In the compound key, BoatClass is the first dimension (index 0) |
|
| 94 | + GroupKey boatClassKey = key.getKeys().get(0); |
|
| 95 | + if (boatClassKey instanceof GenericGroupKey) { |
|
| 96 | + Object value = ((GenericGroupKey<?>) boatClassKey).getValue(); |
|
| 97 | + if (value instanceof BoatClass) { |
|
| 98 | + result = (BoatClass) value; |
|
| 99 | + } else { |
|
| 100 | + result = null; |
|
| 101 | + } |
|
| 102 | + } else { |
|
| 103 | + result = null; |
|
| 104 | + } |
|
| 105 | + } else { |
|
| 106 | + result = null; |
|
| 107 | + } |
|
| 108 | + return result; |
|
| 109 | + } |
|
| 110 | + |
|
| 66 | 111 | @Override |
| 67 | 112 | public boolean canProcessElements() { |
| 68 | 113 | // TODO Auto-generated method stub |