You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by di...@apache.org on 2021/12/30 15:38:30 UTC

[sling-org-apache-sling-sitemap] branch issue/SLING-10560 created (now e91ded0)

This is an automated email from the ASF dual-hosted git repository.

diru pushed a change to branch issue/SLING-10560
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-sitemap.git.


      at e91ded0  SLING-19569: add google image extension

This branch includes the following new commits:

     new e91ded0  SLING-19569: add google image extension

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[sling-org-apache-sling-sitemap] 01/01: SLING-19569: add google image extension

Posted by di...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

diru pushed a commit to branch issue/SLING-10560
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-sitemap.git

commit e91ded0dda950706a61a8d934b2d827c2158d112
Author: Dirk Rudolph <di...@apache.org>
AuthorDate: Thu Dec 30 16:38:16 2021 +0100

    SLING-19569: add google image extension
---
 .../builder/extensions/GoogleImageExtension.java   |  30 ++++++
 .../sitemap/impl/SitemapGeneratorExecutor.java     |   2 +-
 .../AlternateLanguageExtensionProvider.java        |   2 +-
 .../extensions/GoogleImageExtensionProvider.java   | 109 +++++++++++++++++++++
 .../sitemap/impl/builder/AbstractBuilderTest.java  |   3 +-
 .../extensions/GoogleImageExtensionTest.java       |  93 ++++++++++++++++++
 src/test/resources/sitemap-image-1.1.xsd           |  71 ++++++++++++++
 7 files changed, 307 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/sling/sitemap/builder/extensions/GoogleImageExtension.java b/src/main/java/org/apache/sling/sitemap/builder/extensions/GoogleImageExtension.java
new file mode 100644
index 0000000..f36c23c
--- /dev/null
+++ b/src/main/java/org/apache/sling/sitemap/builder/extensions/GoogleImageExtension.java
@@ -0,0 +1,30 @@
+package org.apache.sling.sitemap.builder.extensions;
+
+import org.apache.sling.sitemap.builder.Extension;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * An extension to add image links and metadata to an {@link org.apache.sling.sitemap.builder.Url}.
+ *
+ * @see <a href="https://developers.google.com/search/docs/advanced/sitemaps/image-sitemaps">Image sitemaps</a>
+ */
+@ProviderType
+public interface GoogleImageExtension extends Extension {
+
+    @NotNull
+    GoogleImageExtension setUrl(@NotNull String location);
+
+    @NotNull
+    GoogleImageExtension setCaption(String caption);
+
+    @NotNull
+    GoogleImageExtension setGeoLocation(String geoLocation);
+
+    @NotNull
+    GoogleImageExtension setTitle(String title);
+
+    @NotNull
+    GoogleImageExtension setLicense(String licenseLocation);
+
+}
diff --git a/src/main/java/org/apache/sling/sitemap/impl/SitemapGeneratorExecutor.java b/src/main/java/org/apache/sling/sitemap/impl/SitemapGeneratorExecutor.java
index f6b987e..2cf1b73 100644
--- a/src/main/java/org/apache/sling/sitemap/impl/SitemapGeneratorExecutor.java
+++ b/src/main/java/org/apache/sling/sitemap/impl/SitemapGeneratorExecutor.java
@@ -163,7 +163,7 @@ public class SitemapGeneratorExecutor implements JobExecutor {
                 LOG.debug("Generated sitemaps: {}", String.join(", ", sitemap.files));
             }
 
