JAMES-2368 Rely on ExtendedClassLoader for MailboxListener loading Refining loading strategy with SPI will be done all at once.
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b6fbd098 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b6fbd098 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b6fbd098 Branch: refs/heads/master Commit: b6fbd098167fc83aa53396720b3fce42c450e0a4 Parents: 9eceee1 Author: benwa <btell...@linagora.com> Authored: Wed May 2 11:41:53 2018 +0700 Committer: benwa <btell...@linagora.com> Committed: Fri May 4 13:38:02 2018 +0700 ---------------------------------------------------------------------- pom.xml | 5 ++ server/container/guice/guice-utils/pom.xml | 52 +++++++++++++ .../apache/james/utils/ExtendedClassLoader.java | 79 ++++++++++++++++++++ server/container/guice/mailbox/pom.xml | 4 + .../modules/mailbox/GlobalMailboxListeners.java | 25 +++---- .../mailbox/GlobalMailboxListenersTest.java | 15 +++- server/container/guice/mailet/pom.xml | 4 + .../apache/james/utils/ExtendedClassLoader.java | 79 -------------------- server/container/guice/pom.xml | 1 + 9 files changed, 170 insertions(+), 94 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index bc2ceb0..b7394be 100644 --- a/pom.xml +++ b/pom.xml @@ -1161,6 +1161,11 @@ </dependency> <dependency> <groupId>${project.groupId}</groupId> + <artifactId>james-server-guice-utils</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> <artifactId>james-server-guice-jmap</artifactId> <version>${project.version}</version> </dependency> http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/guice-utils/pom.xml ---------------------------------------------------------------------- diff --git a/server/container/guice/guice-utils/pom.xml b/server/container/guice/guice-utils/pom.xml new file mode 100644 index 0000000..12fea17 --- /dev/null +++ b/server/container/guice/guice-utils/pom.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.james</groupId> + <artifactId>james-server-guice</artifactId> + <version>3.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>james-server-guice-utils</artifactId> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>james-server-filesystem-api</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>james-server-util-java8</artifactId> + </dependency> + <dependency> + <groupId>com.github.fge</groupId> + <artifactId>throwing-lambdas</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + </dependencies> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java ---------------------------------------------------------------------- diff --git a/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java new file mode 100644 index 0000000..5b98666 --- /dev/null +++ b/server/container/guice/guice-utils/src/main/java/org/apache/james/utils/ExtendedClassLoader.java @@ -0,0 +1,79 @@ +/**************************************************************** + * 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.utils; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import org.apache.james.filesystem.api.FileSystem; +import org.apache.james.util.StreamUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.fge.lambdas.Throwing; + +public class ExtendedClassLoader { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExtendedClassLoader.class); + + public static final String EXTENSIONS_JARS_FOLDER_NAME = "extensions-jars/"; + + private final URLClassLoader urlClassLoader; + + @Inject + public ExtendedClassLoader(FileSystem fileSystem) { + this.urlClassLoader = new URLClassLoader(retrieveExtensionsUrls(fileSystem), getClass().getClassLoader()); + } + + private URL[] retrieveExtensionsUrls(FileSystem fileSystem) { + try { + File file = fileSystem.getFile("file://" + EXTENSIONS_JARS_FOLDER_NAME); + return recursiveExpand(file) + .toArray(URL[]::new); + } catch (IOException e) { + LOGGER.info("No " + EXTENSIONS_JARS_FOLDER_NAME + " folder."); + return new URL[]{}; + } + } + + private Stream<URL> recursiveExpand(File file) { + return StreamUtils.ofNullable(file.listFiles()) + .flatMap(Throwing.function(this::expandFile).sneakyThrow()); + } + + private Stream<URL> expandFile(File file) throws MalformedURLException { + if (file.isDirectory()) { + return recursiveExpand(file); + } + LOGGER.info("Loading custom classpath resource {}", file.getAbsolutePath()); + return Stream.of(file.toURI().toURL()); + } + + @SuppressWarnings("unchecked") + public <T> Class<T> locateClass(String className) throws ClassNotFoundException { + return (Class<T>) urlClassLoader.loadClass(className); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/mailbox/pom.xml ---------------------------------------------------------------------- diff --git a/server/container/guice/mailbox/pom.xml b/server/container/guice/mailbox/pom.xml index 1e8415e..77c4183 100644 --- a/server/container/guice/mailbox/pom.xml +++ b/server/container/guice/mailbox/pom.xml @@ -45,6 +45,10 @@ <artifactId>james-server-guice-configuration</artifactId> </dependency> <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>james-server-guice-utils</artifactId> + </dependency> + <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> </dependency> http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/GlobalMailboxListeners.java ---------------------------------------------------------------------- diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/GlobalMailboxListeners.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/GlobalMailboxListeners.java index 4028383..1f51d65 100644 --- a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/GlobalMailboxListeners.java +++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/GlobalMailboxListeners.java @@ -20,12 +20,12 @@ package org.apache.james.modules.mailbox; import java.util.List; -import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.james.lifecycle.api.Configurable; import org.apache.james.mailbox.MailboxListener; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.store.event.MailboxListenerRegistry; +import org.apache.james.utils.ExtendedClassLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,19 +42,22 @@ public class GlobalMailboxListeners implements Configurable { private final Injector injector; private final MailboxListenerRegistry registry; + private final ExtendedClassLoader classLoader; @Inject - public GlobalMailboxListeners(Injector injector, MailboxListenerRegistry registry) { + public GlobalMailboxListeners(Injector injector, MailboxListenerRegistry registry, ExtendedClassLoader classLoader) { this.injector = injector; this.registry = registry; + this.classLoader = classLoader; } @Override - public void configure(HierarchicalConfiguration configuration) throws ConfigurationException { + public void configure(HierarchicalConfiguration configuration) { LOGGER.info("Loading mailbox listeners"); + List<HierarchicalConfiguration> listenersConfiguration = configuration.configurationsAt("listener"); - listenersConfiguration.stream() - .forEach(listenerConfiguration -> configureListener(listenerConfiguration)); + + listenersConfiguration.forEach(this::configureListener); } @VisibleForTesting void configureListener(HierarchicalConfiguration configuration) { @@ -62,16 +65,12 @@ public class GlobalMailboxListeners implements Configurable { Preconditions.checkState(!Strings.isNullOrEmpty(listenerClass), "class name is mandatory"); try { LOGGER.info("Loading mailbox listener {}", listenerClass); - registry.addGlobalListener(injector.getInstance(loadMailboxListener(listenerClass))); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | MailboxException e) { + Class<MailboxListener> clazz = classLoader.locateClass(listenerClass); + MailboxListener listener = injector.getInstance(clazz); + registry.addGlobalListener(listener); + } catch (ClassNotFoundException | MailboxException e) { LOGGER.error("Error while loading global listener {}", listenerClass, e); Throwables.propagate(e); } } - - @SuppressWarnings("unchecked") - private Class<MailboxListener> loadMailboxListener(String listenerClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass(listenerClass); - return (Class<MailboxListener>) clazz; - } } http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/mailbox/src/test/java/org/apache/james/modules/mailbox/GlobalMailboxListenersTest.java ---------------------------------------------------------------------- diff --git a/server/container/guice/mailbox/src/test/java/org/apache/james/modules/mailbox/GlobalMailboxListenersTest.java b/server/container/guice/mailbox/src/test/java/org/apache/james/modules/mailbox/GlobalMailboxListenersTest.java index 4076aac..40cd58a 100644 --- a/server/container/guice/mailbox/src/test/java/org/apache/james/modules/mailbox/GlobalMailboxListenersTest.java +++ b/server/container/guice/mailbox/src/test/java/org/apache/james/modules/mailbox/GlobalMailboxListenersTest.java @@ -20,13 +20,19 @@ package org.apache.james.modules.mailbox; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; import java.nio.charset.StandardCharsets; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.DefaultConfigurationBuilder; +import org.apache.james.filesystem.api.FileSystem; import org.apache.james.mailbox.store.event.MailboxListenerRegistry; +import org.apache.james.utils.ExtendedClassLoader; import org.junit.Before; import org.junit.Test; @@ -38,9 +44,14 @@ public class GlobalMailboxListenersTest { private GlobalMailboxListeners testee; @Before - public void setup() { + public void setup() throws Exception { + FileSystem fileSystem = mock(FileSystem.class); + when(fileSystem.getFile(anyString())) + .thenThrow(new FileNotFoundException()); + registry = new MailboxListenerRegistry(); - testee = new GlobalMailboxListeners(Guice.createInjector(), registry); + testee = new GlobalMailboxListeners(Guice.createInjector(), registry, + new ExtendedClassLoader(fileSystem)); } @Test http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/mailet/pom.xml ---------------------------------------------------------------------- diff --git a/server/container/guice/mailet/pom.xml b/server/container/guice/mailet/pom.xml index 25cddf2..60daf41 100644 --- a/server/container/guice/mailet/pom.xml +++ b/server/container/guice/mailet/pom.xml @@ -48,6 +48,10 @@ </dependency> <dependency> <groupId>${project.groupId}</groupId> + <artifactId>james-server-guice-utils</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> <artifactId>james-server-mailetcontainer-api</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/mailet/src/main/java/org/apache/james/utils/ExtendedClassLoader.java ---------------------------------------------------------------------- diff --git a/server/container/guice/mailet/src/main/java/org/apache/james/utils/ExtendedClassLoader.java b/server/container/guice/mailet/src/main/java/org/apache/james/utils/ExtendedClassLoader.java deleted file mode 100644 index 5b98666..0000000 --- a/server/container/guice/mailet/src/main/java/org/apache/james/utils/ExtendedClassLoader.java +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************** - * 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.utils; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.stream.Stream; - -import javax.inject.Inject; - -import org.apache.james.filesystem.api.FileSystem; -import org.apache.james.util.StreamUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.github.fge.lambdas.Throwing; - -public class ExtendedClassLoader { - - private static final Logger LOGGER = LoggerFactory.getLogger(ExtendedClassLoader.class); - - public static final String EXTENSIONS_JARS_FOLDER_NAME = "extensions-jars/"; - - private final URLClassLoader urlClassLoader; - - @Inject - public ExtendedClassLoader(FileSystem fileSystem) { - this.urlClassLoader = new URLClassLoader(retrieveExtensionsUrls(fileSystem), getClass().getClassLoader()); - } - - private URL[] retrieveExtensionsUrls(FileSystem fileSystem) { - try { - File file = fileSystem.getFile("file://" + EXTENSIONS_JARS_FOLDER_NAME); - return recursiveExpand(file) - .toArray(URL[]::new); - } catch (IOException e) { - LOGGER.info("No " + EXTENSIONS_JARS_FOLDER_NAME + " folder."); - return new URL[]{}; - } - } - - private Stream<URL> recursiveExpand(File file) { - return StreamUtils.ofNullable(file.listFiles()) - .flatMap(Throwing.function(this::expandFile).sneakyThrow()); - } - - private Stream<URL> expandFile(File file) throws MalformedURLException { - if (file.isDirectory()) { - return recursiveExpand(file); - } - LOGGER.info("Loading custom classpath resource {}", file.getAbsolutePath()); - return Stream.of(file.toURI().toURL()); - } - - @SuppressWarnings("unchecked") - public <T> Class<T> locateClass(String className) throws ClassNotFoundException { - return (Class<T>) urlClassLoader.loadClass(className); - } -} http://git-wip-us.apache.org/repos/asf/james-project/blob/b6fbd098/server/container/guice/pom.xml ---------------------------------------------------------------------- diff --git a/server/container/guice/pom.xml b/server/container/guice/pom.xml index 346c5cf..ab62bb7 100644 --- a/server/container/guice/pom.xml +++ b/server/container/guice/pom.xml @@ -39,6 +39,7 @@ <module>custom-mailets</module> <module>es-metric-reporter</module> <module>guice-common</module> + <module>guice-utils</module> <module>jmx</module> <module>jpa-common-guice</module> <module>jpa-guice</module> --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org