Skip to content

Commit

Permalink
JAMES-1695 support several filters in Jetty Configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
mbaechler authored and aduprat committed Mar 1, 2016
1 parent e57e8cc commit 39b1950
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 23 deletions.
Expand Up @@ -25,6 +25,7 @@
import javax.servlet.Servlet;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Range;

Expand All @@ -43,7 +44,7 @@ public static class Builder {
private static final Range<Integer> VALID_PORT_RANGE = Range.closed(1, 65535);

private final ImmutableMap.Builder<String, Object> mappings;
private final ImmutableMap.Builder<String, Object> filters;
private final ImmutableListMultimap.Builder<String, Object> filters;
private Optional<Integer> port;

public class ServletBinder {
Expand Down Expand Up @@ -73,22 +74,31 @@ private FilterBinder(String filterUrl) {
this.filterUrl = filterUrl;
}

public Configuration.Builder with(Filter filter) {
public FilterBinder with(Filter filter) {
Preconditions.checkNotNull(filter);
filters.put(filterUrl, filter);
return Builder.this;
return this;
}

public FilterBinder and(Filter filter) {
return with(filter);
}

public Configuration.Builder with(Class<? extends Filter> filterClass) {
public FilterBinder with(Class<? extends Filter> filterClass) {
Preconditions.checkNotNull(filterClass);
filters.put(filterUrl, filterClass);
return this;
}

public Configuration.Builder only() {
return Builder.this;
}

}

private Builder() {
mappings = ImmutableMap.builder();
filters = ImmutableMap.builder();
filters = ImmutableListMultimap.builder();
port = Optional.empty();
}

Expand Down Expand Up @@ -121,10 +131,10 @@ public Configuration build() {
}

private final ImmutableMap<String, Object> mappings;
private final ImmutableMap<String, Object> filters;
private final ImmutableListMultimap<String, Object> filters;
private final Optional<Integer> port;

private Configuration(ImmutableMap<String, Object> mappings, ImmutableMap<String, Object> filters, Optional<Integer> port) {
private Configuration(ImmutableMap<String, Object> mappings, ImmutableListMultimap<String, Object> filters, Optional<Integer> port) {
this.mappings = mappings;
this.filters = filters;
this.port = port;
Expand All @@ -134,7 +144,7 @@ public ImmutableMap<String, Object> getMappings() {
return mappings;
}

public ImmutableMap<String, Object> getFilters() {
public ImmutableListMultimap<String, Object> getFilters() {
return filters;
}

Expand Down
Expand Up @@ -20,6 +20,7 @@
package org.apache.james.http.jetty;

import java.io.Closeable;
import java.util.Collection;
import java.util.EnumSet;
import java.util.function.BiConsumer;

Expand All @@ -35,6 +36,7 @@

import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimaps;

public class JettyHttpServer implements Closeable {

Expand All @@ -61,10 +63,14 @@ private ServerConnector buildServerConnector(Configuration configuration) {

private ServletHandler buildServletHandler(Configuration configuration) {
ServletHandler servletHandler = new ServletHandler();

BiConsumer<String, ServletHolder> addServletMapping = (path, servletHolder) -> servletHandler.addServletWithMapping(servletHolder, path);
BiConsumer<String, FilterHolder> addFilterMapping = (path, filterHolder) -> servletHandler.addFilterWithMapping(filterHolder, path, EnumSet.of(DispatcherType.REQUEST));
BiConsumer<String, Collection<FilterHolder>> addFilterMappings =
(path, filterHolders) -> filterHolders.stream().forEachOrdered(
filterHolder -> servletHandler.addFilterWithMapping(filterHolder, path, EnumSet.of(DispatcherType.REQUEST)));

Maps.transformEntries(configuration.getMappings(), this::toServletHolder).forEach(addServletMapping);
Maps.transformEntries(configuration.getFilters(), this::toFilterHolder).forEach(addFilterMapping);
Multimaps.transformEntries(configuration.getFilters(), this::toFilterHolder).asMap().forEach(addFilterMappings);
return servletHandler;
}

Expand Down
Expand Up @@ -26,6 +26,8 @@

import org.junit.Test;

import com.google.common.collect.ImmutableList;

public class ConfigurationTest {

@Test
Expand All @@ -39,6 +41,7 @@ public void defaultConfigurationDefinition() {
public void shouldAllowWorkingDefinition() {
Bad400 bad400 = new Bad400();
SpyFilter spyFilter = new SpyFilter();
LambdaFilter anotherFilter = (req, resp, chain) -> chain.doFilter(req, resp);
Configuration testee = Configuration
.builder()
.port(2000)
Expand All @@ -48,18 +51,19 @@ public void shouldAllowWorkingDefinition() {
.with(bad400)
.filter("/123")
.with(CoolFilter.class)
.and(anotherFilter).only()
.filter("/456")
.with(spyFilter)
.with(spyFilter).only()
.build();
assertThat(testee.getPort()).isPresent().contains(2000);
assertThat(testee.getMappings())
.hasSize(2)
.containsEntry("/abc", Ok200.class)
.containsEntry("/def", bad400);
assertThat(testee.getFilters())
assertThat(testee.getFilters().asMap())
.hasSize(2)
.containsEntry("/123", CoolFilter.class)
.containsEntry("/456", spyFilter);
.containsEntry("/123", ImmutableList.of(CoolFilter.class, anotherFilter))
.containsEntry("/456", ImmutableList.of(spyFilter));
}

@Test
Expand Down
Expand Up @@ -57,7 +57,7 @@ public void shouldCreateServersAsDescribedInXmlConfiguration() throws Exception
.serve("/foo")
.with(Ok200.class)
.filter("/*")
.with(SpyFilter.class)
.with(SpyFilter.class).only()
.build());
}

Expand Down
Expand Up @@ -192,7 +192,7 @@ public void shouldCallFilterWhenConfiguredByClass() throws Exception {
.serve("/foo")
.with(Ok200.class)
.filter("/foo")
.with(OverrideFilter.class)
.with(OverrideFilter.class).only()
.build())
.start();

Expand All @@ -214,7 +214,7 @@ public void shouldLetConfiguredServletHandleIncomingRequestAfterFilterHandling()
.serve("/foo")
.with(Ok200.class)
.filter("/foo")
.with(spyFilter)
.with(spyFilter).only()
.build())
.start();

Expand Down
@@ -0,0 +1,35 @@
/****************************************************************
* 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.http.jetty;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;

@FunctionalInterface
public interface LambdaFilter extends Filter {

@Override
default void init(FilterConfig filterConfig) throws ServletException {
}

@Override
default void destroy() {
}
}
Expand Up @@ -30,6 +30,7 @@
import org.apache.james.http.jetty.Configuration;
import org.apache.james.http.jetty.Configuration.Builder;
import org.apache.james.http.jetty.JettyHttpServer;
import org.apache.james.http.jetty.LambdaFilter;
import org.apache.james.lifecycle.api.Configurable;

import com.google.common.base.Throwables;
Expand All @@ -45,14 +46,20 @@ private JMAPServer(PortConfiguration portConfiguration,
AuthenticationServlet authenticationServlet, JMAPServlet jmapServlet,
AuthenticationFilter authenticationFilter) {

LambdaFilter provisionUserFilter = (req, resp, chain) -> chain.doFilter(req, resp);
server = JettyHttpServer.create(
configurationBuilderFor(portConfiguration)
.serve("/authentication").with(authenticationServlet)
.filter("/authentication").with(new AllowAllCrossOriginRequests(
bypass(authenticationFilter).on("POST").and("OPTIONS").only()))
.serve("/jmap").with(jmapServlet)
.filter("/jmap").with(new AllowAllCrossOriginRequests(
bypass(authenticationFilter).on("OPTIONS").only()))
.serve("/authentication")
.with(authenticationServlet)
.filter("/authentication")
.with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("POST").and("OPTIONS").only()))
.only()
.serve("/jmap")
.with(jmapServlet)
.filter("/jmap")
.with(new AllowAllCrossOriginRequests(bypass(authenticationFilter).on("OPTIONS").only()))
.and(provisionUserFilter)
.only()
.build());
}

Expand Down

0 comments on commit 39b1950

Please sign in to comment.