From 99ac68479423f499de006a137e798ac2d02f026b Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 00:11:02 +0000 Subject: [PATCH 1/8] Test that every example ends its output with a Find out more section Adds FindOutMore to the Device Detection and IP Intelligence examples' shared modules, with its own tests, and checks that each on-premise console example run with no settings ends with the section and that every console example with a main method writes it. --- .../console/ExamplesWithoutSettingsTest.java | 16 ++ .../console/FindOutMoreCoverageTest.java | 74 ++++++++ .../examples/shared/FindOutMore.java | 161 ++++++++++++++++++ .../examples/shared/FindOutMoreTest.java | 120 +++++++++++++ .../console/ExamplesWithoutSettingsTest.java | 16 ++ .../console/FindOutMoreCoverageTest.java | 74 ++++++++ .../examples/shared/FindOutMore.java | 161 ++++++++++++++++++ .../examples/shared/FindOutMoreTest.java | 120 +++++++++++++ 8 files changed, 742 insertions(+) create mode 100644 examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/FindOutMoreCoverageTest.java create mode 100644 examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java create mode 100644 examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java create mode 100644 examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/FindOutMoreCoverageTest.java create mode 100644 examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java create mode 100644 examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java diff --git a/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java b/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java index aea911082..9c36dc2ea 100644 --- a/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java +++ b/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java @@ -23,6 +23,7 @@ package fiftyone.devicedetection.examples.console; import fiftyone.devicedetection.examples.shared.DataFileHelper; +import fiftyone.devicedetection.examples.shared.FindOutMore; import org.junit.Test; import java.io.ByteArrayOutputStream; @@ -75,6 +76,7 @@ private static String runWithoutSettings(Main main) throws Exception { } String output = buffer.toString("UTF-8"); out.println(output); + assertFindOutMore(output); return output; } @@ -83,6 +85,20 @@ private static void assertContains(String output, String expected) { output.contains(expected)); } + /** + * Checks that the output ends with the "Find out more" section, after + * the link to the contact page. + */ + private static void assertFindOutMore(String output) { + int heading = output.lastIndexOf(FindOutMore.HEADING); + assertTrue("The output should have the '" + FindOutMore.HEADING + + "' section after the link to the contact page", + heading > output.lastIndexOf(CONTACT_US)); + assertTrue("The '" + FindOutMore.HEADING + + "' section should end with its rule", + output.indexOf(FindOutMore.RULE, heading) > heading); + } + private static void assertOffer(String output) { assertContains(output, "This example used the free Lite data file."); assertContains(output, CONTACT_US); diff --git a/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/FindOutMoreCoverageTest.java b/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/FindOutMoreCoverageTest.java new file mode 100644 index 000000000..f090ac8fe --- /dev/null +++ b/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/FindOutMoreCoverageTest.java @@ -0,0 +1,74 @@ +/* ********************************************************************* + * 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.devicedetection.examples.console; + +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertTrue; + +/** + * Checks that every console example with a main method writes the "Find out + * more" section, including those that need a key or a paid data file and so + * do not run in ExamplesWithoutSettingsTest. + */ +public class FindOutMoreCoverageTest { + + @Test + public void everyExample_WritesFindOutMore() throws IOException { + Path sources = Paths.get(System.getProperty("basedir", "."), + "src", "main", "java"); + assertTrue(sources + " should hold the examples", + Files.isDirectory(sources)); + List files; + try (Stream walk = Files.walk(sources)) { + files = walk.filter(f -> f.toString().endsWith(".java")) + .collect(Collectors.toList()); + } + List examples = new ArrayList<>(); + List missing = new ArrayList<>(); + for (Path file : files) { + String text = new String(Files.readAllBytes(file), + StandardCharsets.UTF_8); + if (text.contains("static void main(")) { + examples.add(file.getFileName().toString()); + if (text.contains("FindOutMore.write") == false) { + missing.add(file.getFileName().toString()); + } + } + } + assertTrue("No examples were found in " + sources, + examples.isEmpty() == false); + assertTrue("These examples do not write the 'Find out more' " + + "section: " + missing, missing.isEmpty()); + } +} diff --git a/examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java b/examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java new file mode 100644 index 000000000..7d6bda5a5 --- /dev/null +++ b/examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java @@ -0,0 +1,161 @@ +/* ********************************************************************* + * 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.devicedetection.examples.shared; + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.regex.Pattern; + +/** + * Writes the "Find out more" section that ends every example's output, set + * apart from the example's own output by a rule above and below. It gives + * pages on 51degrees.com, each tagged with the example that wrote it, then + * the repositories behind the example. + */ +public final class FindOutMore { + + /** + * The heading the section starts with. + */ + public static final String HEADING = "Find out more"; + + /** + * The rule above and below the section. + */ + public static final String RULE = + "----------------------------------------------------------------"; + + /** + * The repositories an on-premise example lists, being this SDK, the C + * engines it builds on and the free data files. + */ + public static final String[] ON_PREMISE_REPOSITORIES = { + "https://github.com/51Degrees/51degrees-java", + "https://github.com/51Degrees/51degrees-cxx", + "https://github.com/51Degrees/data" + }; + + /** + * The repositories a cloud example lists. + */ + public static final String[] CLOUD_REPOSITORIES = { + "https://github.com/51Degrees/51degrees-java" + }; + + /** + * Each page's label and its path on 51degrees.com. + */ + private static final String[][] PAGES = { + {"Device Detection", "device-detection"}, + {"Pricing", "pricing"}, + {"Documentation", "documentation/index.html"} + }; + + /** + * What a campaign tag value may hold. + */ + private static final Pattern SLUG = + Pattern.compile("[a-z0-9][a-z0-9._-]*"); + + private FindOutMore() { + } + + /** + * Writes the section. + * @param output where to write, flushed afterwards + * @param example the example's tag, a lower case slug such as + * "console-gettingstartedonprem.java" + * @param repositories the repositories to list, such as + * {@link #ON_PREMISE_REPOSITORIES} + */ + public static void write( + PrintWriter output, + String example, + String... repositories) { + output.println(); + writeLines(output, "", example, repositories); + } + + /** + * Writes the section with each line a comment, for output that has to + * stay valid in its own format, such as a YAML stream. + * @param output where to write, flushed afterwards + * @param comment what starts a comment line, such as "# " + * @param example the example's tag + * @param repositories the repositories to list + */ + public static void writeCommented( + PrintWriter output, + String comment, + String example, + String... repositories) { + writeLines(output, comment, example, repositories); + } + + private static void writeLines( + PrintWriter output, + String start, + String example, + String... repositories) { + output.println(start + RULE); + output.println(start + HEADING); + for (String[] page : PAGES) { + output.println(start + "\t" + page[0] + ": " + + link(page[1], example)); + } + for (String repository : repositories) { + output.println(start + "\t" + repository); + } + output.println(start + RULE); + output.flush(); + } + + /** + * Writes the section to a stream. See + * {@link #write(PrintWriter, String, String...)}. + */ + public static void write( + OutputStream output, + String example, + String... repositories) { + write(new PrintWriter(output), example, repositories); + } + + /** + * The address of a page on 51degrees.com, tagged with the example. + * @param page the path of the page + * @param example the example's tag + * @return the address + * @throws IllegalArgumentException if the tag is not a lower case slug + */ + public static String link(String page, String example) { + if (example == null || SLUG.matcher(example).matches() == false) { + throw new IllegalArgumentException( + "'" + example + "' is not a lower case slug."); + } + return "https://51degrees.com/" + + page + "?utm_source=code&utm_medium=example" + + "&utm_campaign=51degrees-java&utm_content=" + example + + "&utm_term=find-out-more"; + } +} diff --git a/examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java b/examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java new file mode 100644 index 000000000..2b3aef4ab --- /dev/null +++ b/examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java @@ -0,0 +1,120 @@ +/* ********************************************************************* + * 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.devicedetection.examples.shared; + +import org.junit.Test; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +public class FindOutMoreTest { + + /** + * The campaign tags common-ci's scripts/utm-lint.ps1 requires of a link + * printed by an example. + */ + private static final Pattern TAGGED = Pattern.compile( + "https://51degrees\\.com/[^?\\s]+\\?utm_source=code" + + "&utm_medium=example&utm_campaign=51degrees-java" + + "&utm_content=[a-z0-9][a-z0-9._-]*" + + "&utm_term=[a-z0-9][a-z0-9._-]*"); + + private static String[] write(String example, String... repositories) { + StringWriter text = new StringWriter(); + FindOutMore.write(new PrintWriter(text), example, repositories); + return text.toString().split("\r?\n"); + } + + /** + * The section is a blank line, a rule, the heading, the three tagged + * pages, the repositories and a closing rule. + */ + @Test + public void write_LinksThenRepositories() { + String[] lines = write("console-example.java", + FindOutMore.ON_PREMISE_REPOSITORIES); + assertEquals(10, lines.length); + assertEquals("", lines[0]); + assertEquals(FindOutMore.RULE, lines[1]); + assertEquals(FindOutMore.HEADING, lines[2]); + assertTrue(lines[3].startsWith("\tDevice Detection: https://51degrees.com/device-detection?")); + assertTrue(lines[4].startsWith("\tPricing: https://51degrees.com/pricing?")); + assertTrue(lines[5].startsWith("\tDocumentation: https://51degrees.com/documentation/index.html?")); + for (int i = 3; i <= 5; i++) { + String link = lines[i].substring(lines[i].indexOf("https://")); + assertTrue(link, TAGGED.matcher(link).matches()); + assertTrue(link, link.contains("&utm_content=console-example.java&")); + } + assertEquals("\thttps://github.com/51Degrees/51degrees-java", lines[6]); + assertEquals("\thttps://github.com/51Degrees/51degrees-cxx", lines[7]); + assertEquals("\thttps://github.com/51Degrees/data", lines[8]); + assertEquals(FindOutMore.RULE, lines[9]); + } + + /** + * A cloud example lists this repository alone. + */ + @Test + public void write_Cloud_ThisRepository() { + String[] lines = write("console-example.java", + FindOutMore.CLOUD_REPOSITORIES); + assertEquals(8, lines.length); + assertEquals("\thttps://github.com/51Degrees/51degrees-java", lines[6]); + } + + /** + * Each line of the commented form starts with the comment marker, and + * there is no blank line, so a YAML stream stays valid. + */ + @Test + public void writeCommented_EveryLineAComment() { + StringWriter text = new StringWriter(); + FindOutMore.writeCommented(new PrintWriter(text), "# ", + "console-example.java", FindOutMore.CLOUD_REPOSITORIES); + String[] lines = text.toString().split("\\r?\\n"); + assertEquals(7, lines.length); + for (String line : lines) { + assertTrue(line, line.startsWith("# ")); + } + assertEquals("# " + FindOutMore.HEADING, lines[1]); + } + + /** + * A tag that is not a lower case slug would fail the campaign tag + * convention, so it is refused. + */ + @Test + public void link_NotASlug_Refused() { + assertThrows(IllegalArgumentException.class, + () -> FindOutMore.link("pricing", "Console-Example.java")); + assertThrows(IllegalArgumentException.class, + () -> FindOutMore.link("pricing", "console example")); + assertThrows(IllegalArgumentException.class, + () -> FindOutMore.link("pricing", null)); + } +} diff --git a/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java b/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java index d14a522f6..14c6a4ec6 100644 --- a/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java +++ b/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java @@ -23,6 +23,7 @@ package fiftyone.ipintelligence.examples.console; import fiftyone.ipintelligence.examples.shared.DataFileHelper; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import org.junit.Test; import java.io.ByteArrayOutputStream; @@ -92,6 +93,7 @@ private static String runWithoutSettings(Main main) throws Exception { } String output = buffer.toString("UTF-8"); out.println(output); + assertFindOutMore(output); return output; } @@ -100,6 +102,20 @@ private static void assertContains(String output, String expected) { output.contains(expected)); } + /** + * Checks that the output ends with the "Find out more" section, after + * the link to the contact page. + */ + private static void assertFindOutMore(String output) { + int heading = output.lastIndexOf(FindOutMore.HEADING); + assertTrue("The output should have the '" + FindOutMore.HEADING + + "' section after the link to the contact page", + heading > output.lastIndexOf(CONTACT_US)); + assertTrue("The '" + FindOutMore.HEADING + + "' section should end with its rule", + output.indexOf(FindOutMore.RULE, heading) > heading); + } + private static void assertStops(String output, String purpose) { assertContains(output, purpose + " needs the "); assertContains(output, "so the example stops here."); diff --git a/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/FindOutMoreCoverageTest.java b/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/FindOutMoreCoverageTest.java new file mode 100644 index 000000000..3ad6721cf --- /dev/null +++ b/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/FindOutMoreCoverageTest.java @@ -0,0 +1,74 @@ +/* ********************************************************************* + * 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.ipintelligence.examples.console; + +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.assertTrue; + +/** + * Checks that every console example with a main method writes the "Find out + * more" section, including those that need a key or a paid data file and so + * do not run in ExamplesWithoutSettingsTest. + */ +public class FindOutMoreCoverageTest { + + @Test + public void everyExample_WritesFindOutMore() throws IOException { + Path sources = Paths.get(System.getProperty("basedir", "."), + "src", "main", "java"); + assertTrue(sources + " should hold the examples", + Files.isDirectory(sources)); + List files; + try (Stream walk = Files.walk(sources)) { + files = walk.filter(f -> f.toString().endsWith(".java")) + .collect(Collectors.toList()); + } + List examples = new ArrayList<>(); + List missing = new ArrayList<>(); + for (Path file : files) { + String text = new String(Files.readAllBytes(file), + StandardCharsets.UTF_8); + if (text.contains("static void main(")) { + examples.add(file.getFileName().toString()); + if (text.contains("FindOutMore.write") == false) { + missing.add(file.getFileName().toString()); + } + } + } + assertTrue("No examples were found in " + sources, + examples.isEmpty() == false); + assertTrue("These examples do not write the 'Find out more' " + + "section: " + missing, missing.isEmpty()); + } +} diff --git a/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java new file mode 100644 index 000000000..2647e2c35 --- /dev/null +++ b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java @@ -0,0 +1,161 @@ +/* ********************************************************************* + * 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.ipintelligence.examples.shared; + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.regex.Pattern; + +/** + * Writes the "Find out more" section that ends every example's output, set + * apart from the example's own output by a rule above and below. It gives + * pages on 51degrees.com, each tagged with the example that wrote it, then + * the repositories behind the example. + */ +public final class FindOutMore { + + /** + * The heading the section starts with. + */ + public static final String HEADING = "Find out more"; + + /** + * The rule above and below the section. + */ + public static final String RULE = + "----------------------------------------------------------------"; + + /** + * The repositories an on-premise example lists, being this SDK, the C + * engines it builds on and the free data files. + */ + public static final String[] ON_PREMISE_REPOSITORIES = { + "https://github.com/51Degrees/51degrees-java", + "https://github.com/51Degrees/51degrees-cxx", + "https://github.com/51Degrees/data" + }; + + /** + * The repositories a cloud example lists. + */ + public static final String[] CLOUD_REPOSITORIES = { + "https://github.com/51Degrees/51degrees-java" + }; + + /** + * Each page's label and its path on 51degrees.com. + */ + private static final String[][] PAGES = { + {"IP Intelligence", "ip-intelligence"}, + {"Pricing", "pricing"}, + {"Documentation", "documentation/index.html"} + }; + + /** + * What a campaign tag value may hold. + */ + private static final Pattern SLUG = + Pattern.compile("[a-z0-9][a-z0-9._-]*"); + + private FindOutMore() { + } + + /** + * Writes the section. + * @param output where to write, flushed afterwards + * @param example the example's tag, a lower case slug such as + * "console-gettingstartedonprem.java" + * @param repositories the repositories to list, such as + * {@link #ON_PREMISE_REPOSITORIES} + */ + public static void write( + PrintWriter output, + String example, + String... repositories) { + output.println(); + writeLines(output, "", example, repositories); + } + + /** + * Writes the section with each line a comment, for output that has to + * stay valid in its own format, such as a YAML stream. + * @param output where to write, flushed afterwards + * @param comment what starts a comment line, such as "# " + * @param example the example's tag + * @param repositories the repositories to list + */ + public static void writeCommented( + PrintWriter output, + String comment, + String example, + String... repositories) { + writeLines(output, comment, example, repositories); + } + + private static void writeLines( + PrintWriter output, + String start, + String example, + String... repositories) { + output.println(start + RULE); + output.println(start + HEADING); + for (String[] page : PAGES) { + output.println(start + "\t" + page[0] + ": " + + link(page[1], example)); + } + for (String repository : repositories) { + output.println(start + "\t" + repository); + } + output.println(start + RULE); + output.flush(); + } + + /** + * Writes the section to a stream. See + * {@link #write(PrintWriter, String, String...)}. + */ + public static void write( + OutputStream output, + String example, + String... repositories) { + write(new PrintWriter(output), example, repositories); + } + + /** + * The address of a page on 51degrees.com, tagged with the example. + * @param page the path of the page + * @param example the example's tag + * @return the address + * @throws IllegalArgumentException if the tag is not a lower case slug + */ + public static String link(String page, String example) { + if (example == null || SLUG.matcher(example).matches() == false) { + throw new IllegalArgumentException( + "'" + example + "' is not a lower case slug."); + } + return "https://51degrees.com/" + + page + "?utm_source=code&utm_medium=example" + + "&utm_campaign=51degrees-java&utm_content=" + example + + "&utm_term=find-out-more"; + } +} diff --git a/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java b/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java new file mode 100644 index 000000000..5433e1265 --- /dev/null +++ b/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java @@ -0,0 +1,120 @@ +/* ********************************************************************* + * 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.ipintelligence.examples.shared; + +import org.junit.Test; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +public class FindOutMoreTest { + + /** + * The campaign tags common-ci's scripts/utm-lint.ps1 requires of a link + * printed by an example. + */ + private static final Pattern TAGGED = Pattern.compile( + "https://51degrees\\.com/[^?\\s]+\\?utm_source=code" + + "&utm_medium=example&utm_campaign=51degrees-java" + + "&utm_content=[a-z0-9][a-z0-9._-]*" + + "&utm_term=[a-z0-9][a-z0-9._-]*"); + + private static String[] write(String example, String... repositories) { + StringWriter text = new StringWriter(); + FindOutMore.write(new PrintWriter(text), example, repositories); + return text.toString().split("\r?\n"); + } + + /** + * The section is a blank line, a rule, the heading, the three tagged + * pages, the repositories and a closing rule. + */ + @Test + public void write_LinksThenRepositories() { + String[] lines = write("console-example.java", + FindOutMore.ON_PREMISE_REPOSITORIES); + assertEquals(10, lines.length); + assertEquals("", lines[0]); + assertEquals(FindOutMore.RULE, lines[1]); + assertEquals(FindOutMore.HEADING, lines[2]); + assertTrue(lines[3].startsWith("\tIP Intelligence: https://51degrees.com/ip-intelligence?")); + assertTrue(lines[4].startsWith("\tPricing: https://51degrees.com/pricing?")); + assertTrue(lines[5].startsWith("\tDocumentation: https://51degrees.com/documentation/index.html?")); + for (int i = 3; i <= 5; i++) { + String link = lines[i].substring(lines[i].indexOf("https://")); + assertTrue(link, TAGGED.matcher(link).matches()); + assertTrue(link, link.contains("&utm_content=console-example.java&")); + } + assertEquals("\thttps://github.com/51Degrees/51degrees-java", lines[6]); + assertEquals("\thttps://github.com/51Degrees/51degrees-cxx", lines[7]); + assertEquals("\thttps://github.com/51Degrees/data", lines[8]); + assertEquals(FindOutMore.RULE, lines[9]); + } + + /** + * A cloud example lists this repository alone. + */ + @Test + public void write_Cloud_ThisRepository() { + String[] lines = write("console-example.java", + FindOutMore.CLOUD_REPOSITORIES); + assertEquals(8, lines.length); + assertEquals("\thttps://github.com/51Degrees/51degrees-java", lines[6]); + } + + /** + * Each line of the commented form starts with the comment marker, and + * there is no blank line, so a YAML stream stays valid. + */ + @Test + public void writeCommented_EveryLineAComment() { + StringWriter text = new StringWriter(); + FindOutMore.writeCommented(new PrintWriter(text), "# ", + "console-example.java", FindOutMore.CLOUD_REPOSITORIES); + String[] lines = text.toString().split("\\r?\\n"); + assertEquals(7, lines.length); + for (String line : lines) { + assertTrue(line, line.startsWith("# ")); + } + assertEquals("# " + FindOutMore.HEADING, lines[1]); + } + + /** + * A tag that is not a lower case slug would fail the campaign tag + * convention, so it is refused. + */ + @Test + public void link_NotASlug_Refused() { + assertThrows(IllegalArgumentException.class, + () -> FindOutMore.link("pricing", "Console-Example.java")); + assertThrows(IllegalArgumentException.class, + () -> FindOutMore.link("pricing", "console example")); + assertThrows(IllegalArgumentException.class, + () -> FindOutMore.link("pricing", null)); + } +} From e35c35d1855461bfcf951744151d927e608add32 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 00:17:01 +0000 Subject: [PATCH 2/8] End every console example with a Find out more section Each Device Detection and IP Intelligence console example now ends its output with the section, after the link to the contact page where it gives one, including the examples that stop early on a free data file. The section lists the product, pricing and documentation pages, tagged with the example, and the repositories behind it. OfflineProcessing writes it as YAML comments so its output stays a valid YAML stream, and the examples whose writer closes standard output write it before that. --- .../examples/console/GettingStartedCloud.java | 9 +++++++++ .../examples/console/GettingStartedOnPrem.java | 9 +++++++++ .../examples/console/MatchMetrics.java | 9 +++++++++ .../examples/console/MetadataCloud.java | 9 +++++++++ .../examples/console/MetadataOnPrem.java | 9 +++++++++ .../examples/console/MinimalExample.java | 9 +++++++++ .../examples/console/NativeModelCloud.java | 11 +++++++++++ .../examples/console/OfflineProcessing.java | 11 +++++++++++ .../examples/console/PerformanceBenchmark.java | 9 +++++++++ .../examples/console/ShareUsageExample.java | 9 +++++++++ .../devicedetection/examples/console/TacCloud.java | 11 +++++++++++ .../examples/console/UpdateDataFile.java | 9 +++++++++ .../examples/console/comparison/Comparer.java | 9 +++++++++ .../examples/console/CompareOnPrem.java | 11 +++++++++++ .../examples/console/GetAllPropertiesCloud.java | 9 +++++++++ .../examples/console/GettingStartedCloud.java | 9 +++++++++ .../examples/console/GettingStartedCloudMixed.java | 9 +++++++++ .../examples/console/GettingStartedMixed.java | 9 +++++++++ .../examples/console/GettingStartedOnPrem.java | 9 +++++++++ .../examples/console/MetadataCloud.java | 9 +++++++++ .../examples/console/MetadataOnPrem.java | 9 +++++++++ .../examples/console/MetricsOnPrem.java | 11 +++++++++++ .../examples/console/OfflineProcessing.java | 11 +++++++++++ .../examples/console/PerformanceBenchmark.java | 9 +++++++++ .../examples/console/SuspiciousOnPrem.java | 9 +++++++++ .../examples/console/UpdateDataFile.java | 9 +++++++++ 26 files changed, 246 insertions(+) diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedCloud.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedCloud.java index 846e1fcb4..533763807 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedCloud.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedCloud.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.DeviceDetectionPipelineBuilder; import fiftyone.devicedetection.examples.shared.KeyHelper; import fiftyone.devicedetection.examples.shared.EvidenceHelper; @@ -53,6 +54,12 @@ */ @SuppressWarnings("DuplicatedCode") public class GettingStartedCloud { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-gettingstartedcloud.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedCloud.class); /** @@ -66,6 +73,8 @@ public static void main(String[] args) throws Exception { // prepare 'evidence' for use in pipeline (see below) List> evidence = EvidenceHelper.setUpEvidence(); run(resourceKey, evidence, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } /** diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedOnPrem.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedOnPrem.java index 6cb6e8433..067394b73 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedOnPrem.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/GettingStartedOnPrem.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.examples.shared.DataFileHelper; import fiftyone.devicedetection.examples.shared.EvidenceHelper; import fiftyone.devicedetection.hash.engine.onpremise.flowelements.DeviceDetectionHashEngine; @@ -58,6 +59,12 @@ * The concepts of "pipeline", "flow data", "evidence" and "results" are illustrated. */ public class GettingStartedOnPrem { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-gettingstartedonprem.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedOnPrem.class); /* In this example, by default, the 51degrees "Lite" file is used from the data repository in @@ -84,6 +91,8 @@ public static void main(String[] args) throws Exception { // prepare 'evidence' for use in pipeline (see below) List> evidence = EvidenceHelper.setUpEvidence(); run(dataFile, evidence, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MatchMetrics.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MatchMetrics.java index ddabcaed4..3bcd93807 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MatchMetrics.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MatchMetrics.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.DeviceDetectionPipelineBuilder; import fiftyone.devicedetection.examples.shared.DataFileHelper; import fiftyone.devicedetection.examples.shared.EvidenceHelper; @@ -61,6 +62,12 @@ * page. */ public class MatchMetrics { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-matchmetrics.java"; + private static final Logger logger = LoggerFactory.getLogger(MatchMetrics.class); /** @@ -76,6 +83,8 @@ public static void main(String[] args) throws Exception { String dataFilename = DataFileHelper.getDataFileLocation( args.length > 0 ? args[0] : LITE_HASH_DATA_FILE_PATH); run(dataFilename, EvidenceHelper.setUpEvidence(), false, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataCloud.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataCloud.java index 8ca360fab..377cf30cf 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataCloud.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataCloud.java @@ -21,6 +21,7 @@ * ********************************************************************* */ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.DeviceDetectionPipelineBuilder; import fiftyone.devicedetection.cloud.flowelements.DeviceDetectionCloudEngine; import fiftyone.devicedetection.examples.shared.KeyHelper; @@ -42,12 +43,20 @@ public class MetadataCloud { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-metadatacloud.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedOnPrem.class); public static void main(String[] args) throws Exception { configureLogback(getFilePath("logback.xml")); String resourceKey = args.length > 0 ? args[0]: null; run(resourceKey, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataOnPrem.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataOnPrem.java index c85d852b8..a7dbdb5f1 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataOnPrem.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MetadataOnPrem.java @@ -21,6 +21,7 @@ * ********************************************************************* */ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.pipeline.engines.fiftyone.data.FiftyOneAspectPropertyMetaData; import fiftyone.devicedetection.examples.shared.DataFileHelper; import fiftyone.devicedetection.hash.engine.onpremise.flowelements.DeviceDetectionHashEngine; @@ -45,6 +46,12 @@ public class MetadataOnPrem { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-metadataonprem.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedOnPrem.class); /* In this example, by default, the 51degrees "Lite" file is used from the data repository in @@ -65,6 +72,8 @@ public static void main(String[] args) throws Exception { configureLogback(getFilePath("logback.xml")); String dataFile = args.length > 0 ? args[0] : LITE_V_4_1_HASH; run(dataFile, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MinimalExample.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MinimalExample.java index 8c5fb5206..71f37abee 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MinimalExample.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/MinimalExample.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.DeviceDetectionPipelineBuilder; import fiftyone.devicedetection.shared.DeviceData; import fiftyone.pipeline.core.data.FlowData; @@ -44,9 +45,17 @@ */ public class MinimalExample { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-minimalexample.java"; + public static void main(String[] args) throws Exception { String resource = args.length > 0 ? args[0] : null; run(resource); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } public static void run(String resource) throws Exception { diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/NativeModelCloud.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/NativeModelCloud.java index 3c6c724ac..6545522f3 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/NativeModelCloud.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/NativeModelCloud.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.cloud.data.MultiDeviceDataCloud; import fiftyone.devicedetection.cloud.flowelements.HardwareProfileCloudEngineBuilder; import fiftyone.devicedetection.shared.Constants; @@ -41,6 +42,12 @@ import static fiftyone.pipeline.util.FileFinder.getFilePath; public class NativeModelCloud { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-nativemodelcloud.java"; + // Example values to use when looking up device details from native model names. private static final String NATIVE_MODEL_1 = "SC-03L"; private static final String NATIVE_MODEL_2 = "iPhone11,8"; @@ -90,6 +97,10 @@ public static void run(String resourceKey, OutputStream os) throws Exception { // Repeat for an alternative native model name. analyseNativeModel(NATIVE_MODEL_2, pipeline, output); } + // The writer closes the stream it was given, so the section is + // written before it. + FindOutMore.write(output, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } } diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/OfflineProcessing.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/OfflineProcessing.java index fbcdee51b..173d74ba0 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/OfflineProcessing.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/OfflineProcessing.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.DeviceDetectionPipelineBuilder; import fiftyone.devicedetection.examples.shared.DataFileHelper; import fiftyone.devicedetection.hash.engine.onpremise.flowelements.DeviceDetectionHashEngine; @@ -67,6 +68,12 @@ * predictive power using Performance Profile, Graph and Difference and Drift settings. */ public class OfflineProcessing { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-offlineprocessing.java"; + static final Logger logger = LoggerFactory.getLogger(OfflineProcessing.class); // This 51degrees "Lite" file is used from the data repository in // cxx/data, and is downloaded if it is missing @@ -238,6 +245,10 @@ public static void run(String dataFile, InputStream is, OutputStream os) throws } // finish the last YAML document writer.write("...\n"); + // The section is written as comments, so the output stays a + // valid YAML stream. + FindOutMore.writeCommented(new PrintWriter(writer), "# ", + EXAMPLE_TAG, FindOutMore.ON_PREMISE_REPOSITORIES); writer.flush(); logger.info("Finished processing {} records", count); } diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/PerformanceBenchmark.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/PerformanceBenchmark.java index 163e9f8da..cda12774b 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/PerformanceBenchmark.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/PerformanceBenchmark.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.common.testhelpers.LogbackHelper; import fiftyone.devicedetection.DeviceDetectionOnPremisePipelineBuilder; import fiftyone.devicedetection.DeviceDetectionPipelineBuilder; @@ -58,6 +59,12 @@ * for more information about adjusting performance. */ public class PerformanceBenchmark { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-performancebenchmark.java"; + // the default number of threads if one is not provided. public static final int DEFAULT_NUMBER_OF_THREADS = 4; // the number of tests to execute. @@ -106,6 +113,8 @@ public static void main(String[] args) throws Exception { evidenceFilename, numberOfThreads, new PrintWriter(System.out,true)); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/ShareUsageExample.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/ShareUsageExample.java index 50d44c364..bd28e5cfd 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/ShareUsageExample.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/ShareUsageExample.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.examples.shared.DataFileHelper; import fiftyone.pipeline.core.data.FlowData; import fiftyone.pipeline.core.flowelements.Pipeline; @@ -74,6 +75,12 @@ * identifier before running this example.

*/ public class ShareUsageExample { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-shareusageexample.java"; + static final Logger logger = LoggerFactory.getLogger(ShareUsageExample.class); // Evidence file with 20,000 examples, from the data repository in @@ -104,6 +111,8 @@ public static void main(String[] args) throws Exception { File evidenceFile = DataFileHelper.findDataFile(HEADER_EVIDENCE_YML); run(Files.newInputStream(evidenceFile.toPath())); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } /** diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/TacCloud.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/TacCloud.java index ee5ee1e0b..c5a87bc5a 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/TacCloud.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/TacCloud.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.cloud.data.MultiDeviceDataCloud; import fiftyone.devicedetection.shared.Constants; import fiftyone.devicedetection.shared.DeviceData; @@ -56,6 +57,12 @@ * file tacCloud.xml. */ public class TacCloud { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-taccloud.java"; + // Example values to use when looking up device details from TACs. static final String TAC_1 = "35925406"; static final String TAC_2 = "86386802"; @@ -100,6 +107,10 @@ public static void run(String resourceKey, OutputStream os) throws Exception { analyseTac(TAC_1, pipeline, writer); analyseTac(TAC_2, pipeline, writer); } + // The writer closes the stream it was given, so the section is + // written before it. + FindOutMore.write(writer, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } } diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/UpdateDataFile.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/UpdateDataFile.java index ebffdef86..eae7ca9fd 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/UpdateDataFile.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/UpdateDataFile.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.DeviceDetectionPipelineBuilder; import fiftyone.devicedetection.examples.shared.DataFileHelper; import fiftyone.devicedetection.shared.testhelpers.KeyUtils; @@ -189,6 +190,12 @@ */ public class UpdateDataFile { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-updatedatafile.java"; + public static final String UPDATE_EXAMPLE_LICENSE_KEY_NAME = "LicenseKey"; public static final String DEFAULT_DATA_FILENAME = System.getProperty("user.dir") + File.separator + ENTERPRISE_HASH_DATA_FILE_NAME; @@ -209,6 +216,8 @@ public static void main(String[] args) throws Exception { String licenseKey = args.length > 0 ? args[0] : null; String dataFilename = args.length > 1 ? args[1] : null; run(dataFilename, licenseKey, true); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/comparison/Comparer.java b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/comparison/Comparer.java index ba231800a..19b60ceba 100644 --- a/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/comparison/Comparer.java +++ b/examples/device-detection/console/src/main/java/fiftyone/devicedetection/examples/console/comparison/Comparer.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.examples.console.comparison; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.common.testhelpers.LogbackHelper; import fiftyone.devicedetection.examples.console.comparison.Detection.BenchmarkResult; import fiftyone.devicedetection.examples.console.comparison.Detection.Request; @@ -50,6 +51,12 @@ * code has not been tested and it is left to those interested to uncomment and get working. */ public class Comparer { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-devicedetection-examples-console-comparison-comparer.java"; + public static final int DEFAULT_NUMBER_OF_THREADS = 4; public static final int DEFAULT_NUMBER_OF_RESULTS = 2500; @SuppressWarnings("resource") @@ -69,6 +76,8 @@ public static void main(String[] args) throws Exception { DEFAULT_NUMBER_OF_RESULTS, new Reporting.Minimal(), new PrintWriter(System.out, true)); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java index 0fc3c7bbf..0c3e98d68 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java @@ -72,6 +72,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligenceOnPremisePipelineBuilder; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; @@ -115,6 +116,12 @@ * location is contained in the area returned are written to an output CSV. */ public class CompareOnPrem { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-compareonprem.java"; + private static final Logger logger = LoggerFactory.getLogger(CompareOnPrem.class); /** @@ -216,6 +223,8 @@ args[3], new PrintWriter(System.out)) : LOCATION_PROPERTIES, new PrintWriter(System.out), CONTACT_US)) { + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); return; } @@ -223,6 +232,8 @@ args[3], new PrintWriter(System.out)) : run(dataFile, csvTruthFile, profile, writer); } logger.info("Output written to '{}'", outputFile); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GetAllPropertiesCloud.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GetAllPropertiesCloud.java index 3a55152aa..9d66ab330 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GetAllPropertiesCloud.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GetAllPropertiesCloud.java @@ -46,6 +46,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligenceCloudPipelineBuilder; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.examples.shared.KeyHelper; @@ -76,6 +77,12 @@ * Cloud service. */ public class GetAllPropertiesCloud { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-getallpropertiescloud.java"; + private static final Logger logger = LoggerFactory.getLogger(GetAllPropertiesCloud.class); /** @@ -95,6 +102,8 @@ public static void main(String[] args) throws Exception { KeyUtils.getNamedKey(GettingStartedCloud.CLOUD_END_POINT_NAME); run(resourceKey, endPoint, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloud.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloud.java index 684990a91..c9c8d475c 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloud.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloud.java @@ -46,6 +46,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligenceCloudPipelineBuilder; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.examples.shared.EvidenceHelper; @@ -85,6 +86,12 @@ * The concepts of "pipeline", "flow data", "evidence" and "results" are illustrated. */ public class GettingStartedCloud { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-gettingstartedcloud.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedCloud.class); /** @@ -107,6 +114,8 @@ public static void main(String[] args) throws Exception { // prepare 'evidence' for use in pipeline (see below) List> evidence = EvidenceHelper.setUpEvidence(); run(resourceKey, endPoint, evidence, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloudMixed.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloudMixed.java index efca03fdc..11628ca1c 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloudMixed.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedCloudMixed.java @@ -47,6 +47,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.devicedetection.cloud.flowelements.DeviceDetectionCloudEngine; import fiftyone.devicedetection.cloud.flowelements.DeviceDetectionCloudEngineBuilder; import fiftyone.devicedetection.shared.DeviceData; @@ -90,6 +91,12 @@ * Cloud service. */ public class GettingStartedCloudMixed { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-gettingstartedcloudmixed.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedCloudMixed.class); public static void main(String[] args) throws Exception { @@ -107,6 +114,8 @@ public static void main(String[] args) throws Exception { // includes both a User-Agent header and an IP address. List> evidence = GettingStartedMixed.setUpCombinedEvidence(); run(resourceKey, endPoint, evidence, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedMixed.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedMixed.java index f007e2fb3..771fde5e5 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedMixed.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedMixed.java @@ -47,6 +47,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.devicedetection.hash.engine.onpremise.flowelements.DeviceDetectionHashEngine; import fiftyone.devicedetection.shared.DeviceData; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; @@ -85,6 +86,12 @@ * The configuration file is src/main/resources/gettingStartedMixed.xml. */ public class GettingStartedMixed { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-gettingstartedmixed.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedMixed.class); public static final String DD_DATA_FILE_DEFAULT = "device-detection/51Degrees-LiteV4.1.hash"; @@ -105,6 +112,8 @@ public static void main(String[] args) throws Exception { List> evidence = setUpCombinedEvidence(); run(ddDataFile, ipiDataFile, evidence, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedOnPrem.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedOnPrem.java index e25f3e109..ca39cc6fe 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedOnPrem.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/GettingStartedOnPrem.java @@ -44,6 +44,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.engine.onpremise.interop.swig.WeightedStringListValueSwig; import fiftyone.ipintelligence.examples.shared.DataFileHelper; import fiftyone.ipintelligence.examples.shared.EvidenceHelper; @@ -82,6 +83,12 @@ * The concepts of "pipeline", "flow data", "evidence" and "results" are illustrated. */ public class GettingStartedOnPrem { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-gettingstartedonprem.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedOnPrem.class); /* In this example, by default, the free 51degrees Lite IP Intelligence data file is used from @@ -104,6 +111,8 @@ public static void main(String[] args) throws Exception { // prepare 'evidence' for use in pipeline (see below) List> evidence = EvidenceHelper.setUpEvidence(); run(dataFile, evidence, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataCloud.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataCloud.java index 00da31c62..1af46c383 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataCloud.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataCloud.java @@ -54,6 +54,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligenceCloudPipelineBuilder; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.cloud.flowelements.IPIntelligenceCloudEngine; @@ -85,6 +86,12 @@ * Cloud service. */ public class MetadataCloud { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-metadatacloud.java"; + private static final Logger logger = LoggerFactory.getLogger(MetadataCloud.class); public static void main(String[] args) throws Exception { @@ -99,6 +106,8 @@ public static void main(String[] args) throws Exception { KeyUtils.getNamedKey(GettingStartedCloud.CLOUD_END_POINT_NAME); run(resourceKey, endPoint, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataOnPrem.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataOnPrem.java index 223121f1d..2619ca2cf 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataOnPrem.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetadataOnPrem.java @@ -21,6 +21,7 @@ * ********************************************************************* */ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.pipeline.engines.fiftyone.data.FiftyOneAspectPropertyMetaData; import fiftyone.ipintelligence.examples.shared.DataFileHelper; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; @@ -61,6 +62,12 @@ * [contact us](https://51degrees.com/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-java&utm_content=console-src-main-java-fiftyone-ipintelligence-examples-console-metadataonprem.java&utm_term=header). */ public class MetadataOnPrem { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-metadataonprem.java"; + private static final Logger logger = LoggerFactory.getLogger(GettingStartedOnPrem.class); /* In this example, by default, the free 51degrees Lite IP Intelligence data file is used from @@ -79,6 +86,8 @@ public static void main(String[] args) throws Exception { configureLogback(getFilePath("logback.xml")); String dataFile = args.length > 0 ? args[0] : LITE_DATA_FILE_REL_PATH; run(dataFile, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java index 4730245ec..d287f69f9 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java @@ -54,6 +54,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; import fiftyone.ipintelligence.examples.console.areas.Calculations; @@ -105,6 +106,12 @@ * are output in CSV format. */ public class MetricsOnPrem { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-metricsonprem.java"; + private static final Logger logger = LoggerFactory.getLogger(MetricsOnPrem.class); /** @@ -334,6 +341,8 @@ args[3], new PrintWriter(System.out)) : Arrays.asList(PROPERTIES), new PrintWriter(System.out), CONTACT_US)) { + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); return; } @@ -345,6 +354,8 @@ args[3], new PrintWriter(System.out)) : run(dataFile, samplePercentage, 0, condition, profile, writer); } logger.info("Output written to '{}'", outputFile); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java index 0357b64d8..87c67d177 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/OfflineProcessing.java @@ -54,6 +54,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.examples.shared.DataFileHelper; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; @@ -96,6 +97,12 @@ * using Performance Profile settings. */ public class OfflineProcessing { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-offlineprocessing.java"; + static final Logger logger = LoggerFactory.getLogger(OfflineProcessing.class); // By default the free 51degrees Lite IP Intelligence data file is used from // the data repository in cxx/data, and is downloaded if it is missing. @@ -269,6 +276,10 @@ public static void run(String dataFile, InputStream is, OutputStream os) throws } // finish the last YAML document writer.write("...\n"); + // The section is written as comments, so the output stays a + // valid YAML stream. + FindOutMore.writeCommented(new PrintWriter(writer), "# ", + EXAMPLE_TAG, FindOutMore.ON_PREMISE_REPOSITORIES); writer.flush(); logger.info("Finished processing {} records", count); } diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/PerformanceBenchmark.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/PerformanceBenchmark.java index d3c03c4e2..6a535f868 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/PerformanceBenchmark.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/PerformanceBenchmark.java @@ -46,6 +46,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.common.testhelpers.LogbackHelper; import fiftyone.ipintelligence.IPIntelligenceOnPremisePipelineBuilder; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; @@ -81,6 +82,12 @@ *

*/ public class PerformanceBenchmark { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-performancebenchmark.java"; + // the default number of threads if one is not provided. public static final int DEFAULT_NUMBER_OF_THREADS = 4; // the number of tests to execute. @@ -132,6 +139,8 @@ public static void main(String[] args) throws Exception { evidenceFilename, numberOfThreads, new PrintWriter(System.out,true)); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/SuspiciousOnPrem.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/SuspiciousOnPrem.java index 8f0e5e8f2..5ad8a3865 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/SuspiciousOnPrem.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/SuspiciousOnPrem.java @@ -45,6 +45,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; import fiftyone.ipintelligence.examples.shared.DataFileHelper; @@ -80,6 +81,12 @@ * in production without further testing and tuning. */ public class SuspiciousOnPrem { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-suspiciousonprem.java"; + private static final Logger logger = LoggerFactory.getLogger(SuspiciousOnPrem.class); /* In this example, by default, the free 51degrees Lite IP Intelligence data file is used from @@ -116,6 +123,8 @@ public static void main(String[] args) throws Exception { // prepare 'evidence' for use in pipeline (see below) List> evidence = EvidenceHelper.setUpEvidence(); run(dataFile, evidence, System.out); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/UpdateDataFile.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/UpdateDataFile.java index a57a9b3e0..a396c73c9 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/UpdateDataFile.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/UpdateDataFile.java @@ -22,6 +22,7 @@ package fiftyone.ipintelligence.examples.console; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.IPIntelligencePipelineBuilder; import fiftyone.ipintelligence.examples.shared.DataFileHelper; import fiftyone.ipintelligence.shared.testhelpers.KeyUtils; @@ -178,6 +179,12 @@ */ public class UpdateDataFile { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "console-src-main-java-fiftyone-ipintelligence-examples-console-updatedatafile.java"; + public static final String UPDATE_EXAMPLE_LICENSE_KEY_NAME = "LicenseKey"; public static final String DEFAULT_DATA_FILENAME = System.getProperty("user.dir") + File.separator + ENTERPRISE_DATA_FILE_REL_PATH; @@ -198,6 +205,8 @@ public static void main(String[] args) throws Exception { String licenseKey = args.length > 0 ? args[0] : null; String dataFilename = args.length > 1 ? args[1] : null; run(dataFilename, licenseKey, true); + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); } /** From 2366f65edf4d11fb47d54927caecbe728d0cce43 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 00:22:28 +0000 Subject: [PATCH 3/8] Test that every web example's page ends with a Find out more section Adds the HTML form of the section to FindOutMore, with its own test, and checks the page of each Device Detection and IP Intelligence web example that serves HTML. --- .../examples/shared/FindOutMore.java | 24 +++++++++++++++ .../examples/shared/FindOutMoreTest.java | 29 +++++++++++++++++++ .../web/GettingStartedWebCloudTest.java | 4 +++ .../web/GettingStartedWebOnPremTest.java | 14 +++++++-- .../examples/shared/FindOutMore.java | 24 +++++++++++++++ .../examples/shared/FindOutMoreTest.java | 29 +++++++++++++++++++ .../web/GettingStartedWebCloudMixedTest.java | 4 +++ .../web/GettingStartedWebCloudTest.java | 4 +++ .../web/GettingStartedWebMixedTest.java | 4 +++ .../web/GettingStartedWebOnPremTest.java | 4 +++ 10 files changed, 138 insertions(+), 2 deletions(-) diff --git a/examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java b/examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java index 7d6bda5a5..2b8f918f3 100644 --- a/examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java +++ b/examples/device-detection/shared/src/main/java/fiftyone/devicedetection/examples/shared/FindOutMore.java @@ -141,6 +141,30 @@ public static void write( write(new PrintWriter(output), example, repositories); } + /** + * The section as HTML, for the end of a web example's page. + * @param example the example's tag + * @param repositories the repositories to list + * @return the markup + */ + public static String html(String example, String... repositories) { + StringBuilder html = new StringBuilder(); + html.append("

\n"); + html.append("

").append(HEADING).append("

\n"); + html.append(" \n
\n"); + return html.toString(); + } + /** * The address of a page on 51degrees.com, tagged with the example. * @param page the path of the page diff --git a/examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java b/examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java index 2b3aef4ab..8ff97350a 100644 --- a/examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java +++ b/examples/device-detection/shared/src/test/java/fiftyone/devicedetection/examples/shared/FindOutMoreTest.java @@ -104,6 +104,35 @@ public void writeCommented_EveryLineAComment() { assertEquals("# " + FindOutMore.HEADING, lines[1]); } + /** + * The HTML form has the heading, each tagged page as a link with its + * ampersands escaped, and each repository as a link. + */ + @Test + public void html_LinksThenRepositories() { + String html = FindOutMore.html("web-example.java", + FindOutMore.ON_PREMISE_REPOSITORIES); + assertTrue(html, html.contains("

" + FindOutMore.HEADING + "

")); + java.util.regex.Matcher href = + Pattern.compile("href=\"([^\"]+)\"").matcher(html); + int pages = 0; + int repositories = 0; + while (href.find()) { + String link = href.group(1); + if (link.startsWith("https://51degrees.com/")) { + assertTrue(link, link.contains("&")); + assertTrue(link, + TAGGED.matcher(link.replace("&", "&")).matches()); + pages++; + } else { + assertTrue(link, link.startsWith("https://github.com/51Degrees/")); + repositories++; + } + } + assertEquals(3, pages); + assertEquals(3, repositories); + } + /** * A tag that is not a lower case slug would fail the campaign tag * convention, so it is refused. diff --git a/examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/GettingStartedWebCloudTest.java b/examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/GettingStartedWebCloudTest.java index 11fa1f57a..1ad8ddc50 100644 --- a/examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/GettingStartedWebCloudTest.java +++ b/examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/GettingStartedWebCloudTest.java @@ -22,6 +22,7 @@ package fiftyone.devicedetection.web; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.examples.shared.KeyHelper; import fiftyone.devicedetection.examples.web.EmbedJetty; import org.eclipse.jetty.server.Server; @@ -90,6 +91,9 @@ public void testWebCloud() throws Exception { body.contains("cloud device detection engine")); assertDetected(body, "Browser Name", "BrowserName", "Chrome"); assertDetected(body, "Platform Name", "PlatformName", "Windows"); + assertTrue("The page should end with the '" + FindOutMore.HEADING + + "' section. " + body, body.contains( + "

" + FindOutMore.HEADING + "

")); } /** diff --git a/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPremTest.java b/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPremTest.java index d6a94896f..967773a14 100644 --- a/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPremTest.java +++ b/examples/device-detection/web/getting-started.onprem/src/test/java/fiftyone/devicedetection/examples/web/GettingStartedWebOnPremTest.java @@ -22,6 +22,8 @@ package fiftyone.devicedetection.examples.web; +import fiftyone.devicedetection.examples.shared.DataFileHelper; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.shared.testhelpers.FileUtils; import org.eclipse.jetty.server.Server; import org.junit.AfterClass; @@ -36,14 +38,18 @@ import static fiftyone.devicedetection.examples.web.GettingStartedWebOnPrem.resourceBase; import static fiftyone.pipeline.util.FileFinder.getFilePath; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class GettingStartedWebOnPremTest { private static Server SERVER; @BeforeClass public static void startJetty() throws Exception { + // With no Enterprise file, the free Lite file is found, or + // downloaded, as the example finds it, so a fresh clone runs this. System.setProperty("TestDataFile", FileUtils.getHashFile() == null - ? FileUtils.LITE_HASH_DATA_FILE_PATH + ? DataFileHelper.findDataFile( + FileUtils.LITE_HASH_DATA_FILE_PATH).getAbsolutePath() : FileUtils.getHashFile().getAbsolutePath()); SERVER = EmbedJetty.startWebApp(getFilePath(resourceBase).getAbsolutePath(), 8081); } @@ -55,13 +61,17 @@ public void testWebOnPrem() throws Exception { (HttpURLConnection) new URL("http://localhost:8081/").openConnection(); InputStream response = connection.getInputStream(); + String responseBody; try (Scanner scanner = new Scanner(response)) { - String responseBody = scanner.useDelimiter("\\A").next(); + responseBody = scanner.useDelimiter("\\A").next(); System.out.println(responseBody); } int code = connection.getResponseCode(); connection.disconnect(); assertEquals(200, code); + assertTrue("The page should end with the '" + FindOutMore.HEADING + + "' section", responseBody.contains( + "

" + FindOutMore.HEADING + "

")); } @AfterClass diff --git a/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java index 2647e2c35..b9354f6a8 100644 --- a/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java +++ b/examples/ip-intelligence/shared/src/main/java/fiftyone/ipintelligence/examples/shared/FindOutMore.java @@ -141,6 +141,30 @@ public static void write( write(new PrintWriter(output), example, repositories); } + /** + * The section as HTML, for the end of a web example's page. + * @param example the example's tag + * @param repositories the repositories to list + * @return the markup + */ + public static String html(String example, String... repositories) { + StringBuilder html = new StringBuilder(); + html.append("
\n"); + html.append("

").append(HEADING).append("

\n"); + html.append(" \n
\n"); + return html.toString(); + } + /** * The address of a page on 51degrees.com, tagged with the example. * @param page the path of the page diff --git a/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java b/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java index 5433e1265..bb1d7843f 100644 --- a/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java +++ b/examples/ip-intelligence/shared/src/test/java/fiftyone/ipintelligence/examples/shared/FindOutMoreTest.java @@ -104,6 +104,35 @@ public void writeCommented_EveryLineAComment() { assertEquals("# " + FindOutMore.HEADING, lines[1]); } + /** + * The HTML form has the heading, each tagged page as a link with its + * ampersands escaped, and each repository as a link. + */ + @Test + public void html_LinksThenRepositories() { + String html = FindOutMore.html("web-example.java", + FindOutMore.ON_PREMISE_REPOSITORIES); + assertTrue(html, html.contains("

" + FindOutMore.HEADING + "

")); + java.util.regex.Matcher href = + Pattern.compile("href=\"([^\"]+)\"").matcher(html); + int pages = 0; + int repositories = 0; + while (href.find()) { + String link = href.group(1); + if (link.startsWith("https://51degrees.com/")) { + assertTrue(link, link.contains("&")); + assertTrue(link, + TAGGED.matcher(link.replace("&", "&")).matches()); + pages++; + } else { + assertTrue(link, link.startsWith("https://github.com/51Degrees/")); + repositories++; + } + } + assertEquals(3, pages); + assertEquals(3, repositories); + } + /** * A tag that is not a lower case slug would fail the campaign tag * convention, so it is refused. diff --git a/examples/ip-intelligence/web/getting-started.cloud.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixedTest.java b/examples/ip-intelligence/web/getting-started.cloud.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixedTest.java index ff49ca9e7..a5b7af546 100644 --- a/examples/ip-intelligence/web/getting-started.cloud.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixedTest.java +++ b/examples/ip-intelligence/web/getting-started.cloud.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixedTest.java @@ -22,6 +22,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.examples.shared.KeyHelper; import org.eclipse.jetty.server.Server; import org.junit.AfterClass; @@ -90,6 +91,9 @@ public void testWebCloudMixed() throws Exception { assertEquals("Expected HTTP 200 OK response", 200, code); assertTrue("Response should not be empty", responseBody.length() > 0); + assertTrue("The page should end with the '" + FindOutMore.HEADING + + "' section", responseBody.contains( + "

" + FindOutMore.HEADING + "

")); } @AfterClass diff --git a/examples/ip-intelligence/web/getting-started.cloud/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudTest.java b/examples/ip-intelligence/web/getting-started.cloud/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudTest.java index 06a7b8b48..0eb321002 100644 --- a/examples/ip-intelligence/web/getting-started.cloud/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudTest.java +++ b/examples/ip-intelligence/web/getting-started.cloud/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudTest.java @@ -22,6 +22,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.examples.shared.KeyHelper; import org.eclipse.jetty.server.Server; import org.junit.AfterClass; @@ -91,6 +92,9 @@ public void testWebCloud() throws Exception { // Assert we got a successful response assertEquals("Expected HTTP 200 OK response", 200, code); assertTrue("Response should not be empty", responseBody.length() > 0); + assertTrue("The page should end with the '" + FindOutMore.HEADING + + "' section", responseBody.contains( + "

" + FindOutMore.HEADING + "

")); } @AfterClass diff --git a/examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixedTest.java b/examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixedTest.java index 4aa023bb3..276a418b9 100644 --- a/examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixedTest.java +++ b/examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixedTest.java @@ -22,6 +22,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.examples.shared.DataFileHelper; import org.eclipse.jetty.server.Server; import org.junit.AfterClass; @@ -117,6 +118,9 @@ public void testWebMixed() throws Exception { assertEquals("Expected HTTP 200 OK response", 200, code); assertTrue("Response should not be empty", responseBody.length() > 0); + assertTrue("The page should end with the '" + FindOutMore.HEADING + + "' section", responseBody.contains( + "

" + FindOutMore.HEADING + "

")); } @AfterClass diff --git a/examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPremTest.java b/examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPremTest.java index e1831b39b..f995a4ea6 100644 --- a/examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPremTest.java +++ b/examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPremTest.java @@ -22,6 +22,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.examples.shared.DataFileHelper; import org.eclipse.jetty.server.Server; import org.junit.AfterClass; @@ -96,6 +97,9 @@ public void testWebOnPrem() throws Exception { // Assert we got a successful response assertEquals("Expected HTTP 200 OK response", 200, code); assertTrue("Response should not be empty", responseBody.length() > 0); + assertTrue("The page should end with the '" + FindOutMore.HEADING + + "' section", responseBody.contains( + "

" + FindOutMore.HEADING + "

")); } @AfterClass From b1945dbf724074d2c97e0b2255900b9e05f092f2 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 00:23:36 +0000 Subject: [PATCH 4/8] End every web example's page with a Find out more section The Device Detection pages add it after the contact-us banner, and the IP Intelligence on-premise, mixed, cloud and cloud mixed pages through a placeholder in their templates. --- .../examples/web/HtmlContentHelper.java | 11 +++++++++++ .../examples/web/GettingStartedWebCloudMixed.java | 9 +++++++++ .../src/main/webapp/WEB-INF/html/index.html | 2 ++ .../examples/web/GettingStartedWebCloud.java | 9 +++++++++ .../src/main/webapp/WEB-INF/html/index.html | 2 ++ .../examples/web/GettingStartedWebMixed.java | 9 +++++++++ .../src/main/webapp/WEB-INF/html/index.html | 1 + .../examples/web/GettingStartedWebOnPrem.java | 9 +++++++++ .../src/main/webapp/WEB-INF/html/index.html | 1 + 9 files changed, 53 insertions(+) diff --git a/examples/device-detection/web/shared/src/main/java/fiftyone/devicedetection/examples/web/HtmlContentHelper.java b/examples/device-detection/web/shared/src/main/java/fiftyone/devicedetection/examples/web/HtmlContentHelper.java index 2df9b35a9..d6184ce2a 100644 --- a/examples/device-detection/web/shared/src/main/java/fiftyone/devicedetection/examples/web/HtmlContentHelper.java +++ b/examples/device-detection/web/shared/src/main/java/fiftyone/devicedetection/examples/web/HtmlContentHelper.java @@ -23,6 +23,7 @@ package fiftyone.devicedetection.examples.web; import fiftyone.devicedetection.examples.shared.DataFileHelper; +import fiftyone.devicedetection.examples.shared.FindOutMore; import fiftyone.devicedetection.hash.engine.onpremise.flowelements.DeviceDetectionHashEngine; import fiftyone.devicedetection.shared.DeviceData; import fiftyone.pipeline.cloudrequestengine.flowelements.CloudRequestEngine; @@ -49,6 +50,12 @@ import static fiftyone.pipeline.util.FileFinder.getFilePath; public class HtmlContentHelper { + /** + * The tag of the links in the pages' "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "web-shared-src-main-java-fiftyone-devicedetection-examples-web-htmlcontenthelper.java"; + /** * Helper to output HTML headers * @param out the PrintWriter to write to @@ -306,6 +313,10 @@ private static void doContactUsMessage(PrintWriter out, boolean cloud) { public static void doHtmlPostamble(PrintWriter out, FlowData flowData) { // language=html doContactUsMessage(out, flowData); + out.append(FindOutMore.html(EXAMPLE_TAG, + getFlowElement(flowData) instanceof CloudRequestEngine ? + FindOutMore.CLOUD_REPOSITORIES : + FindOutMore.ON_PREMISE_REPOSITORIES)); out.append("\n\n\n"); } diff --git a/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixed.java b/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixed.java index 977e3b3fa..23ed0874c 100644 --- a/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixed.java +++ b/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloudMixed.java @@ -47,6 +47,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.devicedetection.shared.DeviceData; import fiftyone.ipintelligence.examples.shared.KeyHelper; import fiftyone.ipintelligence.shared.IPIntelligenceData; @@ -87,6 +88,12 @@ * line argument. */ public class GettingStartedWebCloudMixed extends HttpServlet { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "web-getting-started.cloud.mixed-src-main-java-fiftyone-ipintelligence-examples-web-gettingstartedwebcloudmixed.java"; + private static final long serialVersionUID = 1734154705981153543L; public static Logger logger = LoggerFactory.getLogger(GettingStartedWebCloudMixed.class); @@ -194,6 +201,8 @@ private String substituteTemplateValues(String template, DeviceData deviceData, .replace("${AREAS_JS}", escapeForJs(asWktStringProperty(tryGet(ipiData::getAreas)))) .replace("${ACCURACY_RADIUS}", asIntegerProperty(tryGet(ipiData::getAccuracyRadiusMin))) .replace("${TIME_ZONE_OFFSET}", asIntegerProperty(tryGet(ipiData::getTimeZoneOffset))) + .replace("${FIND_OUT_MORE}", FindOutMore.html(EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES)) .replace("${EVIDENCE_ROWS}", buildEvidenceRows(flowData)) .replace("${LocationConfidence}", asStringProperty(tryGet(ipiData::getLocationConfidence))) .replace("${ConnectionType}", asStringProperty(tryGet(ipiData::getConnectionType))) diff --git a/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/webapp/WEB-INF/html/index.html b/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/webapp/WEB-INF/html/index.html index 0c6a897fe..d7947d95d 100644 --- a/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/webapp/WEB-INF/html/index.html +++ b/examples/ip-intelligence/web/getting-started.cloud.mixed/src/main/webapp/WEB-INF/html/index.html @@ -133,6 +133,8 @@

Evidence Used

+ ${FIND_OUT_MORE} + diff --git a/examples/ip-intelligence/web/getting-started.cloud/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloud.java b/examples/ip-intelligence/web/getting-started.cloud/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloud.java index 2e0fbb58f..c849b2560 100644 --- a/examples/ip-intelligence/web/getting-started.cloud/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloud.java +++ b/examples/ip-intelligence/web/getting-started.cloud/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebCloud.java @@ -59,6 +59,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.examples.shared.KeyHelper; import fiftyone.ipintelligence.shared.IPIntelligenceData; import fiftyone.pipeline.core.data.FlowData; @@ -99,6 +100,12 @@ * line argument. */ public class GettingStartedWebCloud extends HttpServlet { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "web-getting-started.cloud-src-main-java-fiftyone-ipintelligence-examples-web-gettingstartedwebcloud.java"; + private static final long serialVersionUID = 1734154705981153542L; public static Logger logger = LoggerFactory.getLogger(GettingStartedWebCloud.class); @@ -203,6 +210,8 @@ private String substituteTemplateValues(String template, IPIntelligenceData ipiD .replace("${AREAS_JS}", escapeForJs(asWktStringProperty(tryGet(ipiData::getAreas)))) .replace("${ACCURACY_RADIUS}", asIntegerProperty(tryGet(ipiData::getAccuracyRadiusMin))) .replace("${TIME_ZONE_OFFSET}", asIntegerProperty(tryGet(ipiData::getTimeZoneOffset))) + .replace("${FIND_OUT_MORE}", FindOutMore.html(EXAMPLE_TAG, + FindOutMore.CLOUD_REPOSITORIES)) .replace("${EVIDENCE_ROWS}", buildEvidenceRows(flowData)); } diff --git a/examples/ip-intelligence/web/getting-started.cloud/src/main/webapp/WEB-INF/html/index.html b/examples/ip-intelligence/web/getting-started.cloud/src/main/webapp/WEB-INF/html/index.html index 05e1d4298..37924c22a 100644 --- a/examples/ip-intelligence/web/getting-started.cloud/src/main/webapp/WEB-INF/html/index.html +++ b/examples/ip-intelligence/web/getting-started.cloud/src/main/webapp/WEB-INF/html/index.html @@ -81,6 +81,8 @@

Location Map

+ ${FIND_OUT_MORE} + diff --git a/examples/ip-intelligence/web/getting-started.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixed.java b/examples/ip-intelligence/web/getting-started.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixed.java index 18f5bc05b..bde4ee782 100644 --- a/examples/ip-intelligence/web/getting-started.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixed.java +++ b/examples/ip-intelligence/web/getting-started.mixed/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebMixed.java @@ -47,6 +47,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.devicedetection.hash.engine.onpremise.flowelements.DeviceDetectionHashEngine; import fiftyone.devicedetection.shared.DeviceData; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; @@ -88,6 +89,12 @@ * By default the free Lite data files are used. */ public class GettingStartedWebMixed extends HttpServlet { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "web-getting-started.mixed-src-main-java-fiftyone-ipintelligence-examples-web-gettingstartedwebmixed.java"; + private static final long serialVersionUID = 1734154705981153541L; public static Logger logger = LoggerFactory.getLogger(GettingStartedWebMixed.class); @@ -228,6 +235,8 @@ private String substituteTemplateValues(String template, DeviceData deviceData, escapeForJs(asString(ipiData.getAreas())) : "") .replace("${ACCURACY_RADIUS}", value(ipiEngine, "AccuracyRadiusMin", ipiData::getAccuracyRadiusMin)) .replace("${TIME_ZONE_OFFSET}", value(ipiEngine, "TimeZoneOffset", ipiData::getTimeZoneOffset)) + .replace("${FIND_OUT_MORE}", FindOutMore.html(EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES)) .replace("${EVIDENCE_ROWS}", buildEvidenceRows(flowData)) .replace("${LocationConfidence}", value(ipiEngine, "LocationConfidence", ipiData::getLocationConfidence)) .replace("${ConnectionType}", value(ipiEngine, "ConnectionType", ipiData::getConnectionType)) diff --git a/examples/ip-intelligence/web/getting-started.mixed/src/main/webapp/WEB-INF/html/index.html b/examples/ip-intelligence/web/getting-started.mixed/src/main/webapp/WEB-INF/html/index.html index 667dca9a9..e9af3cfff 100644 --- a/examples/ip-intelligence/web/getting-started.mixed/src/main/webapp/WEB-INF/html/index.html +++ b/examples/ip-intelligence/web/getting-started.mixed/src/main/webapp/WEB-INF/html/index.html @@ -133,6 +133,7 @@

Location map

${CONTACT_MESSAGE} + ${FIND_OUT_MORE} diff --git a/examples/ip-intelligence/web/getting-started.onprem/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPrem.java b/examples/ip-intelligence/web/getting-started.onprem/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPrem.java index d87b20d5d..74abd3d15 100644 --- a/examples/ip-intelligence/web/getting-started.onprem/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPrem.java +++ b/examples/ip-intelligence/web/getting-started.onprem/src/main/java/fiftyone/ipintelligence/examples/web/GettingStartedWebOnPrem.java @@ -61,6 +61,7 @@ package fiftyone.ipintelligence.examples.web; +import fiftyone.ipintelligence.examples.shared.FindOutMore; import fiftyone.ipintelligence.engine.onpremise.flowelements.IPIntelligenceOnPremiseEngine; import fiftyone.ipintelligence.examples.shared.DataFileHelper; import fiftyone.ipintelligence.shared.IPIntelligenceData; @@ -107,6 +108,12 @@ * obtain an Enterprise data file, please [contact us](https://51degrees.com/contact-us?utm_source=code&utm_medium=example&utm_campaign=51degrees-java&utm_content=web-getting-started.onprem-src-main-java-fiftyone-ipintelligence-examples-web-gettingstartedwebonprem.java&utm_term=gettingstartedwebonprem). */ public class GettingStartedWebOnPrem extends HttpServlet { + /** + * This example's tag in the links of its "Find out more" section. + */ + private static final String EXAMPLE_TAG = + "web-getting-started.onprem-src-main-java-fiftyone-ipintelligence-examples-web-gettingstartedwebonprem.java"; + private static final long serialVersionUID = 1734154705981153540L; public static Logger logger = LoggerFactory.getLogger(GettingStartedWebOnPrem.class); @@ -227,6 +234,8 @@ private String substituteTemplateValues(String template, IPIntelligenceData ipiD escapeForJs(asString(ipiData.getAreas())) : "") .replace("${ACCURACY_RADIUS}", value(ipiEngine, "AccuracyRadiusMin", ipiData::getAccuracyRadiusMin)) .replace("${TIME_ZONE_OFFSET}", value(ipiEngine, "TimeZoneOffset", ipiData::getTimeZoneOffset)) + .replace("${FIND_OUT_MORE}", FindOutMore.html(EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES)) .replace("${EVIDENCE_ROWS}", buildEvidenceRows(flowData)) // On-premise engine: only invite the user to contact us about the // Enterprise data file when running on a free data file. diff --git a/examples/ip-intelligence/web/getting-started.onprem/src/main/webapp/WEB-INF/html/index.html b/examples/ip-intelligence/web/getting-started.onprem/src/main/webapp/WEB-INF/html/index.html index 2abdface2..afb91cab8 100644 --- a/examples/ip-intelligence/web/getting-started.onprem/src/main/webapp/WEB-INF/html/index.html +++ b/examples/ip-intelligence/web/getting-started.onprem/src/main/webapp/WEB-INF/html/index.html @@ -92,6 +92,7 @@

Location map

${CONTACT_MESSAGE} + ${FIND_OUT_MORE} From b8b3b2928adfc3a9e64c1c4ce99eed855bc99d50 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 00:29:44 +0000 Subject: [PATCH 5/8] Test that the web examples' options files default to HTTPS and the free data file --- .../web/CloudOptionsFileTest.java | 56 +++++++++++++++++ .../examples/web/OptionsFileTest.java | 61 +++++++++++++++++++ .../examples/web/OptionsFileTest.java | 61 +++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/CloudOptionsFileTest.java create mode 100644 examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java create mode 100644 examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java diff --git a/examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/CloudOptionsFileTest.java b/examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/CloudOptionsFileTest.java new file mode 100644 index 000000000..1fb4db330 --- /dev/null +++ b/examples/device-detection/web/getting-started.cloud/src/test/java/fiftyone/devicedetection/web/CloudOptionsFileTest.java @@ -0,0 +1,56 @@ +/* ********************************************************************* + * 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.devicedetection.web; + +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertTrue; + +/** + * Checks the options file the cloud web example runs with. + */ +public class CloudOptionsFileTest { + + /** + * With no endpoint set, the example reaches the cloud service over + * HTTPS. + */ + @Test + public void defaultEndPoint_Https() throws IOException { + String xml = new String(Files.readAllBytes(Paths.get( + System.getProperty("basedir", "."), "src", "main", "webapp", + "WEB-INF", "51Degrees-Cloud.xml")), StandardCharsets.UTF_8); + Matcher endPoint = Pattern.compile( + "\\$\\{[^:}]*:-([^}]*)\\}").matcher(xml); + assertTrue("51Degrees-Cloud.xml should give a default endpoint", + endPoint.find()); + assertTrue(endPoint.group(1), endPoint.group(1).startsWith("https://")); + } +} diff --git a/examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java b/examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java new file mode 100644 index 000000000..87685c702 --- /dev/null +++ b/examples/ip-intelligence/web/getting-started.mixed/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java @@ -0,0 +1,61 @@ +/* ********************************************************************* + * 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.ipintelligence.examples.web; + +import fiftyone.ipintelligence.examples.shared.DataFileHelper; +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Checks the options file this web example runs with. + */ +public class OptionsFileTest { + + /** + * With no data file set, the example falls back to the free Lite file, + * which a fresh clone downloads, and not to the Enterprise file, which a + * fresh clone never has. + */ + @Test + public void defaultDataFile_FreeLiteFile() throws IOException { + String xml = new String(Files.readAllBytes(Paths.get( + System.getProperty("basedir", "."), "src", "main", "webapp", + "WEB-INF", "51Degrees-Mixed.xml")), StandardCharsets.UTF_8); + Matcher dataFile = Pattern.compile( + "\\$\\{TestDataFile:-([^}]*)\\}") + .matcher(xml); + assertTrue("51Degrees-Mixed.xml should give a default IP Intelligence " + + "data file", dataFile.find()); + assertEquals("cxx/data/" + DataFileHelper.LITE_DATA_FILE_REL_PATH, + dataFile.group(1)); + } +} diff --git a/examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java b/examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java new file mode 100644 index 000000000..047f34bdc --- /dev/null +++ b/examples/ip-intelligence/web/getting-started.onprem/src/test/java/fiftyone/ipintelligence/examples/web/OptionsFileTest.java @@ -0,0 +1,61 @@ +/* ********************************************************************* + * 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.ipintelligence.examples.web; + +import fiftyone.ipintelligence.examples.shared.DataFileHelper; +import org.junit.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Checks the options file this web example runs with. + */ +public class OptionsFileTest { + + /** + * With no data file set, the example falls back to the free Lite file, + * which a fresh clone downloads, and not to the Enterprise file, which a + * fresh clone never has. + */ + @Test + public void defaultDataFile_FreeLiteFile() throws IOException { + String xml = new String(Files.readAllBytes(Paths.get( + System.getProperty("basedir", "."), "src", "main", "webapp", + "WEB-INF", "51Degrees-OnPrem.xml")), StandardCharsets.UTF_8); + Matcher dataFile = Pattern.compile( + "\\$\\{TestDataFile:-([^}]*)\\}") + .matcher(xml); + assertTrue("51Degrees-OnPrem.xml should give a default IP Intelligence " + + "data file", dataFile.find()); + assertEquals("cxx/data/" + DataFileHelper.LITE_DATA_FILE_REL_PATH, + dataFile.group(1)); + } +} From 41981d1e1ff36e4951c5e1614f08c47cc35957ee Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 00:30:06 +0000 Subject: [PATCH 6/8] Default the web examples to HTTPS and the free IP Intelligence file The Device Detection cloud web example's options file named the cloud service over plain HTTP. The IP Intelligence on-premise and mixed web examples' options files fell back to the Enterprise data file, which a fresh clone never has, and now fall back to the free Lite file. --- .../src/main/webapp/WEB-INF/51Degrees-Cloud.xml | 2 +- .../src/main/webapp/WEB-INF/51Degrees-Mixed.xml | 2 +- .../src/main/webapp/WEB-INF/51Degrees-OnPrem.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/device-detection/web/getting-started.cloud/src/main/webapp/WEB-INF/51Degrees-Cloud.xml b/examples/device-detection/web/getting-started.cloud/src/main/webapp/WEB-INF/51Degrees-Cloud.xml index ced491606..a7abb5715 100644 --- a/examples/device-detection/web/getting-started.cloud/src/main/webapp/WEB-INF/51Degrees-Cloud.xml +++ b/examples/device-detection/web/getting-started.cloud/src/main/webapp/WEB-INF/51Degrees-Cloud.xml @@ -25,7 +25,7 @@ - ${TestCloudEndpoint:-http://cloud.51degrees.com/api/v4} + ${TestCloudEndpoint:-https://cloud.51degrees.com/api/v4} - ${TestDataFile:-cxx/data/ip-intelligence/51Degrees-EnterpriseIpiV41.ipi} + ${TestDataFile:-cxx/data/ip-intelligence/51Degrees-LiteV41.ipi} LowMemory IPIntelligenceOnPremiseEngine From d25574f2959195c261862b55bd8ae2243bcdf828 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 10:00:03 +0000 Subject: [PATCH 7/8] Test that an unknown performance profile still ends with Find out more CompareOnPrem and MetricsOnPrem return when their fourth argument names no performance profile. The no-settings tests now run each with one, and the check's Javadoc says what it checks, the section after the last contact link and closed by its rule, as log lines may follow it. --- .../console/ExamplesWithoutSettingsTest.java | 5 +- .../console/ExamplesWithoutSettingsTest.java | 55 ++++++++++++++++--- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java b/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java index 9c36dc2ea..00f21fca2 100644 --- a/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java +++ b/examples/device-detection/console/src/test/java/fiftyone/devicedetection/examples/console/ExamplesWithoutSettingsTest.java @@ -86,8 +86,9 @@ private static void assertContains(String output, String expected) { } /** - * Checks that the output ends with the "Find out more" section, after - * the link to the contact page. + * Checks that the output has the "Find out more" section after the last + * link to the contact page, and that the section closes with its rule. + * Log lines may still follow the section. */ private static void assertFindOutMore(String output) { int heading = output.lastIndexOf(FindOutMore.HEADING); diff --git a/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java b/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java index 14c6a4ec6..8b5e2c9a3 100644 --- a/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java +++ b/examples/ip-intelligence/console/src/test/java/fiftyone/ipintelligence/examples/console/ExamplesWithoutSettingsTest.java @@ -48,6 +48,11 @@ public class ExamplesWithoutSettingsTest { private static final String LICENSE_KEY = UpdateDataFile.UPDATE_EXAMPLE_LICENSE_KEY_NAME; + /** + * A name that is not a performance profile. + */ + private static final String UNKNOWN_PROFILE = "NoSuchProfile"; + /** * An example's main method. */ @@ -56,14 +61,15 @@ private interface Main { } /** - * Runs the example's main with no arguments and the data file and - * licence key system properties removed, and returns what it wrote to - * standard output. The deprecated name of the data file variable is - * read when the current one is not set, so both are checked and - * removed. + * Runs the example's main with the arguments given, none unless a test + * gives some, and the data file and licence key system properties + * removed, and returns what it wrote to standard output. The deprecated + * name of the data file variable is read when the current one is not + * set, so both are checked and removed. */ @SuppressWarnings("deprecation") - private static String runWithoutSettings(Main main) throws Exception { + private static String runWithoutSettings(Main main, String... args) + throws Exception { assumeTrue("Skipping, a data file or licence key is set in the environment", System.getenv(DataFileHelper.IPI_PATH_VARIABLE) == null && System.getenv(DataFileHelper.IPI_PATH_ENV_VAR) == null && @@ -77,7 +83,7 @@ private static String runWithoutSettings(Main main) throws Exception { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); System.setOut(new PrintStream(buffer, true, "UTF-8")); try { - main.main(new String[0]); + main.main(args); } finally { System.setOut(out); if (dataFile != null) { @@ -103,8 +109,9 @@ private static void assertContains(String output, String expected) { } /** - * Checks that the output ends with the "Find out more" section, after - * the link to the contact page. + * Checks that the output has the "Find out more" section after the last + * link to the contact page, and that the section closes with its rule. + * Log lines may still follow the section. */ private static void assertFindOutMore(String output) { int heading = output.lastIndexOf(FindOutMore.HEADING); @@ -154,6 +161,36 @@ public void metrics() throws Exception { "Measuring the location areas"); } + /** + * A name that is not a performance profile ends the example after the + * names it accepts, and the section still follows. + */ + @Test + public void compare_UnknownProfile() throws Exception { + assertContains( + runWithoutSettings(CompareOnPrem::main, + DataFileHelper.LITE_DATA_FILE_REL_PATH, + CompareOnPrem.GEOIP_COMPARISON_EVIDENCE_REL_PATH, + CompareOnPrem.DEFAULT_OUTPUT_FILE, + UNKNOWN_PROFILE), + "'" + UNKNOWN_PROFILE + "' is not a performance profile."); + } + + /** + * A name that is not a performance profile ends the example after the + * names it accepts, and the section still follows. + */ + @Test + public void metrics_UnknownProfile() throws Exception { + assertContains( + runWithoutSettings(MetricsOnPrem::main, + DataFileHelper.LITE_DATA_FILE_REL_PATH, + MetricsOnPrem.DEFAULT_OUTPUT_FILE, + String.valueOf(MetricsOnPrem.DEFAULT_SAMPLE_PERCENTAGE), + UNKNOWN_PROFILE), + "'" + UNKNOWN_PROFILE + "' is not a performance profile."); + } + @Test public void offlineProcessing() throws Exception { String output = runWithoutSettings(OfflineProcessing::main); From 2e9b7f700f7cb42acbb1a1fd8afa9545deccc01e Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 10:00:25 +0000 Subject: [PATCH 8/8] End CompareOnPrem and MetricsOnPrem with Find out more on an unknown profile --- .../fiftyone/ipintelligence/examples/console/CompareOnPrem.java | 2 ++ .../fiftyone/ipintelligence/examples/console/MetricsOnPrem.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java index 0c3e98d68..1e4bae6ad 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/CompareOnPrem.java @@ -214,6 +214,8 @@ public static void main(String[] args) throws Exception { args[3], new PrintWriter(System.out)) : DEFAULT_PERFORMANCE_PROFILE; if (profile == null) { + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); return; } diff --git a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java index d287f69f9..19466fc9a 100644 --- a/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java +++ b/examples/ip-intelligence/console/src/main/java/fiftyone/ipintelligence/examples/console/MetricsOnPrem.java @@ -332,6 +332,8 @@ public static void main(String[] args) throws Exception { args[3], new PrintWriter(System.out)) : DEFAULT_PERFORMANCE_PROFILE; if (profile == null) { + FindOutMore.write(System.out, EXAMPLE_TAG, + FindOutMore.ON_PREMISE_REPOSITORIES); return; }