reta closed pull request #329: CXF-7501: Cannot inject field in ContainerRequestFilter (and generally, into any providers registered using FeatureContext) URL: https://github.com/apache/cxf/pull/329
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/CdiServerConfigurableFactory.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/CdiServerConfigurableFactory.java new file mode 100644 index 00000000000..15d4643d847 --- /dev/null +++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/CdiServerConfigurableFactory.java @@ -0,0 +1,91 @@ +/** + * 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.cxf.cdi; + +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.AnnotatedType; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanAttributes; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.InjectionTargetFactory; +import javax.ws.rs.RuntimeType; +import javax.ws.rs.core.Configurable; +import javax.ws.rs.core.FeatureContext; + +import org.apache.cxf.cdi.event.DisposableCreationalContext; +import org.apache.cxf.jaxrs.impl.ConfigurableImpl; +import org.apache.cxf.jaxrs.impl.ConfigurableImpl.Instantiator; +import org.apache.cxf.jaxrs.provider.ServerConfigurableFactory; + +/** + * Creates the instance of Configurable<?> suitable for CDI-managed runtime. + */ +public class CdiServerConfigurableFactory implements ServerConfigurableFactory { + private final BeanManager beanManager; + + CdiServerConfigurableFactory(final BeanManager beanManager) { + this.beanManager = beanManager; + } + + @Override + public Configurable<FeatureContext> create(FeatureContext context) { + return new CdiServerFeatureContextConfigurable(context, beanManager); + } + + /** + * Instantiates the instance of the provider using CDI/BeanManager + */ + private static class CdiInstantiator implements Instantiator { + private final BeanManager beanManager; + + CdiInstantiator(final BeanManager beanManager) { + this.beanManager = beanManager; + } + + @Override + public <T> Object create(Class<T> cls) { + final AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(cls); + final InjectionTargetFactory<T> injectionTargetFactory = + beanManager.getInjectionTargetFactory(annotatedType); + final BeanAttributes<T> attributes = beanManager.createBeanAttributes(annotatedType); + final Bean<T> bean = beanManager.createBean(attributes, cls, injectionTargetFactory); + final CreationalContext<?> context = beanManager.createCreationalContext(bean); + + if (!beanManager.isNormalScope(bean.getScope())) { + beanManager.fireEvent(new DisposableCreationalContext(context)); + } + + return beanManager.getReference(bean, cls, context); + } + } + + private static class CdiServerFeatureContextConfigurable extends ConfigurableImpl<FeatureContext> { + private final Instantiator instantiator; + + CdiServerFeatureContextConfigurable(FeatureContext mc, BeanManager beanManager) { + super(mc, RuntimeType.SERVER, SERVER_FILTER_INTERCEPTOR_CLASSES); + this.instantiator = new CdiInstantiator(beanManager); + } + + @Override + protected Instantiator getInstantiator() { + return instantiator; + } + } +} diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java index 2a36a3a4877..ce23e1a924c 100644 --- a/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java +++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/JAXRSCdiResourceExtension.java @@ -49,9 +49,11 @@ import org.apache.cxf.Bus; import org.apache.cxf.bus.extension.ExtensionManagerBus; +import org.apache.cxf.cdi.event.DisposableCreationalContext; import org.apache.cxf.cdi.extension.JAXRSServerFactoryCustomizationExtension; import org.apache.cxf.feature.Feature; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; +import org.apache.cxf.jaxrs.provider.ServerConfigurableFactory; import org.apache.cxf.jaxrs.utils.ResourceUtils; /** @@ -138,6 +140,11 @@ public void load(@Observes final AfterDeploymentValidation event, final BeanMana busBean, Bus.class, beanManager.createCreationalContext(busBean)); + + // Adding the extension for dynamic providers registration and instantiation + if (bus.getExtension(ServerConfigurableFactory.class) == null) { + bus.setExtension(new CdiServerConfigurableFactory(beanManager), ServerConfigurableFactory.class); + } for (final Bean< ? > application: applicationBeans) { final Application instance = (Application)beanManager.getReference( @@ -182,11 +189,22 @@ public void injectBus(@Observes final AfterBeanDiscovery event, final BeanManage } /** + * Registers created CreationalContext instances for disposal + */ + public void registerCreationalContextForDisposal(@Observes final DisposableCreationalContext event) { + synchronized (disposableCreationalContexts) { + disposableCreationalContexts.add(event.getContext()); + } + } + + /** * Releases created CreationalContext instances */ public void release(@Observes final BeforeShutdown event) { - for (final CreationalContext<?> disposableCreationalContext: disposableCreationalContexts) { - disposableCreationalContext.release(); + synchronized (disposableCreationalContexts) { + for (final CreationalContext<?> disposableCreationalContext: disposableCreationalContexts) { + disposableCreationalContext.release(); + } } } @@ -375,9 +393,13 @@ private void customize(final BeanManager beanManager, final JAXRSServerFactoryBe */ private<T> CreationalContext< T > createCreationalContext(final BeanManager beanManager, Bean< T > bean) { final CreationalContext< T > creationalContext = beanManager.createCreationalContext(bean); + if (!(bean instanceof DefaultApplicationBean)) { - disposableCreationalContexts.add(creationalContext); + synchronized (disposableCreationalContexts) { + disposableCreationalContexts.add(creationalContext); + } } + return creationalContext; } diff --git a/integration/cdi/src/main/java/org/apache/cxf/cdi/event/DisposableCreationalContext.java b/integration/cdi/src/main/java/org/apache/cxf/cdi/event/DisposableCreationalContext.java new file mode 100644 index 00000000000..0944e4a057f --- /dev/null +++ b/integration/cdi/src/main/java/org/apache/cxf/cdi/event/DisposableCreationalContext.java @@ -0,0 +1,34 @@ +/** + * 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.cxf.cdi.event; + +import javax.enterprise.context.spi.CreationalContext; + +public class DisposableCreationalContext { + private final CreationalContext<?> context; + + public DisposableCreationalContext(CreationalContext<?> context) { + this.context = context; + } + + public CreationalContext<?> getContext() { + return context; + } +} diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java index 9be144d0a55..54540272018 100644 --- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java +++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ConfigurableImpl.java @@ -31,12 +31,17 @@ public class ConfigurableImpl<C extends Configurable<C>> implements Configurable<C> { private ConfigurationImpl config; - private C configurable; - private Class<?>[] supportedProviderClasses; + private final C configurable; + private final Class<?>[] supportedProviderClasses; + + public interface Instantiator { + <T> Object create(Class<T> cls); + } + public ConfigurableImpl(C configurable, RuntimeType rt, Class<?>[] supportedProviderClasses) { this(configurable, supportedProviderClasses, new ConfigurationImpl(rt)); } - + public ConfigurableImpl(C configurable, Class<?>[] supportedProviderClasses, Configuration config) { this(configurable, supportedProviderClasses); this.config = config instanceof ConfigurationImpl @@ -98,8 +103,7 @@ public C register(Class<?> providerClass) { @Override public C register(Class<?> providerClass, int bindingPriority) { - return doRegister(ConfigurationImpl.createProvider(providerClass), - bindingPriority, supportedProviderClasses); + return doRegister(getInstantiator().create(providerClass), bindingPriority, supportedProviderClasses); } @Override @@ -109,7 +113,11 @@ public C register(Class<?> providerClass, Class<?>... contracts) { @Override public C register(Class<?> providerClass, Map<Class<?>, Integer> contracts) { - return register(ConfigurationImpl.createProvider(providerClass), contracts); + return register(getInstantiator().create(providerClass), contracts); + } + + protected Instantiator getInstantiator() { + return ConfigurationImpl::createProvider; } private C doRegister(Object provider, int bindingPriority, Class<?>... contracts) { diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerConfigurableFactory.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerConfigurableFactory.java new file mode 100644 index 00000000000..f4e9ef8e955 --- /dev/null +++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerConfigurableFactory.java @@ -0,0 +1,42 @@ +/** + * 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.cxf.jaxrs.provider; + +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.Configurable; +import javax.ws.rs.core.FeatureContext; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.WriterInterceptor; + +/** + * Manages the creation of server-side Configurable<FeatureContext> depending on + * the presence of managed runtime (like CDI f.e.). + */ +public interface ServerConfigurableFactory { + Class<?>[] SERVER_FILTER_INTERCEPTOR_CLASSES = new Class<?>[] { + ContainerRequestFilter.class, + ContainerResponseFilter.class, + ReaderInterceptor.class, + WriterInterceptor.class + }; + + Configurable<FeatureContext> create(FeatureContext context); +} diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java index dbacd48c3a1..dda7ee290d3 100644 --- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java +++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ServerProviderFactory.java @@ -21,11 +21,9 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -40,6 +38,7 @@ import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.container.DynamicFeature; import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Configurable; import javax.ws.rs.core.Configuration; import javax.ws.rs.core.Feature; import javax.ws.rs.core.FeatureContext; @@ -72,12 +71,6 @@ import org.apache.cxf.message.MessageUtils; public final class ServerProviderFactory extends ProviderFactory { - private static final Set<Class<?>> SERVER_FILTER_INTERCEPTOR_CLASSES = - new HashSet<Class<?>>(Arrays.<Class<?>>asList(ContainerRequestFilter.class, - ContainerResponseFilter.class, - ReaderInterceptor.class, - WriterInterceptor.class)); - private static final String WADL_PROVIDER_NAME = "org.apache.cxf.jaxrs.model.wadl.WadlGenerator"; private static final String MAKE_DEFAULT_WAE_LEAST_SPECIFIC = "default.wae.mapper.least.specific"; private List<ProviderInfo<ExceptionMapper<?>>> exceptionMappers = @@ -399,8 +392,11 @@ private void doApplyDynamicFeatures(ClassResourceInfo cri) { } private FeatureContext createServerFeatureContext() { - FeatureContextImpl featureContext = new FeatureContextImpl(); - ServerFeatureContextConfigurable configImpl = new ServerFeatureContextConfigurable(featureContext); + final FeatureContextImpl featureContext = new FeatureContextImpl(); + final ServerConfigurableFactory factory = getBus().getExtension(ServerConfigurableFactory.class); + final Configurable<FeatureContext> configImpl = (factory == null) + ? new ServerFeatureContextConfigurable(featureContext) + : factory.create(featureContext); featureContext.setConfigurable(configImpl); if (application != null) { @@ -418,7 +414,7 @@ protected static boolean isPrematching(Class<?> filterCls) { private static class ServerFeatureContextConfigurable extends ConfigurableImpl<FeatureContext> { protected ServerFeatureContextConfigurable(FeatureContext mc) { - super(mc, RuntimeType.SERVER, SERVER_FILTER_INTERCEPTOR_CLASSES.toArray(new Class<?>[]{})); + super(mc, RuntimeType.SERVER, ServerConfigurableFactory.SERVER_FILTER_INTERCEPTOR_CLASSES); } } diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreAuthenticator.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreAuthenticator.java new file mode 100644 index 00000000000..d2448cec54b --- /dev/null +++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreAuthenticator.java @@ -0,0 +1,33 @@ +/** + * 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.cxf.systests.cdi.base; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Named; + +@Named @ApplicationScoped +public class BookStoreAuthenticator { + public BookStoreAuthenticator() { + + } + + public boolean authenticated() { + return true; + } +} diff --git a/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreRequestFilter.java b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreRequestFilter.java new file mode 100644 index 00000000000..cbd88115afe --- /dev/null +++ b/systests/cdi/base/src/main/java/org/apache/cxf/systests/cdi/base/BookStoreRequestFilter.java @@ -0,0 +1,39 @@ +/** + * 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.cxf.systests.cdi.base; + +import java.io.IOException; + +import javax.inject.Inject; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +public class BookStoreRequestFilter implements ContainerRequestFilter { + @Inject private BookStoreAuthenticator authenticator; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + if (!authenticator.authenticated()) { + requestContext.abortWith(Response.status(Status.UNAUTHORIZED).build()); + } + } +} diff --git a/systests/cdi/cdi-owb/cdi-producers-owb/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java b/systests/cdi/cdi-owb/cdi-producers-owb/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java index 6a108dc1834..ba340825828 100644 --- a/systests/cdi/cdi-owb/cdi-producers-owb/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java +++ b/systests/cdi/cdi-owb/cdi-producers-owb/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java @@ -23,11 +23,13 @@ import javax.ws.rs.core.FeatureContext; import org.apache.cxf.jaxrs.provider.atom.AtomFeedProvider; +import org.apache.cxf.systests.cdi.base.BookStoreRequestFilter; public class SampleFeature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(AtomFeedProvider.class); + context.register(BookStoreRequestFilter.class); return false; } } diff --git a/systests/cdi/cdi-weld/cdi-producers-weld/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java b/systests/cdi/cdi-weld/cdi-producers-weld/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java index 6a108dc1834..ba340825828 100644 --- a/systests/cdi/cdi-weld/cdi-producers-weld/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java +++ b/systests/cdi/cdi-weld/cdi-producers-weld/src/test/java/org/apache/cxf/systest/jaxrs/cdi/SampleFeature.java @@ -23,11 +23,13 @@ import javax.ws.rs.core.FeatureContext; import org.apache.cxf.jaxrs.provider.atom.AtomFeedProvider; +import org.apache.cxf.systests.cdi.base.BookStoreRequestFilter; public class SampleFeature implements Feature { @Override public boolean configure(FeatureContext context) { context.register(AtomFeedProvider.class); + context.register(BookStoreRequestFilter.class); return false; } } ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: [email protected] With regards, Apache Git Services
