Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ce6e78f
Test the web integration switches, the Sequence Element data and usag…
jwrosewell Nov 9, 2026
d303029
Add switches and paths to the web integration, and Element Data to th…
jwrosewell Nov 9, 2026
34e66a4
Test the MVC integration's paths and element switches
jwrosewell Nov 9, 2026
f9556fd
Give the MVC integration the filter's paths and element switches, and…
jwrosewell Nov 9, 2026
f0aa52b
Test the Sequence Element data under the key sequence
jwrosewell Nov 9, 2026
44554b1
Key the Sequence Element data as sequence, as the other languages do
jwrosewell Nov 9, 2026
a6303a4
Do not call an overridable method from the constructor
jwrosewell Nov 9, 2026
bad4a61
Test that the JSON is served from /51dpipeline/json and from the old …
jwrosewell Nov 9, 2026
d31b99c
Serve the JSON from /51dpipeline/json by default, and from the old pa…
jwrosewell Nov 9, 2026
572ecd7
Test the Sequence Element with session ids and sequences of every kind
jwrosewell Nov 9, 2026
2261027
Treat the session id and the sequence independently, as the specifica…
jwrosewell Nov 9, 2026
fb3074a
Merge rc into the web integration draft
jwrosewell Nov 9, 2026
125e056
Test that the usage sharing filter never includes the web request
jwrosewell Nov 9, 2026
16f58d0
Keep the web request out of the usage sharing filter, as .NET does
jwrosewell Nov 9, 2026
2d741ef
Expect a new session id when the Sequence Element is given an empty one
jwrosewell Nov 9, 2026
8071a10
Merge rc into the web integration draft
jwrosewell Nov 9, 2026
acbb8c7
Test that a build with the JSON Builder Element and no Sequence Eleme…
jwrosewell Nov 9, 2026
2629230
Refuse a build with the JSON Builder Element and no Sequence Element
jwrosewell Nov 9, 2026
f114456
Use a configuration without the JSON Builder Element when client-side…
jwrosewell Nov 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public class GettingStartedOnPrem {
cxx/data, and is downloaded if it is missing, or you may specify another file as a command line
parameter.

Note that the Lite data file is only used for illustration, and has limited accuracy and
capabilities. The example shows the properties only the Enterprise data file has as needing
Note that the Lite data file is only used for illustration, and has a small number of
Properties. The example shows the properties only the Enterprise data file has as needing
it. Contact us for a copy of the Enterprise data file: https://51degrees.com/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-java&utm_content=console-src-main-java-fiftyone-devicedetection-examples-console-gettingstartedonprem.java&utm_term=lite_v_4_1_hash */
public static String LITE_V_4_1_HASH = "device-detection/51Degrees-LiteV4.1.hash";
public static String ENTERPRISE_HASH = "TAC-HashV41.hash";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ public class MetadataOnPrem {
cxx/data, and is downloaded if it is missing, or you may specify another file as a command line
parameter.

Note that the Lite data file is only used for illustration, and has limited accuracy and
capabilities. Contact us for a copy of the Enterprise data file: https://51degrees.com/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-java&utm_content=console-src-main-java-fiftyone-devicedetection-examples-console-metadataonprem.java&utm_term=lite_v_4_1_hash */
Note that the Lite data file is only used for illustration, and has a small number of
Properties. Contact us for a copy of the Enterprise data file: https://51degrees.com/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-java&utm_content=console-src-main-java-fiftyone-devicedetection-examples-console-metadataonprem.java&utm_term=lite_v_4_1_hash */
public static String LITE_V_4_1_HASH = "device-detection/51Degrees-LiteV4.1.hash";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public class OfflineProcessing {
// cxx/data, and is downloaded if it is missing
//
// Note that the Lite data file is only used for illustration, and has
// limited accuracy and capabilities. Contact us for a copy of the
// a small number of Properties. Contact us for a copy of the
// Enterprise data file: https://51degrees.com/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-java&utm_content=console-src-main-java-fiftyone-devicedetection-examples-console-offlineprocessing.java&utm_term=lite_v_4_1_hash
public static final String LITE_V_4_1_HASH =
"device-detection/51Degrees-LiteV4.1.hash";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
* https://distributor.51degrees.com/api/v2/download?LicenseKeys=<your_license_key>&Type=27&Download=True&Product=22
* ```
* ## Lite Data File
* Lite data files (free-to-use, limited capabilities, no license key required) are created roughly
* Lite data files (free-to-use, a small number of Properties, no license key required) are created roughly
* once a month and cannot be updated using auto-update, they may be downloaded with the
* scripts in the [data repository](https://github.com/51Degrees/data) on GitHub, which is
* the cxx/data folder of the source.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</Element>
<Element>
<!--
Needed to obtain additional information from 51Degrees.core.json
Needed to obtain additional information from /51dpipeline/json
-->
<BuilderName>JsonBuilderElement</BuilderName>
</Element>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
</Element>
<Element>
<!--
Needed to obtain additional information from 51Degrees.core.json
Needed to obtain additional information from /51dpipeline/json
-->
<BuilderName>JsonBuilderElement</BuilderName>
</Element>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<BuilderName>IPIntelligenceOnPremiseEngine</BuilderName>
</Element>
<Element>
<!-- Needed to obtain additional information from 51Degrees.core.json -->
<!-- Needed to obtain additional information from /51dpipeline/json -->
<BuilderName>JsonBuilderElement</BuilderName>
</Element>
<Element>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ public EvidenceKeyFilterShareUsage(

@Override
public boolean include(String key) {
// The Usage Sharing Element reads the whole web request itself, and
// the request is never a value to share.
if (ShareUsageEvidence.HTTP_REQUEST_KEY.equalsIgnoreCase(key)) {
return false;
}
String lowerKey = key.toLowerCase();
for (String neverShared : NEVER_SHARED_EVIDENCE_KEYS) {
if (lowerKey.equals(neverShared) ||
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* *********************************************************************
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
* Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House,
* Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
*
* This Original Work is licensed under the European Union Public Licence
* (EUPL) v.1.2 and is subject to its terms as set out below.
*
* If a copy of the EUPL was not distributed with this file, You can obtain
* one at https://opensource.org/licenses/EUPL-1.2.
*
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
* amended by the European Commission) shall be deemed incompatible for
* the purposes of the Work and the provisions of the compatibility
* clause in Article 5 of the EUPL shall not apply.
*
* If using the Work as, or as part of, a network application, by
* including the attribution notice(s) required under Article 5 of the EUPL
* in the end user terms of the application under an appropriate heading,
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */

package fiftyone.pipeline.engines.fiftyone.data;

import fiftyone.pipeline.core.data.ElementDataBase;
import fiftyone.pipeline.core.data.FlowData;
import fiftyone.pipeline.engines.fiftyone.flowelements.SequenceElement;
import org.slf4j.Logger;

/**
* Data containing the result of {@link SequenceElement}.
* @see <a href="https://github.com/51Degrees/specifications/blob/rc/pipeline-specification/pipeline-elements/sequence-element.md#element-data">Specification</a>
*/
public class SequenceData extends ElementDataBase {

/**
* Name of the property holding the session id.
*/
public static final String SESSION_ID_PROPERTY_NAME = "session-id";

/**
* Name of the property holding the sequence.
*/
public static final String SEQUENCE_PROPERTY_NAME = "sequence";

/**
* Construct a new instance.
* @param logger the logger to use
* @param flowData the flow data the data belongs to
*/
public SequenceData(Logger logger, FlowData flowData) {
super(logger, flowData);
}

/**
* Get the identifier of the session.
* @return the session id
*/
public String getSessionId() {
return getAs(SESSION_ID_PROPERTY_NAME, String.class);
}

/**
* Set the identifier of the session.
* @param sessionId the session id
*/
public void setSessionId(String sessionId) {
put(SESSION_ID_PROPERTY_NAME, sessionId);
}

/**
* Get the number of consecutive callbacks made in the session.
* @return the sequence
*/
public Integer getSequence() {
return getAs(SEQUENCE_PROPERTY_NAME, Integer.class);
}

/**
* Set the number of consecutive callbacks made in the session.
* @param sequence the sequence
*/
public void setSequence(int sequence) {
put(SEQUENCE_PROPERTY_NAME, sequence);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@
package fiftyone.pipeline.engines.fiftyone.flowelements;

import fiftyone.pipeline.core.data.*;
import fiftyone.pipeline.core.data.factories.ElementDataFactory;
import fiftyone.pipeline.core.flowelements.FlowElement;
import fiftyone.pipeline.core.flowelements.FlowElementBase;
import fiftyone.pipeline.engines.fiftyone.data.SequenceData;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
import org.slf4j.Logger;

/**
Expand All @@ -39,6 +43,10 @@
public class SequenceElement
extends FlowElementBase<ElementData, ElementPropertyMetaData> {

private static final Pattern DIGITS = Pattern.compile("[0-9]+");

private final List<ElementPropertyMetaData> properties;

/**
* The session id and sequence of a callback, which the specification
* lists as this element's accepted Evidence. Without them the web
Expand All @@ -55,48 +63,92 @@ public class SequenceElement
* Construct a new instance of the {@link FlowElement}.
* @param logger logger instance to use for logging
*/
public SequenceElement(Logger logger) {
super(logger, null);
@SuppressWarnings("this-escape")
public SequenceElement(final Logger logger) {
super(logger, new ElementDataFactory<ElementData>() {
@Override
public ElementData create(
FlowData flowData,
FlowElement<ElementData, ?> flowElement) {
return new SequenceData(logger, flowData);
}
});
properties = new ArrayList<>();
properties.add(new ElementPropertyMetaDataDefault(
SequenceData.SESSION_ID_PROPERTY_NAME,
this,
"",
String.class,
true));
properties.add(new ElementPropertyMetaDataDefault(
SequenceData.SEQUENCE_PROPERTY_NAME,
this,
"",
Integer.class,
true));
}

@Override
protected void processInternal(FlowData data) throws Exception {
Map<String, Object> evidence = data.getEvidence().asKeyMap();

// If the evidence does not contain a session id then create a new one.
if (evidence.containsKey(Constants.EVIDENCE_SESSIONID) == false) {
data.addEvidence(Constants.EVIDENCE_SESSIONID, getNewSessionId());
}

// If the evidence does not have a sequence then add one.
if (evidence.containsKey(Constants.EVIDENCE_SEQUENCE) == false) {
data.addEvidence(Constants.EVIDENCE_SEQUENCE, 1);
} else {
data.addEvidence(
Constants.EVIDENCE_SEQUENCE,
getSequence(evidence.get(Constants.EVIDENCE_SEQUENCE)) + 1);
}
// The session id and the sequence are each used only when they are
// valid, and otherwise count as absent.
Object givenSession = evidence.get(Constants.EVIDENCE_SESSIONID);
String sessionId =
givenSession instanceof String &&
((String) givenSession).isEmpty() == false ?
(String) givenSession : getNewSessionId();
Integer previous = toSequence(evidence.get(Constants.EVIDENCE_SEQUENCE));
int sequence = previous == null ? 1 : previous + 1;

data.addEvidence(Constants.EVIDENCE_SESSIONID, sessionId);
data.addEvidence(Constants.EVIDENCE_SEQUENCE, sequence);

SequenceData sequenceData = (SequenceData) data.getOrAdd(
getElementDataKey(),
getDataFactory());
sequenceData.setSessionId(sessionId);
sequenceData.setSequence(sequence);
}

/**
* The sequence in Evidence, which is a number when an element set it and
* text when it came from the query string of a callback. Anything that is
* not a number counts as no sequence.
* The sequence in Evidence, which is a whole number or text made only of
* decimal digits. A value that is anything else, does not fit in an int
* or has no larger int after it counts as no sequence, so that adding
* one never overflows.
* @return the sequence, or null if there is none
*/
private static int getSequence(Object sequence) {
if (sequence instanceof Number) {
return ((Number) sequence).intValue();
}
try {
return Integer.parseInt(String.valueOf(sequence).trim());
} catch (NumberFormatException e) {
return 0;
private static Integer toSequence(Object sequence) {
long value;
if (sequence instanceof Integer || sequence instanceof Long ||
sequence instanceof Short || sequence instanceof Byte) {
value = ((Number) sequence).longValue();
} else if (sequence instanceof BigInteger) {
BigInteger big = (BigInteger) sequence;
if (big.bitLength() > 31) {
return null;
}
value = big.longValue();
} else if (sequence instanceof String &&
DIGITS.matcher((String) sequence).matches()) {
// More digits than any int has cannot fit, however many zeros
// come first, so only the value of a short string is read.
String digits = ((String) sequence).replaceFirst("^0+(?=.)", "");
if (digits.length() > 10) {
return null;
}
value = Long.parseLong(digits);
} else {
return null;
}
return value < Integer.MAX_VALUE && value >= Integer.MIN_VALUE ?
Integer.valueOf((int) value) : null;
}

@Override
public String getElementDataKey() {
return "sequence-element";
return "sequence";
}

@Override
Expand All @@ -106,7 +158,7 @@ public EvidenceKeyFilter getEvidenceKeyFilter() {

@Override
public List<ElementPropertyMetaData> getProperties() {
return new ArrayList<>();
return properties;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ private static EvidenceKeyFilterShareUsage defaults() {
* values and query string parameters only when their names start with
* 51D_, and any other evidence.
*/
/**
* The whole web request is read by the Usage Sharing Element and never
* shared as a value, so the filter does not include it.
*/
@Test
public void webRequestIsNeverIncluded() {
EvidenceKeyFilterShareUsage filter = defaults();

assertFalse(filter.include("server.http-request"));
assertFalse(filter.include("Server.Http-Request"));
}

@Test
public void defaultRules() {
EvidenceKeyFilterShareUsage filter = defaults();
Expand Down
Loading
Loading