You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2020/11/23 08:20:04 UTC

[james-project] 05/19: JAMES-2884 Configure default JMAP version

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

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit f6594105783b424157b7c761d0fa022c97402055
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sat Nov 21 08:02:43 2020 +0700

    JAMES-2884 Configure default JMAP version
---
 .../servers/pages/distributed/configure/jmap.adoc  |  6 ++++++
 .../org/apache/james/jmap/draft/JMAPModule.java    |  4 +++-
 .../james/jmap/routes/JMAPApiRoutesTest.scala      |  4 ++--
 .../james/jmap/routes/SessionRoutesTest.scala      |  2 +-
 .../org/apache/james/jmap/JMAPConfiguration.java   | 24 +++++++++++++++++++---
 .../main/java/org/apache/james/jmap/Version.java   |  4 ++++
 .../java/org/apache/james/jmap/VersionParser.java  |  9 ++++++--
 .../apache/james/jmap/JMAPConfigurationTest.java   |  6 +++---
 .../java/org/apache/james/jmap/JMAPServerTest.java | 12 +++++------
 .../org/apache/james/jmap/VersionParserTest.java   |  2 +-
 src/site/xdoc/server/config-jmap.xml               |  6 ++++++
 11 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/docs/modules/servers/pages/distributed/configure/jmap.adoc b/docs/modules/servers/pages/distributed/configure/jmap.adoc
index 5ab56a9..6650de7 100644
--- a/docs/modules/servers/pages/distributed/configure/jmap.adoc
+++ b/docs/modules/servers/pages/distributed/configure/jmap.adoc
@@ -42,6 +42,12 @@ This should not be the same keystore than the ones used by TLS based protocols.
 | Should simple Email/query be resolved against a Cassandra projection, or should we resolve them against ElasticSearch?
 This enables a higher resilience, but the projection needs to be correctly populated.
 
+| jmap.version.default
+| Optional string. Defaults to draft. Allowed values: draft, rfc-8621.
+| Which version of the JMAP protocol should be served when none supplied in the Accept header.
+Defaults to draft for legacy reasons (avoid breaking changes) but setting the value to
+rfc-8621 allow compatibility with other third party apps.
+
 |===
 
 == Wire tapping
diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java
index 91cf4bf..49613ca 100644
--- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java
+++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/jmap/draft/JMAPModule.java
@@ -133,13 +133,15 @@ public class JMAPModule extends AbstractModule {
 
     @Provides
     @Singleton
-    JMAPConfiguration provideConfiguration(PropertiesProvider propertiesProvider) throws ConfigurationException, IOException {
+    JMAPConfiguration provideConfiguration(PropertiesProvider propertiesProvider) throws ConfigurationException {
         try {
             Configuration configuration = propertiesProvider.getConfiguration("jmap");
             return JMAPConfiguration.builder()
                 .enabled(configuration.getBoolean("enabled", true))
                 .port(Port.of(configuration.getInt("jmap.port", DEFAULT_JMAP_PORT)))
                 .enableEmailQueryView(Optional.ofNullable(configuration.getBoolean("view.email.query.enabled", null)))
+                .defaultVersion(Optional.ofNullable(configuration.getString("jmap.version.default", null))
+                    .map(Version::of))
                 .build();
         } catch (FileNotFoundException e) {
             LOGGER.warn("Could not find JMAP configuration file. JMAP server will not be enabled.");
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
index 8521824..eb64f27 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala
@@ -255,7 +255,7 @@ class JMAPApiRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers {
   var jmapServer: JMAPServer = _
 
   before {
-    val versionParser: VersionParser = new VersionParser(SUPPORTED_VERSIONS)
+    val versionParser: VersionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT)
     jmapServer = new JMAPServer(TEST_CONFIGURATION, ROUTES_HANDLER, versionParser)
     jmapServer.start()
 
@@ -446,7 +446,7 @@ class JMAPApiRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers {
     val apiRoute: JMAPApiRoutes = new JMAPApiRoutes(AUTHENTICATOR, userProvisionner, mailboxesProvisioner, methods)
     val routesHandler: ImmutableSet[JMAPRoutesHandler] = ImmutableSet.of(new JMAPRoutesHandler(Version.RFC8621, apiRoute))
 
-    val versionParser: VersionParser = new VersionParser(SUPPORTED_VERSIONS)
+    val versionParser: VersionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT)
     jmapServer = new JMAPServer(TEST_CONFIGURATION, routesHandler, versionParser)
     jmapServer.start()
 
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala
index 6cab55a..7a27623 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/SessionRoutesTest.scala
@@ -70,7 +70,7 @@ class SessionRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers {
     jmapServer = new JMAPServer(
       TEST_CONFIGURATION,
       Set(new JMAPRoutesHandler(Version.RFC8621, sessionRoutes)).asJava,
-      new VersionParser(Set(Version.RFC8621).asJava))
+      new VersionParser(Set(Version.RFC8621, Version.DRAFT).asJava, JMAPConfiguration.DEFAULT))
     jmapServer.start()
 
     RestAssured.requestSpecification = new RequestSpecBuilder()
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java
index 5b7c729..0eaeb3f 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPConfiguration.java
@@ -35,6 +35,7 @@ public class JMAPConfiguration {
         private Optional<Boolean> enabled = Optional.empty();
         private Optional<Boolean> emailQueryViewEnabled = Optional.empty();
         private Optional<Port> port = Optional.empty();
+        private Optional<Version> defaultVersion = Optional.empty();
 
         private Builder() {
 
@@ -75,6 +76,15 @@ public class JMAPConfiguration {
             return this;
         }
 
+        public Builder defaultVersion(Version defaultVersion) {
+            return defaultVersion(Optional.of(defaultVersion));
+        }
+
+        public Builder defaultVersion(Optional<Version> defaultVersion) {
+            this.defaultVersion = defaultVersion;
+            return this;
+        }
+
         public Builder randomPort() {
             this.port = Optional.empty();
             return this;
@@ -82,20 +92,24 @@ public class JMAPConfiguration {
 
         public JMAPConfiguration build() {
             Preconditions.checkState(enabled.isPresent(), "You should specify if JMAP server should be started");
-            return new JMAPConfiguration(enabled.get(), port, emailQueryViewEnabled.orElse(false));
+            return new JMAPConfiguration(enabled.get(), port, emailQueryViewEnabled.orElse(false),
+                    defaultVersion.orElse(Version.DRAFT));
         }
-
     }
 
+    public static JMAPConfiguration DEFAULT = JMAPConfiguration.builder().enable().build();
+
     private final boolean enabled;
     private final Optional<Port> port;
     private final boolean emailQueryViewEnabled;
+    private final Version defaultVersion;
 
     @VisibleForTesting
-    JMAPConfiguration(boolean enabled, Optional<Port> port, boolean emailQueryViewEnabled) {
+    JMAPConfiguration(boolean enabled, Optional<Port> port, boolean emailQueryViewEnabled, Version defaultVersion) {
         this.enabled = enabled;
         this.port = port;
         this.emailQueryViewEnabled = emailQueryViewEnabled;
+        this.defaultVersion = defaultVersion;
     }
 
     public boolean isEnabled() {
@@ -109,4 +123,8 @@ public class JMAPConfiguration {
     public boolean isEmailQueryViewEnabled() {
         return emailQueryViewEnabled;
     }
+
+    public Version getDefaultVersion() {
+        return defaultVersion;
+    }
 }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/Version.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/Version.java
index 7fe2ef5..5437789 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/Version.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/Version.java
@@ -25,6 +25,10 @@ public class Version {
     public static final Version DRAFT = new Version("draft");
     public static final Version RFC8621 = new Version("rfc-8621");
 
+    public static Version of(String value) {
+        return new Version(value);
+    }
+
     private final String version;
 
     Version(String version) {
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/VersionParser.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/VersionParser.java
index 0368679..1e9c8ac 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/VersionParser.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/VersionParser.java
@@ -39,9 +39,14 @@ public class VersionParser {
     private static final String JMAP_VERSION_HEADER = "jmapVersion";
 
     private final Set<Version> supportedVersions;
+    private final JMAPConfiguration jmapConfiguration;
 
     @Inject
-    public VersionParser(Set<Version> supportedVersions) {
+    public VersionParser(Set<Version> supportedVersions, JMAPConfiguration jmapConfiguration) {
+        this.jmapConfiguration = jmapConfiguration;
+        Preconditions.checkArgument(supportedVersions.contains(jmapConfiguration.getDefaultVersion()),
+                jmapConfiguration + " is not a supported JMAP version");
+
         this.supportedVersions = supportedVersions;
     }
 
@@ -61,7 +66,7 @@ public class VersionParser {
             .map(NameValuePair::getValue)
             .map(this::parse)
             .findFirst()
-            .orElse(Version.DRAFT);
+            .orElse(jmapConfiguration.getDefaultVersion());
     }
 
     private Stream<NameValuePair> asVersion(HttpServerRequest request) {
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java
index 011f774..af5e159 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPConfigurationTest.java
@@ -41,7 +41,7 @@ class JMAPConfigurationTest {
 
     @Test
     void buildShouldWorkWhenRandomPort() {
-        JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(ENABLED, Optional.empty(), ENABLED);
+        JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(ENABLED, Optional.empty(), ENABLED, Version.DRAFT);
 
         JMAPConfiguration jmapConfiguration = JMAPConfiguration.builder()
             .enable()
@@ -53,7 +53,7 @@ class JMAPConfigurationTest {
 
     @Test
     void buildShouldWorkWhenFixedPort() {
-        JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(ENABLED, Optional.of(Port.of(80)), ENABLED);
+        JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(ENABLED, Optional.of(Port.of(80)), ENABLED, Version.DRAFT);
 
         JMAPConfiguration jmapConfiguration = JMAPConfiguration.builder()
             .enable()
@@ -66,7 +66,7 @@ class JMAPConfigurationTest {
 
     @Test
     void buildShouldWorkWhenDisabled() {
-        JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(DISABLED, Optional.empty(), DISABLED);
+        JMAPConfiguration expectedJMAPConfiguration = new JMAPConfiguration(DISABLED, Optional.empty(), DISABLED, Version.DRAFT);
 
         JMAPConfiguration jmapConfiguration = JMAPConfiguration.builder()
             .disable()
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPServerTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPServerTest.java
index 6fd242b..207e12a 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPServerTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/JMAPServerTest.java
@@ -88,7 +88,7 @@ class JMAPServerTest {
 
     @Test
     void serverShouldAnswerWhenStarted() {
-        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS);
+        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT);
         JMAPServer jmapServer = new JMAPServer(TEST_CONFIGURATION, NO_ROUTES_HANDLERS, versionParser);
         jmapServer.start();
 
@@ -107,7 +107,7 @@ class JMAPServerTest {
 
     @Test
     void startShouldNotThrowWhenConfigurationDisabled() {
-        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS);
+        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT);
         JMAPServer jmapServer = new JMAPServer(DISABLED_CONFIGURATION, NO_ROUTES_HANDLERS, versionParser);
 
         assertThatCode(jmapServer::start).doesNotThrowAnyException();
@@ -115,7 +115,7 @@ class JMAPServerTest {
 
     @Test
     void stopShouldNotThrowWhenConfigurationDisabled() {
-        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS);
+        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT);
         JMAPServer jmapServer = new JMAPServer(DISABLED_CONFIGURATION, NO_ROUTES_HANDLERS, versionParser);
         jmapServer.start();
 
@@ -124,7 +124,7 @@ class JMAPServerTest {
 
     @Test
     void getPortShouldThrowWhenServerIsNotStarted() {
-        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS);
+        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT);
         JMAPServer jmapServer = new JMAPServer(TEST_CONFIGURATION, NO_ROUTES_HANDLERS, versionParser);
 
         assertThatThrownBy(jmapServer::getPort)
@@ -133,7 +133,7 @@ class JMAPServerTest {
 
     @Test
     void getPortShouldThrowWhenDisabledConfiguration() {
-        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS);
+        VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT);
         JMAPServer jmapServer = new JMAPServer(DISABLED_CONFIGURATION, NO_ROUTES_HANDLERS, versionParser);
         jmapServer.start();
 
@@ -147,7 +147,7 @@ class JMAPServerTest {
 
         @BeforeEach
         void setUp() {
-            VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS);
+            VersionParser versionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT);
             server = new JMAPServer(TEST_CONFIGURATION, FAKE_ROUTES_HANDLERS, versionParser);
             server.start();
 
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/VersionParserTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/VersionParserTest.java
index 17e1882..5709620 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/VersionParserTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/VersionParserTest.java
@@ -37,7 +37,7 @@ class VersionParserTest {
 
     @BeforeEach
     void setUp() {
-        versionParser = new VersionParser(SUPPORTED_VERSIONS);
+        versionParser = new VersionParser(SUPPORTED_VERSIONS, JMAPConfiguration.DEFAULT);
     }
 
     @Test
diff --git a/src/site/xdoc/server/config-jmap.xml b/src/site/xdoc/server/config-jmap.xml
index ef03111..77c5326 100644
--- a/src/site/xdoc/server/config-jmap.xml
+++ b/src/site/xdoc/server/config-jmap.xml
@@ -69,6 +69,12 @@
                     <dd>Optional boolean. Defaults to false.</dd>
                     <dd>Should simple Email/query be resolved against a Cassandra projection, or should we resolve them against ElasticSearch?
                         This enables a higher resilience, but the projection needs to be correctly populated.</dd>
+
+                    <dt><strong>jmap.version.default</strong></dt>
+                    <dd>Optional string. Defaults to draft. Allowed values: draft, rfc-8621.</dd>
+                    <dd>Which version of the JMAP protocol should be served when none supplied in the Accept header.
+                    Defaults to draft for legacy reasons (avoid breaking changes) but setting the value to
+                    rfc-8621 allow compatibility with other third party apps.</dd>
                 </dl>
 
             </subsection>


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org