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 2022/12/07 04:40:36 UTC

[james-project] branch 3.7.x updated (3b668561af -> c3149be514)

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

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


    from 3b668561af JAMES-3860 Rely on Files.createTempFile (#1325)
     new 61cf9618b0 [FIX] ToSenderFolder needs to call .block on mono (#1317)
     new a0e5fdcbf5 JAMES-3859 configurable -> startable
     new c3149be514 JAMES-3859 start sequence ordering should take provisions into account

The 3 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.


Summary of changes:
 .../java/org/apache/james/StartSequenceTest.java   | 189 +++++++++++++++++++++
 .../org/apache/james/modules/StartablesModule.java |  26 +++
 .../james/utils/InitializationOperations.java      |  25 +--
 .../java/org/apache/james/utils/Startables.java    |   1 -
 .../modules/InitializationOperationsTest.java      |  56 ++----
 .../james/utils/InitializationOperation.java       |   8 +
 .../james/utils/InitilizationOperationBuilder.java |  35 +++-
 .../james/transport/mailets/ToSenderFolder.java    |   2 +-
 8 files changed, 283 insertions(+), 59 deletions(-)
 create mode 100644 server/apps/memory-app/src/test/java/org/apache/james/StartSequenceTest.java


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


[james-project] 03/03: JAMES-3859 start sequence ordering should take provisions into account

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

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

commit c3149be51427b44b44720823df8027893f11fb8f
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Nov 18 12:07:35 2022 +0700

    JAMES-3859 start sequence ordering should take provisions into account
    
    Provider listener order needs to be corrected, for this we add the notion of requirements that is
    inferred by the class constructor parameters.
---
 .../java/org/apache/james/StartSequenceTest.java   | 189 +++++++++++++++++++++
 .../org/apache/james/modules/StartablesModule.java |  26 +++
 .../james/utils/InitializationOperations.java      |  13 +-
 .../java/org/apache/james/utils/Startables.java    |   1 -
 .../modules/InitializationOperationsTest.java      |  56 ++----
 .../james/utils/InitializationOperation.java       |   8 +
 .../james/utils/InitilizationOperationBuilder.java |  35 +++-
 7 files changed, 276 insertions(+), 52 deletions(-)

diff --git a/server/apps/memory-app/src/test/java/org/apache/james/StartSequenceTest.java b/server/apps/memory-app/src/test/java/org/apache/james/StartSequenceTest.java
new file mode 100644
index 0000000000..c4d061a5b4
--- /dev/null
+++ b/server/apps/memory-app/src/test/java/org/apache/james/StartSequenceTest.java
@@ -0,0 +1,189 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james;
+
+import static org.apache.james.data.UsersRepositoryModuleChooser.Implementation.DEFAULT;
+import static org.assertj.core.api.Assertions.assertThatCode;
+
+import org.apache.james.lifecycle.api.Startable;
+import org.apache.james.modules.TestJMAPServerModule;
+import org.apache.james.utils.InitializationOperation;
+import org.apache.james.utils.InitilizationOperationBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Provides;
+import com.google.inject.Scopes;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.ProvidesIntoSet;
+
+class StartSequenceTest {
+    static class A implements Startable {
+        public boolean started = false;
+
+        public void start() {
+            started = true;
+        }
+    }
+    static class D implements Startable {
+        public boolean started = false;
+
+        public void start() {
+            started = true;
+        }
+    }
+    static class F implements Startable {
+        public boolean started = false;
+
+        public void start() {
+            started = true;
+        }
+    }
+
+    static class B implements Startable {
+        private final A a;
+
+        @Inject
+        B(A a) {
+            this.a = a;
+        }
+
+        public void start() {
+            assert a.started;
+        }
+    }
+
+    static class C implements Startable {
+        private final D d;
+
+        @Inject
+        C(D d) {
+            this.d = d;
+        }
+
+        public void start() {
+            assert d.started;
+        }
+    }
+
+    static class E implements Startable {
+        private final F f;
+        private final A a;
+
+        @Inject
+        E(F f, A a) {
+            this.f = f;
+            this.a = a;
+        }
+
+        public void start() {
+            assert f.started;
+            assert a.started;
+        }
+    }
+
+    static class ConfigurableTestModule extends AbstractModule {
+
+        @Override
+        protected void configure() {
+            bind(B.class).in(Scopes.SINGLETON);
+            bind(C.class).in(Scopes.SINGLETON);
+            bind(D.class).in(Scopes.SINGLETON);
+            bind(F.class).in(Scopes.SINGLETON);
+        }
+
+        @Provides
+        @Singleton
+        E e(F f, A a) {
+            return new E(f, a);
+        }
+
+        @Provides
+        @Singleton
+        A a() {
+            return new A();
+        }
+
+        @ProvidesIntoSet
+        InitializationOperation initA(A a) {
+            return InitilizationOperationBuilder
+                .forClass(A.class)
+                .init(a::start);
+        }
+
+        @ProvidesIntoSet
+        InitializationOperation initB(B b) {
+            return InitilizationOperationBuilder
+                .forClass(B.class)
+                .init(b::start);
+        }
+
+        @ProvidesIntoSet
+        InitializationOperation initC(C c) {
+            return InitilizationOperationBuilder
+                .forClass(C.class)
+                .init(c::start);
+        }
+
+        @ProvidesIntoSet
+        InitializationOperation initD(D d) {
+            return InitilizationOperationBuilder
+                .forClass(D.class)
+                .init(d::start);
+        }
+
+        @ProvidesIntoSet
+        InitializationOperation initD(E e) {
+            return InitilizationOperationBuilder
+                .forClass(E.class)
+                .init(e::start)
+                .requires(ImmutableList.of(A.class, F.class));
+        }
+
+        @ProvidesIntoSet
+        InitializationOperation initD(F f) {
+            return InitilizationOperationBuilder
+                .forClass(F.class)
+                .init(f::start);
+        }
+    }
+
+    @RegisterExtension
+    static JamesServerExtension jamesServerExtension = new JamesServerBuilder<MemoryJamesConfiguration>(tmpDir ->
+        MemoryJamesConfiguration.builder()
+            .workingDirectory(tmpDir)
+            .configurationFromClasspath()
+            .usersRepository(DEFAULT)
+            .build())
+        .server(configuration -> MemoryJamesServerMain.createServer(configuration)
+            .overrideWith(new TestJMAPServerModule())
+            .overrideWith(new ConfigurableTestModule()))
+        .lifeCycle(JamesServerExtension.Lifecycle.PER_CLASS)
+        .disableAutoStart()
+        .build();
+
+    @Test
+    void providesShouldBeTakenIntoAccountByTheStartSequence(GuiceJamesServer server) {
+        assertThatCode(server::start).doesNotThrowAnyException();
+    }
+}
diff --git a/server/container/guice/common/src/main/java/org/apache/james/modules/StartablesModule.java b/server/container/guice/common/src/main/java/org/apache/james/modules/StartablesModule.java
index 146cac7d83..0c32b788c2 100644
--- a/server/container/guice/common/src/main/java/org/apache/james/modules/StartablesModule.java
+++ b/server/container/guice/common/src/main/java/org/apache/james/modules/StartablesModule.java
@@ -23,13 +23,17 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.io.Serializable;
 
+import org.apache.commons.lang3.NotImplementedException;
 import org.apache.james.lifecycle.api.Startable;
 import org.apache.james.utils.Startables;
 
 import com.google.inject.AbstractModule;
+import com.google.inject.Binding;
 import com.google.inject.TypeLiteral;
 import com.google.inject.matcher.AbstractMatcher;
+import com.google.inject.matcher.Matcher;
 import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.ProvisionListener;
 import com.google.inject.spi.TypeEncounter;
 
 public class StartablesModule extends AbstractModule {
@@ -45,6 +49,28 @@ public class StartablesModule extends AbstractModule {
         bind(Startables.class).toInstance(startables);
 
         bindListener(new SubclassesOf(Startable.class), this::hear);
+        bindListener(new Matcher<Binding<?>>() {
+            @Override
+            public boolean matches(Binding<?> binding) {
+                return Startable.class.isAssignableFrom(binding.getKey().getTypeLiteral().getRawType());
+            }
+
+            @Override
+            public Matcher<Binding<?>> and(Matcher<? super Binding<?>> matcher) {
+                throw new NotImplementedException();
+            }
+
+            @Override
+            public Matcher<Binding<?>> or(Matcher<? super Binding<?>> matcher) {
+                throw new NotImplementedException();
+            }
+        }, new ProvisionListener() {
+            @Override
+            public <T> void onProvision(ProvisionInvocation<T> invokation) {
+                startables.add(invokation.getBinding().getKey().getTypeLiteral().getRawType().asSubclass(Startable.class));
+            }
+        });
+
     }
 
     private <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
diff --git a/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java b/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java
index f2388d13cd..61adb875d3 100644
--- a/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java
+++ b/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java
@@ -23,8 +23,6 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.apache.james.lifecycle.api.Startable;
-
 import com.github.fge.lambdas.Throwing;
 import com.google.inject.Inject;
 
@@ -53,9 +51,16 @@ public class InitializationOperations {
             .collect(Collectors.toSet());
     }
 
-    private Stream<InitializationOperation> configurationPerformerFor(Class<? extends Startable> startable) {
+    /**
+     * Locate configuration performer for this class.
+     *
+     * We reorder the performer so that one class requirements are always satisfied (startable order is wrong for
+     * provisioned instances...)
+     */
+    private Stream<InitializationOperation> configurationPerformerFor(Class<?> startable) {
         return initializationOperations.stream()
-                .filter(x -> x.forClass().equals(startable));
+                .filter(x -> startable.isAssignableFrom(x.forClass()))
+                .flatMap(x -> Stream.concat(x.requires().stream().flatMap(this::configurationPerformerFor), Stream.of(x)));
     }
 
     private void processOthers(Set<InitializationOperation> processed) {
diff --git a/server/container/guice/common/src/main/java/org/apache/james/utils/Startables.java b/server/container/guice/common/src/main/java/org/apache/james/utils/Startables.java
index b2a16d5892..ef8bee20c6 100644
--- a/server/container/guice/common/src/main/java/org/apache/james/utils/Startables.java
+++ b/server/container/guice/common/src/main/java/org/apache/james/utils/Startables.java
@@ -27,7 +27,6 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 
 public class Startables {
-
     private final Set<Class<? extends Startable>> startables;
 
     public Startables() {
diff --git a/server/container/guice/common/src/test/java/org/apache/james/modules/InitializationOperationsTest.java b/server/container/guice/common/src/test/java/org/apache/james/modules/InitializationOperationsTest.java
index f5e1bee7d7..73c5a7c80d 100644
--- a/server/container/guice/common/src/test/java/org/apache/james/modules/InitializationOperationsTest.java
+++ b/server/container/guice/common/src/test/java/org/apache/james/modules/InitializationOperationsTest.java
@@ -30,12 +30,14 @@ import org.apache.james.lifecycle.api.Configurable;
 import org.apache.james.lifecycle.api.Startable;
 import org.apache.james.utils.InitializationOperation;
 import org.apache.james.utils.InitializationOperations;
+import org.apache.james.utils.InitilizationOperationBuilder;
 import org.junit.jupiter.api.Test;
 
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.Scopes;
 import com.google.inject.multibindings.Multibinder;
+import com.google.inject.multibindings.ProvidesIntoSet;
 
 class InitializationOperationsTest {
     @Test
@@ -56,55 +58,21 @@ class InitializationOperationsTest {
             bind(B.class).in(Scopes.SINGLETON);
             bind(A.class).in(Scopes.SINGLETON);
             bind(C.class).in(Scopes.SINGLETON);
-    
-            Multibinder.newSetBinder(binder(), InitializationOperation.class).addBinding().to(BInitializationOperation.class);
-            Multibinder.newSetBinder(binder(), InitializationOperation.class).addBinding().to(AInitializationOperation.class);
         }
-    }
-
-    private static class AInitializationOperation implements InitializationOperation {
-        private final A a;
 
-        @Inject
-        private AInitializationOperation(A a) {
-            this.a = a;
+        @ProvidesIntoSet
+        InitializationOperation initA(A a) {
+            return InitilizationOperationBuilder
+                .forClass(A.class)
+                .init(() -> a.configure(null));
         }
 
-        @Override
-        public void initModule() {
-            try {
-                a.configure(null);
-            } catch (ConfigurationException e) {
-                throw new RuntimeException(e);
-            }
-        }
 
-        @Override
-        public Class<? extends Startable> forClass() {
-            return A.class;
-        }
-    }
-
-    private static class BInitializationOperation implements InitializationOperation {
-        private final B b;
-
-        @Inject
-        private BInitializationOperation(B b) {
-            this.b = b;
-        }
-
-        @Override
-        public void initModule() {
-            try {
-                b.configure(null);
-            } catch (ConfigurationException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        @Override
-        public Class<? extends Startable> forClass() {
-            return B.class;
+        @ProvidesIntoSet
+        InitializationOperation initB(B b) {
+            return InitilizationOperationBuilder
+                .forClass(B.class)
+                .init(() -> b.configure(null));
         }
     }
 
diff --git a/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitializationOperation.java b/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitializationOperation.java
index d43f7f0d82..5741755590 100644
--- a/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitializationOperation.java
+++ b/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitializationOperation.java
@@ -19,8 +19,12 @@
 
 package org.apache.james.utils;
 
+import java.util.List;
+
 import org.apache.james.lifecycle.api.Startable;
 
+import com.google.common.collect.ImmutableList;
+
 public interface InitializationOperation {
 
     void initModule() throws Exception;
@@ -33,4 +37,8 @@ public interface InitializationOperation {
      * @return the Class that this object will initialize.
      */
     Class<? extends Startable> forClass();
+
+    default List<Class<?>> requires() {
+        return ImmutableList.of();
+    }
 }
diff --git a/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitilizationOperationBuilder.java b/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitilizationOperationBuilder.java
index 8bdf04cc71..a13e4fa45c 100644
--- a/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitilizationOperationBuilder.java
+++ b/server/container/guice/configuration/src/main/java/org/apache/james/utils/InitilizationOperationBuilder.java
@@ -19,8 +19,15 @@
 
 package org.apache.james.utils;
 
+import java.util.Arrays;
+import java.util.List;
+
+import javax.inject.Inject;
+
 import org.apache.james.lifecycle.api.Startable;
 
+import com.google.common.collect.ImmutableList;
+
 public class InitilizationOperationBuilder {
 
     @FunctionalInterface
@@ -30,21 +37,33 @@ public class InitilizationOperationBuilder {
 
     @FunctionalInterface
     public interface RequireInit {
-        InitializationOperation init(Init init);
+        PrivateImpl init(Init init);
     }
 
     public static RequireInit forClass(Class<? extends Startable> type) {
         return init -> new PrivateImpl(init, type);
     }
 
-    private static class PrivateImpl implements InitializationOperation {
-
+    public static class PrivateImpl implements InitializationOperation {
         private final Init init;
         private final Class<? extends Startable> type;
+        private List<Class<?>> requires;
 
         private PrivateImpl(Init init, Class<? extends Startable> type) {
             this.init = init;
             this.type = type;
+            /*
+            Class requirements are by default infered from the parameters of the first @Inject annotated constructor.
+
+            If it does not exist, use the first constructor (case in a @Provides).
+             */
+            this.requires = Arrays.stream(type.getDeclaredConstructors())
+                .filter(c -> c.isAnnotationPresent(Inject.class))
+                .findFirst()
+                .or(() -> Arrays.stream(type.getDeclaredConstructors()).findFirst())
+                .stream()
+                .flatMap(c -> Arrays.stream(c.getParameterTypes()))
+                .collect(ImmutableList.toImmutableList());
         }
 
         @Override
@@ -56,5 +75,15 @@ public class InitilizationOperationBuilder {
         public Class<? extends Startable> forClass() {
             return type;
         }
+
+        public PrivateImpl requires(List<Class<?>> requires) {
+            this.requires = requires;
+            return this;
+        }
+
+        @Override
+        public List<Class<?>> requires() {
+            return requires;
+        }
     }
 }


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


[james-project] 02/03: JAMES-3859 configurable -> startable

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

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

commit a0e5fdcbf538262e981b1c375e1839668f732ab7
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Nov 18 12:05:39 2022 +0700

    JAMES-3859 configurable -> startable
---
 .../org/apache/james/utils/InitializationOperations.java | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java b/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java
index fde491545f..f2388d13cd 100644
--- a/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java
+++ b/server/container/guice/common/src/main/java/org/apache/james/utils/InitializationOperations.java
@@ -31,31 +31,31 @@ import com.google.inject.Inject;
 public class InitializationOperations {
 
     private final Set<InitializationOperation> initializationOperations;
-    private final Startables configurables;
+    private final Startables startables;
 
     @Inject
-    public InitializationOperations(Set<InitializationOperation> initializationOperations, Startables configurables) {
+    public InitializationOperations(Set<InitializationOperation> initializationOperations, Startables startables) {
         this.initializationOperations = initializationOperations;
-        this.configurables = configurables;
+        this.startables = startables;
     }
 
     public void initModules() {
-        Set<InitializationOperation> processed = processConfigurables();
+        Set<InitializationOperation> processed = processStartables();
         
         processOthers(processed);
     }
 
-    private Set<InitializationOperation> processConfigurables() {
-        return configurables.get().stream()
+    private Set<InitializationOperation> processStartables() {
+        return startables.get().stream()
             .flatMap(this::configurationPerformerFor)
             .distinct()
             .peek(Throwing.consumer(InitializationOperation::initModule).sneakyThrow())
             .collect(Collectors.toSet());
     }
 
-    private Stream<InitializationOperation> configurationPerformerFor(Class<? extends Startable> configurable) {
+    private Stream<InitializationOperation> configurationPerformerFor(Class<? extends Startable> startable) {
         return initializationOperations.stream()
-                .filter(x -> x.forClass().equals(configurable));
+                .filter(x -> x.forClass().equals(startable));
     }
 
     private void processOthers(Set<InitializationOperation> processed) {


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


[james-project] 01/03: [FIX] ToSenderFolder needs to call .block on mono (#1317)

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

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

commit 61cf9618b0f91d476745b2431397320356a946f0
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Fri Nov 18 21:22:17 2022 +0700

    [FIX] ToSenderFolder needs to call .block on mono (#1317)
---
 .../main/java/org/apache/james/transport/mailets/ToSenderFolder.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
index bdd55a856d..311ba38768 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
@@ -84,7 +84,7 @@ public class ToSenderFolder extends GenericMailet {
             MailAddress sender = mail.getMaybeSender().get();
             Username username = retrieveUser(sender);
 
-            mailboxAppender.append(mail.getMessage(), username, folder);
+            mailboxAppender.append(mail.getMessage(), username, folder).block();
 
             LOGGER.error("Local delivery with ToSenderFolder mailet for mail {} with sender {} in folder {}", mail.getName(), sender, folder);
         }


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