-            // when the max(fileIndex) is smaller then in previous iterations, cleanup old files.
+            // when the max(fileIndex) is smaller than in previous iterations, cleanup old files.
             Collection<String> purgedFiles = storage.deleteSitemaps(res, name, i -> i.getFileIndex() >= sitemap.fileIndex);
 
             if (LOG.isDebugEnabled()) {
diff --git a/src/main/java/org/apache/sling/sitemap/impl/builder/extensions/AlternateLanguageExtensionProvider.java b/src/main/java/org/apache/sling/sitemap/impl/builder/extensions/AlternateLanguageExtensionProvider.java
index e41ee82..90b801f 100644
--- a/src/main/java/org/apache/sling/sitemap/impl/builder/extensions/AlternateLanguageExtensionProvider.java
+++ b/src/main/java/org/apache/sling/sitemap/impl/builder/extensions/AlternateLanguageExtensionProvider.java
@@ -50,7 +50,7 @@ public class AlternateLanguageExtensionProvider implements SitemapExtensionProvi
         private String hreflang;
         private String href;
 
-        private static <T> T required(T object, String message) throws XMLStreamException {
+        private static String required(String object, String message) throws XMLStreamException {
             if (object == null) {
                 throw new XMLStreamException(message);
             }
diff --git a/src/main/java/org/apache/sling/sitemap/impl/builder/extensions/GoogleImageExtensionProvider.java b/src/main/java/org/apache/sling/sitemap/impl/builder/extensions/GoogleImageExtensionProvider.java
new file mode 100644
index 0000000..2c4a1c0
--- /dev/null
+++ b/src/main/java/org/apache/sling/sitemap/impl/builder/extensions/GoogleImageExtensionProvider.java
@@ -0,0 +1,109 @@
+package org.apache.sling.sitemap.impl.builder.extensions;
+
+import org.apache.sling.sitemap.builder.extensions.GoogleImageExtension;
+import org.apache.sling.sitemap.spi.builder.AbstractExtension;
+import org.apache.sling.sitemap.spi.builder.SitemapExtensionProvider;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.annotations.Component;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+@Component(
+        property = {
+                SitemapExtensionProvider.PROPERTY_INTERFACE + "=org.apache.sling.sitemap.builder.extensions.GoogleImageExtension",
+                SitemapExtensionProvider.PROPERTY_PREFIX + "=image",
+                SitemapExtensionProvider.PROPERTY_NAMESPACE + "=http://www.google.com/schemas/sitemap-image/1.1",
+                SitemapExtensionProvider.PROPERTY_LOCAL_NAME + "=image"
+        }
+)
+public class GoogleImageExtensionProvider implements SitemapExtensionProvider {
+
+    @Override
+    @NotNull
+    public AbstractExtension newInstance() {
+        return new ExtensionImpl();
+    }
+
+    private static class ExtensionImpl extends AbstractExtension implements GoogleImageExtension {
+
+        private String url;
+        private String caption;
+        private String geoLocation;
+        private String title;
+        private String license;
+
+        private static String required(String object, String message) throws XMLStreamException {
+            if (object == null) {
+                throw new XMLStreamException(message);
+            }
+            return object;
+        }
+
+        @Override
+        @NotNull
+        public GoogleImageExtension setUrl(@NotNull String location) {
+            this.url = location;
+            return this;
+        }
+
+        @Override
+        @NotNull
+        public GoogleImageExtension setCaption(String caption) {
+            this.caption = caption;
+            return this;
+        }
+
+        @Override
+        @NotNull
+        public GoogleImageExtension setGeoLocation(String geoLocation) {
+            this.geoLocation = geoLocation;
+            return this;
+        }
+
+        @Override
+        @NotNull
+        public GoogleImageExtension setTitle(String title) {
+            this.title = title;
+            return this;
+        }
+
+        @Override
+        @NotNull
+        public GoogleImageExtension setLicense(String licenseLocation) {
+            this.license = licenseLocation;
+            return this;
+        }
+
+        @Override
+        public void writeTo(@NotNull XMLStreamWriter writer) throws XMLStreamException {
+            writer.writeStartElement("loc");
+            writer.writeCharacters(required(url,"image:loc is missing"));
+            writer.writeEndElement();
+
+            if (caption != null) {
+                writer.writeStartElement("caption");
+                writer.writeCharacters(caption);
+                writer.writeEndElement();
+            }
+
+            if (geoLocation != null) {
+                writer.writeStartElement("geo_location");
+                writer.writeCharacters(geoLocation);
+                writer.writeEndElement();
+            }
+
+            if (title != null) {
+                writer.writeStartElement("title");
+                writer.writeCharacters(title);
+                writer.writeEndElement();
+            }
+
+            if (license != null) {
+                writer.writeStartElement("license");
+                writer.writeCharacters(license);
+                writer.writeEndElement();
+            }
+        }
+    }
+}
diff --git a/src/test/java/org/apache/sling/sitemap/impl/builder/AbstractBuilderTest.java b/src/test/java/org/apache/sling/sitemap/impl/builder/AbstractBuilderTest.java
index 4816a70..e1ceeca 100644
--- a/src/test/java/org/apache/sling/sitemap/impl/builder/AbstractBuilderTest.java
+++ b/src/test/java/org/apache/sling/sitemap/impl/builder/AbstractBuilderTest.java
@@ -42,9 +42,10 @@ public abstract class AbstractBuilderTest {
     private static final URL XHTML_XSD = AbstractBuilderTest.class.getClassLoader().getResource("xhtml1-strict.xsd");
     private static final URL SITEMAP_XSD = AbstractBuilderTest.class.getClassLoader().getResource("sitemap-0.9.xsd");
     private static final URL SITEMAP_INDEX_XSD = AbstractBuilderTest.class.getClassLoader().getResource("siteindex-0.9.xsd");
+    private static final URL SITEMAP_IMAGE_XSD = AbstractBuilderTest.class.getClassLoader().getResource("sitemap-image-1.1.xsd");
 
     protected void assertSitemap(String expected, String given) {
-        assertEqualsAndValid(expected, given, XML_XSD, XHTML_XSD, SITEMAP_XSD);
+        assertEqualsAndValid(expected, given, XML_XSD, XHTML_XSD, SITEMAP_XSD, SITEMAP_IMAGE_XSD);
     }
 
     protected void assertSitemapIndex(String expected, String given) {
diff --git a/src/test/java/org/apache/sling/sitemap/impl/builder/extensions/GoogleImageExtensionTest.java b/src/test/java/org/apache/sling/sitemap/impl/builder/extensions/GoogleImageExtensionTest.java
new file mode 100644
index 0000000..47c4832
--- /dev/null
+++ b/src/test/java/org/apache/sling/sitemap/impl/builder/extensions/GoogleImageExtensionTest.java
@@ -0,0 +1,93 @@
+package org.apache.sling.sitemap.impl.builder.extensions;
+
+import org.apache.sling.sitemap.SitemapException;
+import org.apache.sling.sitemap.builder.Url;
+import org.apache.sling.sitemap.builder.extensions.GoogleImageExtension;
+import org.apache.sling.sitemap.impl.builder.AbstractBuilderTest;
+import org.apache.sling.sitemap.impl.builder.SitemapImpl;
+import org.apache.sling.testing.mock.sling.junit5.SlingContext;
+import org.apache.sling.testing.mock.sling.junit5.SlingContextExtension;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+@ExtendWith({SlingContextExtension.class})
+public class GoogleImageExtensionTest extends AbstractBuilderTest {
+
+    final SlingContext context = new SlingContext();
+
+    private ExtensionProviderManager extensionProviderManager;
+
+    @BeforeEach
+    void setup() {
+        context.registerInjectActivateService(new GoogleImageExtensionProvider());
+        extensionProviderManager = context.registerInjectActivateService(new ExtensionProviderManager());
+    }
+
+    @Test
+    void testGoogleImageCombinations() throws SitemapException, IOException {
+        // given
+        StringWriter writer = new StringWriter();
+        SitemapImpl sitemap = new SitemapImpl(writer, extensionProviderManager);
+
+        // when
+        Url url = sitemap.addUrl("http://example.ch/de.html");
+        url.addExtension(GoogleImageExtension.class)
+                .setUrl("http://example.ch/dam/de/images/hero.jpg");
+        url.addExtension(GoogleImageExtension.class)
+                .setUrl("http://example.ch/dam/de/images/brand.jpg")
+                .setCaption("Nothing can go wrong trusting our strong brand.")
+                .setTitle("Brand image")
+                .setGeoLocation("Europe/Zurich")
+                .setLicense("https://creativecommons.org/publicdomain/zero/1.0/");
+        sitemap.close();
+
+        // then
+        assertSitemap(
+                AbstractBuilderTest.XML_HEADER + "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" " +
+                        "xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\">"
+                        + "<url>"
+                        + "<loc>http://example.ch/de.html</loc>"
+                        + "<image:image>"
+                        + "<image:loc>http://example.ch/dam/de/images/hero.jpg</image:loc>"
+                        + "</image:image>"
+                        + "<image:image>"
+                        + "<image:loc>http://example.ch/dam/de/images/brand.jpg</image:loc>"
+                        + "<image:caption>Nothing can go wrong trusting our strong brand.</image:caption>"
+                        + "<image:geo_location>Europe/Zurich</image:geo_location>"
+                        + "<image:title>Brand image</image:title>"
+                        + "<image:license>https://creativecommons.org/publicdomain/zero/1.0/</image:license>"
+                        + "</image:image>"
+                        + "</url>"
+                        + "</urlset>",
+                writer.toString()
+        );
+    }
+
+    @Test
+    void testNothingWrittenWhenExtensionMissesMandatoryProperties() throws SitemapException, IOException {
+        // given
+        StringWriter writer = new StringWriter();
+        SitemapImpl sitemap = new SitemapImpl(writer, extensionProviderManager);
+
+        // when
+        Url url = sitemap.addUrl("http://example.ch/de.html");
+        url.addExtension(GoogleImageExtension.class);
+        sitemap.close();
+
+        // then
+        assertSitemap(
+                AbstractBuilderTest.XML_HEADER + "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" " +
+                        "xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\">"
+                        + "<url>"
+                        + "<loc>http://example.ch/de.html</loc>"
+                        + "</url>"
+                        + "</urlset>",
+                writer.toString()
+        );
+    }
+
+}
diff --git a/src/test/resources/sitemap-image-1.1.xsd b/src/test/resources/sitemap-image-1.1.xsd
new file mode 100644
index 0000000..440d277
--- /dev/null
+++ b/src/test/resources/sitemap-image-1.1.xsd
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsd:schema
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+    targetNamespace="http://www.google.com/schemas/sitemap-image/1.1"
+    xmlns="http://www.google.com/schemas/sitemap-image/1.1"
+    elementFormDefault="qualified">
+
+<xsd:annotation>
+  <xsd:documentation>
+    XML Schema for the Image Sitemap extension. This schema defines the
+    Image-specific elements only; the core Sitemap elements are defined
+    separately.
+
+    Help Center documentation for the Image Sitemap extension:
+
+      http://www.google.com/support/webmasters/bin/answer.py?answer=178636
+
+    Copyright 2010 Google Inc. All Rights Reserved.
+  </xsd:documentation>
+</xsd:annotation>
+
+<xsd:element name="image">
+  <xsd:annotation>
+    <xsd:documentation>
+      Encloses all information about a single image. Each URL (&lt;loc&gt; tag)
+      can include up to 1,000 &lt;image:image&gt; tags.
+    </xsd:documentation>
+  </xsd:annotation>
+  <xsd:complexType>
+    <xsd:sequence>
+      <xsd:element name="loc" type="xsd:anyURI">
+        <xsd:annotation>
+          <xsd:documentation>
+            The URL of the image.
+          </xsd:documentation>
+        </xsd:annotation>
+      </xsd:element>
+      <xsd:element name="caption" type="xsd:string" minOccurs="0">
+        <xsd:annotation>
+          <xsd:documentation>
+            The caption of the image.
+          </xsd:documentation>
+        </xsd:annotation>
+      </xsd:element>
+      <xsd:element name="geo_location" type="xsd:string" minOccurs="0">
+        <xsd:annotation>
+          <xsd:documentation>
+            The geographic location of the image. For example,
+            "Limerick, Ireland".
+          </xsd:documentation>
+        </xsd:annotation>
+      </xsd:element>
+      <xsd:element name="title" type="xsd:string" minOccurs="0">
+        <xsd:annotation>
+          <xsd:documentation>
+            The title of the image.
+          </xsd:documentation>
+        </xsd:annotation>
+      </xsd:element>
+      <xsd:element name="license" type="xsd:anyURI" minOccurs="0">
+        <xsd:annotation>
+          <xsd:documentation>
+            A URL to the license of the image.
+          </xsd:documentation>
+        </xsd:annotation>
+      </xsd:element>
+    </xsd:sequence>
+  </xsd:complexType>
+</xsd:element>
+
+</xsd:schema>