From 8580ac3b9861ae7541b18bc6f4cd556f40e60476 Mon Sep 17 00:00:00 2001 From: Axel Uhl Date: Thu, 19 Sep 2019 20:09:43 +0200 Subject: [PATCH] preparing for certificate upload servlet Change-Id: Ic424683d1bebb4a9c6f62f8353c073eda387b84d --- .../domain/common/orc/ORCCertificate.java | 9 ++- .../orc/ORCCertificateUploadConstants.java | 14 ++++ .../common/orc/impl/ORCCertificateImpl.java | 22 ++++-- .../impl/ORCCertificatesCollectionJSON.java | 24 +++++-- .../impl/ORCCertificatesCollectionRMS.java | 13 ++-- .../impl/ORCCertificateJsonDeserializer.java | 13 ++-- .../impl/ORCCertificateJsonSerializer.java | 2 + .../ORCCertificateSelectionDeserializer.java | 15 +++++ .../orc/ORCCertificateImportServlet.java | 67 +++++++++++++++++++ .../sap/sse/common/impl/AbstractDuration.java | 5 +- 10 files changed, 157 insertions(+), 27 deletions(-) create mode 100755 java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificateUploadConstants.java create mode 100755 java/com.sap.sailing.server.gateway.serialization/src/com/sap/sailing/server/gateway/deserialization/impl/ORCCertificateSelectionDeserializer.java create mode 100755 java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/orc/ORCCertificateImportServlet.java diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java index 06a6c98e595..7c3c9e96ed8 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificate.java @@ -7,6 +7,7 @@ import com.sap.sse.common.Bearing; import com.sap.sse.common.Distance; import com.sap.sse.common.Duration; import com.sap.sse.common.Speed; +import com.sap.sse.common.WithID; /** * Represents semantically a real ORC certificate for a {@link Competitor}, which is used to rate different type of @@ -17,13 +18,17 @@ import com.sap.sse.common.Speed; * too. *

* One implementing class provides all necessary functionalities to score the Competitors with a choosen - * {@link RankingMetric}. + * {@link RankingMetric}.

* + * The {@link WithID} interface is to be implemented such that a {@link String} is produced as the ID that + * contains the concatenation (without intermediate white space) of the {@code NatAuth}, the {@code CertNo} + * and the {@code BIN} fields, as provided as single fields in the JSON representation, and as provided + * in the concatenated form in the {@code NATCERTN.FILE_ID} column in the RMS format. * * @author Daniel Lisunkin (i505543) * */ -public interface ORCCertificate extends Serializable { +public interface ORCCertificate extends WithID, Serializable { /** * Returns the sailnumber of the {@link Competitor} which this certificate belongs to. * diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificateUploadConstants.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificateUploadConstants.java new file mode 100755 index 00000000000..4a116cd7475 --- /dev/null +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/ORCCertificateUploadConstants.java @@ -0,0 +1,14 @@ +package com.sap.sailing.domain.common.orc; + +/** + * Constants for parameters and response document fields for the {@link ORCCertificateImportServlet}. + * + * @author Axel Uhl (d043530) + * + */ +public interface ORCCertificateUploadConstants { + String REGATTA_NAME = "regatta_name"; + String RACE_NAME = "race_name"; + String BOAT_ID = "boat_id"; + String CERTIFICATE_SELECTION = "certificate_selection"; +} diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java index a6eb866c5c9..e17a4fa854c 100644 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/orc/impl/ORCCertificateImpl.java @@ -23,6 +23,8 @@ import com.sap.sse.common.impl.DegreeBearingImpl; public class ORCCertificateImpl implements ORCCertificate { private static final long serialVersionUID = 8725162998514202782L; + + private final String idConsistingOfNatAuthCertNoAndBIN; /** * Equals the column heading of the allowances table of an ORC certificate. The speeds are set by the offshore @@ -108,15 +110,18 @@ public class ORCCertificateImpl implements ORCCertificate { private final Map nonSpinnakerSpeedPredictionPerTrueWindSpeed; - public ORCCertificateImpl(String sailnumber, String boatName, String boatclass, Distance length, - Duration gph, Double cdl, - Map> velocityPredictionsPerTrueWindSpeedAndAngle, Map beatAngles, - Map beatVMGPredictionPerTrueWindSpeed, Map beatAllowancePerTrueWindSpeed, - Map runAngles, Map runVMGPredictionPerTrueWindSpeed, + public ORCCertificateImpl(String idConsistingOfNatAuthCertNoAndBIN, String sailnumber, String boatName, String boatclass, + Distance length, Duration gph, + Double cdl, Map> velocityPredictionsPerTrueWindSpeedAndAngle, + Map beatAngles, Map beatVMGPredictionPerTrueWindSpeed, + Map beatAllowancePerTrueWindSpeed, Map runAngles, + Map runVMGPredictionPerTrueWindSpeed, Map runAllowancePerTrueWindSpeed, Map windwardLeewardSpeedPredictionsPerTrueWindSpeed, Map longDistanceSpeedPredictionsPerTrueWindSpeed, - Map circularRandomSpeedPredictionsPerTrueWindSpeed, Map nonSpinnakerSpeedPredictionsPerTrueWindSpeed) { + Map circularRandomSpeedPredictionsPerTrueWindSpeed, + Map nonSpinnakerSpeedPredictionsPerTrueWindSpeed) { + this.idConsistingOfNatAuthCertNoAndBIN = idConsistingOfNatAuthCertNoAndBIN; this.sailnumber = sailnumber; this.boatName = boatName; this.boatclass = boatclass; @@ -137,6 +142,11 @@ public class ORCCertificateImpl implements ORCCertificate { this.nonSpinnakerSpeedPredictionPerTrueWindSpeed = Collections.unmodifiableMap(nonSpinnakerSpeedPredictionsPerTrueWindSpeed); } + @Override + public String getId() { + return idConsistingOfNatAuthCertNoAndBIN; + } + @Override public String getBoatName() { return boatName; diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java index df261a9efdc..6d193e90a71 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionJSON.java @@ -78,8 +78,20 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec //TODO Throw Exception for sailnumber not found. InvalidArgumentException? return null; } + String natAuth = null; + String bin = null; + String certNo = null; for (Entry entry : object.entrySet()) { switch ((String) entry.getKey()) { + case "NatAuth": + natAuth = entry.getValue().toString(); + break; + case "BIN": + bin = entry.getValue().toString(); + break; + case "CertNo": + certNo = entry.getValue().toString(); + break; case "LOA": length = new MeterDistance(((Number) entry.getValue()).doubleValue()); break; @@ -177,12 +189,12 @@ public class ORCCertificatesCollectionJSON extends AbstractORCCertificatesCollec nonSpinnakerSpeedPredictionPerTrueWindSpeed.put(tws, ORCCertificateImpl.NAUTICAL_MILE .inTime(predefinedAllowanceDurationsPerTrueWindSpeed.get(NON_SPINNAKER).get(tws))); } - return new ORCCertificateImpl(searchString, boatName, boatclass, length, gph, - cdl, velocityPredictionPerTrueWindSpeedAndAngle, beatAngles, - beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, gybeAngles, - runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed, - windwardLeewardSpeedPredictionPerTrueWindSpeed, longDistanceSpeedPredictionPerTrueWindSpeed, - circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed); + return new ORCCertificateImpl(natAuth+certNo+bin, searchString, boatName, boatclass, length, + gph, cdl, velocityPredictionPerTrueWindSpeedAndAngle, + beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, + gybeAngles, runVMGPredictionPerTrueWindSpeed, + runAllowancePerTrueWindSpeed, windwardLeewardSpeedPredictionPerTrueWindSpeed, + longDistanceSpeedPredictionPerTrueWindSpeed, circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed); } @Override diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java index 92f5bbe4490..c1eac87ca15 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/orc/impl/ORCCertificatesCollectionRMS.java @@ -53,6 +53,7 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect private static final String LONG_DISTANCE = "OC"; private static final String CIRCULAR_RANDOM = "CR"; private static final String NON_SPINNAKER = "NSP"; + private static final String NATCERTN_FILE_ID = "NATCERTN.FILE_ID"; private final Map> certificateValuesBySailnumber; @@ -137,12 +138,12 @@ public class ORCCertificatesCollectionRMS extends AbstractORCCertificatesCollect } velocityPredictionsPerTrueWindSpeedAndAngle.put(tws, velocityPredictionPerTrueWindAngle); } - return new ORCCertificateImpl(searchString, boatName, boatclass, length, gph, - cdl, velocityPredictionsPerTrueWindSpeedAndAngle, beatAngles, - beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, runAngles, - runVMGPredictionPerTrueWindSpeed, runAllowancePerTrueWindSpeed, - windwardLeewardSpeedPredictionPerTrueWindSpeed, longDistanceSpeedPredictionPerTrueWindSpeed, - circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed); + return new ORCCertificateImpl(certificateValues.getValue(NATCERTN_FILE_ID), searchString, boatName, boatclass, length, + gph, cdl, velocityPredictionsPerTrueWindSpeedAndAngle, + beatAngles, beatVMGPredictionPerTrueWindSpeed, beatAllowancePerTrueWindSpeed, + runAngles, runVMGPredictionPerTrueWindSpeed, + runAllowancePerTrueWindSpeed, windwardLeewardSpeedPredictionPerTrueWindSpeed, + longDistanceSpeedPredictionPerTrueWindSpeed, circularRandomSpeedPredictionPerTrueWindSpeed, nonSpinnakerSpeedPredictionPerTrueWindSpeed); } @Override diff --git a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java index 4fe2cb0a8b2..ff697332a16 100755 --- a/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java +++ b/java/com.sap.sailing.server.gateway.serialization.shared.android/src/com/sap/sailing/server/gateway/deserialization/racelog/impl/ORCCertificateJsonDeserializer.java @@ -93,12 +93,13 @@ public class ORCCertificateJsonDeserializer implements JsonDeserializer { + @Override + public ORCCertificateSelection deserialize(JSONObject object) throws JsonDeserializationException { + // TODO Implement JsonDeserializer.deserialize(...) + return null; + } +} 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 new file mode 100755 index 00000000000..bdf39a1398b --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/orc/ORCCertificateImportServlet.java @@ -0,0 +1,67 @@ +package com.sap.sailing.server.gateway.orc; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItem; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +import com.sap.sailing.domain.common.orc.ORCCertificateUploadConstants; +import com.sap.sailing.server.gateway.deserialization.impl.ORCCertificateSelectionDeserializer; +import com.sap.sailing.server.gateway.impl.AbstractFileUploadServlet; +import com.sap.sse.common.Util.Pair; + +/** + * Servlet that processes uploaded ORC boat certificate files, can download certificates from URLs and can link + * certificates to boats in the scope of races and/or regattas. The files obtained by upload or download can be in RMS + * or JSON format and are probed for either one. A single file may contain multiple certificates. The selection and + * linking of certificates to boats within the selected context (regatta / race) happens by identifying the certificate + * by identifying the upload or download resource and within it the sail number, and by providing the boat ID to which + * to link the certificate. + * + * @author Axel Uhl (d043530) + * + */ +public class ORCCertificateImportServlet extends AbstractFileUploadServlet { + private static final long serialVersionUID = -1459007826806652976L; + private static final Logger logger = Logger.getLogger(ORCCertificateImportServlet.class.getName()); + + @Override + protected void process(List fileItems, HttpServletRequest req, HttpServletResponse resp) throws IOException { + try { + String regattaName = null; + String raceName = null; + List> files = new ArrayList<>(); + for (FileItem item : fileItems) { + if (!item.isFormField()) + files.add(new Pair(item.getName(), item)); + else { + if (item.getFieldName() != null) { + if (item.getFieldName().equals(ORCCertificateUploadConstants.REGATTA_NAME)) { + regattaName = item.getString(); + } else if (item.getFieldName().equals(ORCCertificateUploadConstants.RACE_NAME)) { + raceName = item.getString(); + } else if (item.getFieldName().equals(ORCCertificateUploadConstants.CERTIFICATE_SELECTION)) { + final Object certificateSelection = new ORCCertificateSelectionDeserializer() + .deserialize((JSONObject) new JSONParser().parse(item.getString())); + // TODO continue with certificate selection processing here... + } + } + } + } + // setJsonResponseHeader(resp); + // DO NOT set a JSON response header. This causes the browser to wrap the response in a + //

 tag when uploading from GWT, as this is an AJAX-request inside an iFrame.
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            resp.setContentType("text/html;charset=UTF-8");
+        }
+    }
+}
diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/impl/AbstractDuration.java b/java/com.sap.sse.common/src/com/sap/sse/common/impl/AbstractDuration.java
index 7f8a60f686f..0d533ce851a 100755
--- a/java/com.sap.sse.common/src/com/sap/sse/common/impl/AbstractDuration.java
+++ b/java/com.sap.sse.common/src/com/sap/sse/common/impl/AbstractDuration.java
@@ -1,12 +1,15 @@
 package com.sap.sse.common.impl;
 
 import com.sap.sse.common.Duration;
+import com.sap.sse.common.Util;
 
 public abstract class AbstractDuration implements Duration {
     private static final long serialVersionUID = -7217998647218524638L;
 
     @Override
     public String toString() {
-        return String.format("%02d:%02d:%06.3f", ((int) asHours()), (((int) asMinutes()%60)), asSeconds()%60);
+        return ""+Util.padPositiveValue((int) asHours(), 2, 0, /* round */ false)+":"+
+                Util.padPositiveValue(asMinutes()%60, 2, 0, /* round */ false)+":"+
+                Util.padPositiveValue(asSeconds()%60, 2, 3, /* round */ true);
     }
 }