From 8da311447d1b87942a186d185b7e0a68e96e4abf Mon Sep 17 00:00:00 2001 From: jbescos Date: Wed, 14 Apr 2021 15:27:37 +0200 Subject: [PATCH 1/5] Stop filling monitoring queues when processor fails (#4697) Signed-off-by: Jorge Bescos Gascon --- .../monitoring/MonitoringEventListener.java | 31 ++- .../MonitoringStatisticsProcessor.java | 23 +-- tests/integration/jersey-4697/pom.xml | 45 +++++ .../MonitoringEventListenerTest.java | 178 ++++++++++++++++++ tests/integration/pom.xml | 1 + 5 files changed, 257 insertions(+), 21 deletions(-) create mode 100644 tests/integration/jersey-4697/pom.xml create mode 100644 tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringEventListener.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringEventListener.java index 84abfd64de..dd397bf759 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringEventListener.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -20,14 +20,14 @@ import java.util.List; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; -import javax.ws.rs.ProcessingException; - import javax.annotation.Priority; import javax.inject.Inject; +import javax.ws.rs.ProcessingException; import org.glassfish.jersey.internal.inject.InjectionManager; import org.glassfish.jersey.server.internal.LocalizationMessages; @@ -68,6 +68,8 @@ public final class MonitoringEventListener implements ApplicationEventListener { private final Queue responseStatuses = new ArrayBlockingQueue<>(EVENT_QUEUE_SIZE); private final Queue exceptionMapperEvents = new ArrayBlockingQueue<>(EVENT_QUEUE_SIZE); private volatile MonitoringStatisticsProcessor monitoringStatisticsProcessor; + // By default new events can arrive before MonitoringStatisticsProcessor is running. + private final AtomicBoolean processorFailed = new AtomicBoolean(false); /** * Time statistics. @@ -185,6 +187,7 @@ public void onEvent(final ApplicationEvent event) { case RELOAD_FINISHED: case INITIALIZATION_FINISHED: this.monitoringStatisticsProcessor = new MonitoringStatisticsProcessor(injectionManager, this); + processorFailed.set(false); this.monitoringStatisticsProcessor.startMonitoringWorker(); break; case DESTROY_FINISHED: @@ -238,13 +241,13 @@ public void onEvent(final RequestEvent event) { methodStats = new MethodStats(method, methodTimeStart, now - methodTimeStart); break; case EXCEPTION_MAPPING_FINISHED: - if (!exceptionMapperEvents.offer(event)) { + if (!offer(exceptionMapperEvents, event)) { LOGGER.warning(LocalizationMessages.ERROR_MONITORING_QUEUE_MAPPER()); } break; case FINISHED: if (event.isResponseWritten()) { - if (!responseStatuses.offer(event.getContainerResponse().getStatus())) { + if (!offer(responseStatuses, event.getContainerResponse().getStatus())) { LOGGER.warning(LocalizationMessages.ERROR_MONITORING_QUEUE_RESPONSE()); } } @@ -264,8 +267,7 @@ public void onEvent(final RequestEvent event) { } sb.setLength(sb.length() - 1); } - - if (!requestQueuedItems.offer(new RequestStats(new TimeStats(requestTimeStart, now - requestTimeStart), + if (!offer(requestQueuedItems, new RequestStats(new TimeStats(requestTimeStart, now - requestTimeStart), methodStats, sb.toString()))) { LOGGER.warning(LocalizationMessages.ERROR_MONITORING_QUEUE_REQUEST()); } @@ -274,6 +276,21 @@ public void onEvent(final RequestEvent event) { } } + private boolean offer(Queue queue, T event) { + if (!processorFailed.get()) { + return queue.offer(event); + } + // Don't need to warn that the event was not queued because an Exception was thrown by MonitoringStatisticsProcessor + return true; + } + + /** + * Invoked by {@link MonitoringStatisticsProcessor} when there is one exception consuming from queues. + */ + void processorFailed() { + processorFailed.set(true); + } + /** * Get the exception mapper event queue. * diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringStatisticsProcessor.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringStatisticsProcessor.java index 8bc4ec8f0e..580c1dbfdc 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringStatisticsProcessor.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/MonitoringStatisticsProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -35,6 +35,7 @@ import org.glassfish.jersey.server.ExtendedResourceContext; import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.server.internal.LocalizationMessages; +import org.glassfish.jersey.server.internal.monitoring.MonitoringEventListener.RequestStats; import org.glassfish.jersey.server.model.ResourceMethod; import org.glassfish.jersey.server.model.ResourceModel; import org.glassfish.jersey.server.monitoring.MonitoringStatisticsListener; @@ -94,6 +95,7 @@ public void run() { processResponseCodeEvents(); processExceptionMapperEvents(); } catch (final Throwable t) { + monitoringEventListener.processorFailed(); LOGGER.log(Level.SEVERE, LocalizationMessages.ERROR_MONITORING_STATISTICS_GENERATION(), t); // rethrowing exception stops further task execution throw new ProcessingException(LocalizationMessages.ERROR_MONITORING_STATISTICS_GENERATION(), t); @@ -120,11 +122,9 @@ public void run() { private void processExceptionMapperEvents() { final Queue eventQueue = monitoringEventListener.getExceptionMapperEvents(); final FloodingLogger floodingLogger = new FloodingLogger(eventQueue); - - while (!eventQueue.isEmpty()) { + RequestEvent event = null; + while ((event = eventQueue.poll()) != null) { floodingLogger.conditionallyLogFlooding(); - - final RequestEvent event = eventQueue.remove(); final ExceptionMapperStatisticsImpl.Builder mapperStats = statisticsBuilder.getExceptionMapperStatisticsBuilder(); if (event.getExceptionMapper() != null) { @@ -138,12 +138,9 @@ private void processExceptionMapperEvents() { private void processRequestItems() { final Queue requestQueuedItems = monitoringEventListener.getRequestQueuedItems(); final FloodingLogger floodingLogger = new FloodingLogger(requestQueuedItems); - - while (!requestQueuedItems.isEmpty()) { + RequestStats event = null; + while ((event = requestQueuedItems.poll()) != null) { floodingLogger.conditionallyLogFlooding(); - - final MonitoringEventListener.RequestStats event = requestQueuedItems.remove(); - final MonitoringEventListener.TimeStats requestStats = event.getRequestStats(); statisticsBuilder.addRequestExecution(requestStats.getStartTime(), requestStats.getDuration()); @@ -160,11 +157,9 @@ private void processRequestItems() { private void processResponseCodeEvents() { final Queue responseEvents = monitoringEventListener.getResponseStatuses(); final FloodingLogger floodingLogger = new FloodingLogger(responseEvents); - - while (!responseEvents.isEmpty()) { + Integer code = null; + while ((code = responseEvents.poll()) != null) { floodingLogger.conditionallyLogFlooding(); - - final Integer code = responseEvents.remove(); statisticsBuilder.addResponseCode(code); } diff --git a/tests/integration/jersey-4697/pom.xml b/tests/integration/jersey-4697/pom.xml new file mode 100644 index 0000000000..27ee6ca51e --- /dev/null +++ b/tests/integration/jersey-4697/pom.xml @@ -0,0 +1,45 @@ + + + + + project + org.glassfish.jersey.tests.integration + 2.34-SNAPSHOT + + 4.0.0 + + jersey-4697 + + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-bundle + pom + test + + + org.mockito + mockito-all + test + + + + \ No newline at end of file diff --git a/tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java b/tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java new file mode 100644 index 0000000000..578d96442d --- /dev/null +++ b/tests/integration/jersey-4697/src/test/java/org/glassfish/jersey/tests/integration/jersey4697/MonitoringEventListenerTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.integration.jersey4697; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.lang.management.ManagementFactory; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Map; + +import javax.inject.Inject; +import javax.management.JMX; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeDataSupport; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import org.glassfish.jersey.internal.inject.InjectionManager; +import org.glassfish.jersey.internal.inject.Providers; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; +import org.glassfish.jersey.server.internal.monitoring.MonitoringEventListener; +import org.glassfish.jersey.server.monitoring.ApplicationEventListener; +import org.glassfish.jersey.server.monitoring.ExceptionMapperMXBean; +import org.glassfish.jersey.server.monitoring.RequestEvent; +import org.glassfish.jersey.server.monitoring.RequestEventListener; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class MonitoringEventListenerTest extends JerseyTest { + + private static final long TIMEOUT = 500; + private static final String MBEAN_EXCEPTION = + "org.glassfish.jersey:type=MonitoringEventListenerTest,subType=Global,exceptions=ExceptionMapper"; + + @Path("/example") + public static class ExampleResource { + @Inject + private InjectionManager injectionManager; + @GET + @Path("/error") + public Response error() { + throw new RuntimeException("Any exception to be counted in ExceptionMapper"); + } + @GET + @Path("/poison") + public Response poison() { + MonitoringEventListener monitoringEventListener = listener(); + RequestEvent requestEvent = mock(RequestEvent.class); + when(requestEvent.getType()).thenReturn(RequestEvent.Type.START); + RequestEventListener eventListener = monitoringEventListener.onRequest(requestEvent); + RequestEvent poisonEvent = mock(RequestEvent.class); + when(poisonEvent.getType()).thenReturn(RequestEvent.Type.EXCEPTION_MAPPING_FINISHED); + when(poisonEvent.getExceptionMapper()) + .thenThrow(new IllegalStateException("This causes the scheduler to stop working")); + eventListener.onEvent(poisonEvent); + return Response.ok().build(); + } + @GET + @Path("/queueSize") + public Response queueSize() throws Exception { + MonitoringEventListener monitoringEventListener = listener(); + Method method = MonitoringEventListener.class.getDeclaredMethod("getExceptionMapperEvents"); + method.setAccessible(true); + Collection queue = (Collection) method.invoke(monitoringEventListener); + return Response.ok(queue.size()).build(); + } + private MonitoringEventListener listener() { + Iterable listeners = + Providers.getAllProviders(injectionManager, ApplicationEventListener.class); + for (ApplicationEventListener listener : listeners) { + if (listener instanceof MonitoringEventListener) { + return (MonitoringEventListener) listener; + } + } + throw new IllegalStateException("MonitoringEventListener was not found"); + } + } + + @Provider + public static class RuntimeExceptionMapper implements ExceptionMapper { + @Override + public Response toResponse(RuntimeException e) { + return Response.status(500).entity("RuntimeExceptionMapper: " + e.getMessage()).build(); + } + } + + @Override + protected Application configure() { + ResourceConfig resourceConfig = new ResourceConfig(ExampleResource.class); + // Need to map the exception to be counted by ExceptionMapper + resourceConfig.register(RuntimeExceptionMapper.class); + resourceConfig.property(ServerProperties.MONITORING_ENABLED, true); + resourceConfig.property(ServerProperties.MONITORING_STATISTICS_ENABLED, true); + resourceConfig.property(ServerProperties.MONITORING_STATISTICS_MBEANS_ENABLED, true); + resourceConfig.property(ServerProperties.MONITORING_STATISTICS_REFRESH_INTERVAL, 1); + resourceConfig.setApplicationName("MonitoringEventListenerTest"); + return resourceConfig; + } + + @Test + public void exceptionInScheduler() throws Exception { + final Long ERRORS_BEFORE_FAIL = 10L; + // Send some requests to process some statistics. + request(ERRORS_BEFORE_FAIL); + // Give some time to the scheduler to collect data. + Thread.sleep(TIMEOUT); + // All events were consumed by scheduler + queueIsEmpty(); + // Make the scheduler to fail. No more statistics are collected. + makeFailure(); + // Sending again requests + request(20); + Thread.sleep(TIMEOUT); + // No new events should be accepted because scheduler is not working. + queueIsEmpty(); + Long monitoredErrors = mappedErrorsFromJMX(MBEAN_EXCEPTION); + assertEquals(ERRORS_BEFORE_FAIL, monitoredErrors); + } + + private void makeFailure() { + Response response = target("/example/poison").request().get(); + assertEquals(200, response.getStatus()); + } + + private void queueIsEmpty() { + Response response = target("/example/queueSize").request().get(); + assertEquals(200, response.getStatus()); + assertEquals(Integer.valueOf(0), response.readEntity(Integer.class)); + } + + private Long mappedErrorsFromJMX(String name) throws Exception { + Long monitoredErrors = null; + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + ObjectName objectName = new ObjectName(name); + ExceptionMapperMXBean bean = JMX.newMBeanProxy(mbs, objectName, ExceptionMapperMXBean.class); + Map counter = bean.getExceptionMapperCount(); + CompositeDataSupport value = (CompositeDataSupport) counter.entrySet().iterator().next().getValue(); + for (Object obj : value.values()) { + if (obj instanceof Long) { + // Messy way to get the errors, but generic types doesn't match and there is no nice way + monitoredErrors = (Long) obj; + break; + } + } + return monitoredErrors; + } + + private void request(long requests) { + for (long i = 0; i < requests; i++) { + Response response = target("/example/error").request().get(); + assertEquals(500, response.getStatus()); + } + } +} diff --git a/tests/integration/pom.xml b/tests/integration/pom.xml index 0b5c2b32bf..6398e81887 100644 --- a/tests/integration/pom.xml +++ b/tests/integration/pom.xml @@ -88,6 +88,7 @@ jersey-4321 jersey-4507 jersey-4542 + jersey-4697 jersey-4722 jetty-response-close microprofile From 7b6d2f84391f24310baae7d8e55e644703642826 Mon Sep 17 00:00:00 2001 From: jansupol Date: Fri, 9 Apr 2021 15:37:38 +0200 Subject: [PATCH 2/5] Add a default Enum MB provider. Signed-off-by: jansupol --- .../message/internal/EnumMessageProvider.java | 72 +++++++ .../message/internal/MessagingBinders.java | 3 +- .../tests/e2e/entity/EnumEntityTest.java | 175 ++++++++++++++++++ 3 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 core-common/src/main/java/org/glassfish/jersey/message/internal/EnumMessageProvider.java create mode 100644 tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EnumEntityTest.java diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/EnumMessageProvider.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/EnumMessageProvider.java new file mode 100644 index 0000000000..bcf30bd450 --- /dev/null +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/EnumMessageProvider.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.message.internal; + +import javax.inject.Singleton; +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +/** + * Default provider for enum types. + * @since 2.34 + */ +@Singleton +@Consumes(MediaType.TEXT_PLAIN) +@Produces(MediaType.TEXT_PLAIN) +final class EnumMessageProvider extends AbstractMessageReaderWriterProvider { + + @Override + public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.isEnum(); + } + + @Override + public Enum readFrom( + Class type, + Type genericType, + Annotation[] annotations, + MediaType mediaType, + MultivaluedMap httpHeaders, + InputStream entityStream) throws IOException, WebApplicationException { + final String value = readFromAsString(entityStream, mediaType); + return Enum.valueOf(type, value); + } + + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.isEnum(); + } + + @Override + public void writeTo( + Enum anEnum, Class type, + Type genericType, + Annotation[] annotations, + MediaType mediaType, + MultivaluedMap httpHeaders, + OutputStream entityStream) throws IOException, WebApplicationException { + writeToAsString(anEnum.name(), entityStream, mediaType); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java index 8c5e67d0e9..3df2ae9d7c 100644 --- a/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java +++ b/core-common/src/main/java/org/glassfish/jersey/message/internal/MessagingBinders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -89,6 +89,7 @@ protected void configure() { bindSingletonWorker(ReaderProvider.class); // bindSingletonWorker(RenderedImageProvider.class); - enabledProvidersBinder bindSingletonWorker(StringMessageProvider.class); + bindSingletonWorker(EnumMessageProvider.class); // Message body readers -- enabledProvidersBinder // bind(SourceProvider.StreamSourceReader.class).to(MessageBodyReader.class).in(Singleton.class); diff --git a/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EnumEntityTest.java b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EnumEntityTest.java new file mode 100644 index 0000000000..6e842ff673 --- /dev/null +++ b/tests/e2e-entity/src/test/java/org/glassfish/jersey/tests/e2e/entity/EnumEntityTest.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.e2e.entity; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.util.runner.ConcurrentRunner; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +@RunWith(ConcurrentRunner.class) +public class EnumEntityTest extends JerseyTest { + + public enum SimpleEnum { + VALUE1, + VALUE2 + } + + public enum ValueEnum { + VALUE100(100), + VALUE200(200); + + private final int value; + + ValueEnum(int value) { + this.value = value; + } + } + + @Path("/") + public static class EnumResource { + @POST + @Path("/simple") + public String postSimple(SimpleEnum simpleEnum) { + return simpleEnum.name(); + } + + @POST + @Path("/value") + public String postValue(ValueEnum valueEnum) { + return valueEnum.name(); + } + + @POST + @Path("/echo") + public String echo(String value) { + return value; + } + + @PUT + @Path("/simple") + public SimpleEnum putSimple(String simple) { + return SimpleEnum.valueOf(simple); + } + + @PUT + @Path("value") + public ValueEnum putValue(String value) { + return ValueEnum.valueOf(value); + } + } + + @Override + protected Application configure() { + return new ResourceConfig(EnumResource.class); + } + + // Server side tests + + @Test + public void testSimpleEnumServerReader() { + for (SimpleEnum value : SimpleEnum.values()) { + try (Response r = target("simple").request(MediaType.TEXT_PLAIN_TYPE) + .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value.name(), r.readEntity(String.class)); + } + } + } + + @Test + public void testValueEnumServerReader() { + for (ValueEnum value : ValueEnum.values()) { + try (Response r = target("value").request(MediaType.TEXT_PLAIN_TYPE) + .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value.name(), r.readEntity(String.class)); + } + } + } + + @Test + public void testSimpleEnumServerWriter() { + for (SimpleEnum value : SimpleEnum.values()) { + try (Response r = target("simple").request(MediaType.TEXT_PLAIN_TYPE) + .put(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value.name(), r.readEntity(String.class)); + } + } + } + + @Test + public void testValueEnumServerWriter() { + for (ValueEnum value : ValueEnum.values()) { + try (Response r = target("value").request(MediaType.TEXT_PLAIN_TYPE) + .put(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value.name(), r.readEntity(String.class)); + } + } + } + + // Client side tests + + @Test + public void testSimpleEnumClientReader() { + for (SimpleEnum value : SimpleEnum.values()) { + try (Response r = target("simple").request(MediaType.TEXT_PLAIN_TYPE) + .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value, r.readEntity(SimpleEnum.class)); + } + } + } + + @Test + public void testValueEnumClientReader() { + for (ValueEnum value : ValueEnum.values()) { + try (Response r = target("value").request(MediaType.TEXT_PLAIN_TYPE) + .post(Entity.entity(value.name(), MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value, r.readEntity(ValueEnum.class)); + } + } + } + + @Test + public void testSimpleEnumClientWriter() { + for (SimpleEnum value : SimpleEnum.values()) { + try (Response r = target("echo").request(MediaType.TEXT_PLAIN_TYPE) + .post(Entity.entity(value, MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value.name(), r.readEntity(String.class)); + } + } + } + + @Test + public void testValueEnumClientWriter() { + for (ValueEnum value : ValueEnum.values()) { + try (Response r = target("echo").request(MediaType.TEXT_PLAIN_TYPE) + .post(Entity.entity(value, MediaType.TEXT_PLAIN_TYPE))) { + Assert.assertEquals(value.name(), r.readEntity(String.class)); + } + } + } + +} From 06b1a6cae5d7720897bc726197de838f42441b04 Mon Sep 17 00:00:00 2001 From: jansupol <15908245+jansupol@users.noreply.github.com> Date: Thu, 15 Apr 2021 19:27:07 +0200 Subject: [PATCH 3/5] Allow to use @Inject instead of @Context with CDI (#4749) * Allow to use @Inject instead of @Context with CDI Signed-off-by: jansupol --- bom/pom.xml | 5 + .../RequestProcessingConfigurator.java | 5 +- ext/cdi/jersey-cdi-rs-inject/pom.xml | 50 +++ .../inject/internal/InjectExtension.java | 114 +++++++ .../javax.enterprise.inject.spi.Extension | 1 + .../internal/AbstractCdiBeanSupplier.java | 21 +- .../cdi1x/internal/CdiComponentProvider.java | 66 +++- ext/cdi/pom.xml | 1 + .../context-inject-on-server/pom.xml | 89 ++++++ .../cdi/inject/ApplicationInjectParent.java | 209 +++++++++++++ .../tests/cdi/inject/InjectionChecker.java | 294 ++++++++++++++++++ .../cdi/inject/NonScopedApplication.java | 33 ++ .../inject/NonScopedApplicationInject.java | 33 ++ .../NonScopedContainerRequestFilter.java | 20 ++ .../NonScopedContainerResponseFilter.java | 21 ++ .../cdi/inject/NonScopedExceptionMapper.java | 20 ++ .../tests/cdi/inject/NonScopedResource.java | 25 ++ .../inject/NonScopedWriterInterceptor.java | 27 ++ .../tests/cdi/inject/ParentChecker.java | 22 ++ .../inject/ParentContainerRequestFilter.java | 47 +++ .../inject/ParentContainerResponseFilter.java | 46 +++ .../cdi/inject/ParentExceptionMapper.java | 44 +++ .../jersey/tests/cdi/inject/ParentInject.java | 195 ++++++++++++ .../tests/cdi/inject/ParentResource.java | 64 ++++ .../cdi/inject/ParentWriterInterceptor.java | 54 ++++ .../cdi/inject/PropertySettingFilter.java | 36 +++ .../cdi/inject/RequestScopedParentInject.java | 47 +++ .../tests/cdi/inject/ScopedApplication.java | 36 +++ .../cdi/inject/ScopedApplicationInject.java | 38 +++ .../inject/ScopedContainerRequestFilter.java | 23 ++ .../inject/ScopedContainerResponseFilter.java | 23 ++ .../cdi/inject/ScopedExceptionMapper.java | 23 ++ .../tests/cdi/inject/ScopedResource.java | 27 ++ .../cdi/inject/ScopedWriterInterceptor.java | 28 ++ .../tests/cdi/inject/SseAplication.java | 104 +++++++ .../src/main/resources/META-INF/beans.xml | 25 ++ .../NonScopedApplicationInjectTest.java | 95 ++++++ .../cdi/inject/NonScopedInjectionTest.java | 132 ++++++++ .../inject/ScopedApplicationInjectTest.java | 95 ++++++ .../tests/cdi/inject/ScopedInjectionTest.java | 131 ++++++++ .../jersey/tests/cdi/inject/SseTest.java | 130 ++++++++ tests/integration/cdi-integration/pom.xml | 1 + 42 files changed, 2487 insertions(+), 13 deletions(-) create mode 100644 ext/cdi/jersey-cdi-rs-inject/pom.xml create mode 100644 ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java create mode 100644 ext/cdi/jersey-cdi-rs-inject/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension create mode 100644 tests/integration/cdi-integration/context-inject-on-server/pom.xml create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/InjectionChecker.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplication.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInject.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerRequestFilter.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerResponseFilter.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedExceptionMapper.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedResource.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedWriterInterceptor.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentChecker.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentExceptionMapper.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentResource.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentWriterInterceptor.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/PropertySettingFilter.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/RequestScopedParentInject.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplication.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInject.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerRequestFilter.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerResponseFilter.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedExceptionMapper.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedResource.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedWriterInterceptor.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/SseAplication.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/main/resources/META-INF/beans.xml create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInjectTest.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedInjectionTest.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInjectTest.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedInjectionTest.java create mode 100644 tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/SseTest.java diff --git a/bom/pom.xml b/bom/pom.xml index ac731c53a9..d7fc55ef76 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -243,6 +243,11 @@ jersey-cdi1x-ban-custom-hk2-binding ${project.version} + + org.glassfish.jersey.ext.cdi + jersey-cdi-rs-inject + ${project.version} + org.glassfish.jersey.ext.rx jersey-rx-client-guava diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/process/RequestProcessingConfigurator.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/process/RequestProcessingConfigurator.java index d084621dfc..1e703c154b 100644 --- a/core-server/src/main/java/org/glassfish/jersey/server/internal/process/RequestProcessingConfigurator.java +++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/process/RequestProcessingConfigurator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -30,6 +30,7 @@ import org.glassfish.jersey.internal.BootstrapBag; import org.glassfish.jersey.internal.BootstrapConfigurator; +import org.glassfish.jersey.internal.PropertiesDelegate; import org.glassfish.jersey.internal.inject.AbstractBinder; import org.glassfish.jersey.internal.inject.InjectionManager; import org.glassfish.jersey.process.internal.RequestScoped; @@ -132,7 +133,7 @@ protected void configure() { // Bind proxiable HttpHeaders, Request and ContainerRequestContext injection injection points bindFactory(ContainerRequestFactory.class) - .to(HttpHeaders.class).to(Request.class) + .to(HttpHeaders.class).to(Request.class).to(PropertiesDelegate.class) .proxy(true).proxyForSameScope(false) .in(RequestScoped.class); diff --git a/ext/cdi/jersey-cdi-rs-inject/pom.xml b/ext/cdi/jersey-cdi-rs-inject/pom.xml new file mode 100644 index 0000000000..a2720f61fc --- /dev/null +++ b/ext/cdi/jersey-cdi-rs-inject/pom.xml @@ -0,0 +1,50 @@ + + + + + project + org.glassfish.jersey.ext.cdi + 2.34-SNAPSHOT + + 4.0.0 + + jersey-cdi-rs-inject + jersey-ext-cdi-rs-inject + Allow to annotate by Inject instead of Context + + + + org.glassfish.jersey.core + jersey-common + ${project.version} + + + org.glassfish.jersey.ext.cdi + jersey-cdi1x + ${project.version} + + + javax.enterprise + cdi-api + provided + + + + \ No newline at end of file diff --git a/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java new file mode 100644 index 0000000000..a6d2e09bb1 --- /dev/null +++ b/ext/cdi/jersey-cdi-rs-inject/src/main/java/org/glassfish/jersey/ext/cdi1x/inject/internal/InjectExtension.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.ext.cdi1x.inject.internal; + +import org.glassfish.jersey.ext.cdi1x.internal.CdiComponentProvider; +import org.glassfish.jersey.internal.util.ReflectionHelper; +import org.glassfish.jersey.internal.util.collection.LazyValue; +import org.glassfish.jersey.internal.util.collection.Value; +import org.glassfish.jersey.internal.util.collection.Values; + +import javax.enterprise.event.Observes; +import javax.enterprise.inject.Alternative; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.BeforeBeanDiscovery; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessAnnotatedType; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ResourceContext; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Configuration; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.ext.ParamConverterProvider; +import javax.ws.rs.ext.Providers; +import javax.ws.rs.sse.Sse; +import java.security.AccessController; +import java.util.HashSet; +import java.util.Set; + +/** + *

+ * A utility class that makes sure {@code @Inject} can be used instead of {@code @Context} for the Jakarta REST API classes + * and interfaces, such as for {@code Configuration}, or {@code Providers}. + *

+ *

+ * Note that {@code ContextResolver} can be injected using {@code @Context}, but the Jakarta REST specification does not require + * the implementation to be capable of doing so. Since {@code ContextResolver} is parametrized type, the injection using CDI's + * {@Inject} is not supported. The {@code ContextResolver} can be obtained from {@code Providers}. + *

+ */ +@SuppressWarnings("unused") +class InjectExtension implements Extension { + private void processAnnotatedType(@Observes ProcessAnnotatedType processAnnotatedType, BeanManager beanManager) { + final Class baseClass = (Class) processAnnotatedType.getAnnotatedType().getBaseType(); + if (Application.class.isAssignableFrom(baseClass) && Configuration.class.isAssignableFrom(baseClass)) { + if (!baseClass.isAnnotationPresent(Alternative.class)) { + processAnnotatedType.veto(); // Filter bean annotated ResourceConfig + } + } + } + + private void beforeDiscoveryObserver(@Observes final BeforeBeanDiscovery bbf, final BeanManager beanManager) { + final CdiComponentProvider cdiComponentProvider = beanManager.getExtension(CdiComponentProvider.class); + cdiComponentProvider.addHK2DepenendencyCheck(InjectExtension::isHK2Dependency); + } + + private static final boolean isHK2Dependency(Class clazz) { + return JERSEY_BOUND_INJECTABLES.get().contains(clazz); + } + + private static final LazyValue>> JERSEY_BOUND_INJECTABLES + = Values.lazy((Value>>) () -> sumNonJerseyBoundInjectables()); + + private static Set> sumNonJerseyBoundInjectables() { + final Set> injectables = new HashSet<>(); + + //JAX-RS + injectables.add(Application.class); + injectables.add(Configuration.class); + injectables.add(ContainerRequestContext.class); + injectables.add(HttpHeaders.class); + injectables.add(ParamConverterProvider.class); + injectables.add(Providers.class); + injectables.add(Request.class); + injectables.add(ResourceContext.class); + injectables.add(ResourceInfo.class); + injectables.add(SecurityContext.class); + injectables.add(Sse.class); + injectables.add(UriInfo.class); + + //Servlet if available + addOptionally("javax.servlet.http.HttpServletRequest", injectables); + addOptionally("javax.servlet.http.HttpServletResponse", injectables); + addOptionally("javax.servlet.ServletConfig", injectables); + addOptionally("javax.servlet.ServletContext", injectables); + addOptionally("javax.servlet.FilterConfig", injectables); + + return injectables; + } + + private static void addOptionally(String className, Set> set) { + final Class optionalClass = AccessController.doPrivileged(ReflectionHelper.classForNamePA(className)); + if (optionalClass != null) { + set.add(optionalClass); + } + } +} diff --git a/ext/cdi/jersey-cdi-rs-inject/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/ext/cdi/jersey-cdi-rs-inject/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 0000000000..4613a217d0 --- /dev/null +++ b/ext/cdi/jersey-cdi-rs-inject/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1 @@ +org.glassfish.jersey.ext.cdi1x.inject.internal.InjectExtension \ No newline at end of file diff --git a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java index bba828251e..5bea827384 100644 --- a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java +++ b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/AbstractCdiBeanSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -19,11 +19,14 @@ import java.lang.annotation.Annotation; import java.util.Iterator; import java.util.NoSuchElementException; +import java.util.Set; +import javax.enterprise.context.spi.Contextual; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.InjectionPoint; import javax.enterprise.inject.spi.InjectionTarget; import javax.enterprise.inject.spi.InjectionTargetFactory; @@ -83,11 +86,17 @@ public void preDestroy(final T instance) { public T getInstance(final Class clazz) { final CreationalContext creationalContext = beanManager.createCreationalContext(null); final T instance = injectionTarget.produce(creationalContext); - injectionTarget.inject(instance, creationalContext); - if (injectionManager != null) { - injectionManager.inject(instance, CdiComponentProvider.CDI_CLASS_ANALYZER); - } - injectionTarget.postConstruct(instance); + final CdiComponentProvider cdiComponentProvider = beanManager.getExtension(CdiComponentProvider.class); + final CdiComponentProvider.InjectionManagerInjectedCdiTarget hk2managedTarget = + cdiComponentProvider.new InjectionManagerInjectedCdiTarget(injectionTarget) { + @Override + public Set getInjectionPoints() { + return injectionTarget.getInjectionPoints(); + } + }; + hk2managedTarget.setInjectionManager(injectionManager); + hk2managedTarget.inject(instance, creationalContext); + hk2managedTarget.postConstruct(instance); return instance; } diff --git a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java index 364319afef..9e3596698f 100644 --- a/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java +++ b/ext/cdi/jersey-cdi1x/src/main/java/org/glassfish/jersey/ext/cdi1x/internal/CdiComponentProvider.java @@ -29,10 +29,12 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; @@ -110,6 +112,8 @@ public class CdiComponentProvider implements ComponentProvider, Extension { private final Set jaxrsInjectableTypes = new HashSet<>(); private final Set hk2ProvidedTypes = Collections.synchronizedSet(new HashSet()); private final Set jerseyVetoedTypes = Collections.synchronizedSet(new HashSet()); + private final Set jerseyOrDependencyTypes = Collections.synchronizedSet(new LinkedHashSet<>()); + private final ThreadLocal threadInjectionManagers = new ThreadLocal<>(); /** * set of request scoped components @@ -138,6 +142,7 @@ public Boolean apply(final Class clazz) { public CdiComponentProvider() { customHk2TypesProvider = CdiUtil.lookupService(Hk2CustomBoundTypesProvider.class); injectionManagerStore = CdiUtil.createHk2InjectionManagerStore(); + addHK2DepenendencyCheck(CdiComponentProvider::isJerseyOrDependencyType); } @Override @@ -449,7 +454,7 @@ private Set filterHk2InjectionPointsOut(final Set) { final Class injectedClass = (Class) injectedType; - if (isJerseyOrDependencyType(injectedClass)) { + if (testDependencyType(injectedClass)) { //remember the type, we would need to mock it's CDI binding at runtime hk2ProvidedTypes.add(injectedType); } else { @@ -598,6 +603,15 @@ private static boolean isJerseyOrDependencyType(final Class clazz) { && !pkgName.startsWith("com.sun.jersey.tests"))); } + private boolean testDependencyType(Class clazz) { + for (Predicate> predicate : jerseyOrDependencyTypes) { + if (predicate.test(clazz)) { + return true; + } + } + return false; + } + private void bindHk2ClassAnalyzer() { ClassAnalyzer defaultClassAnalyzer = injectionManager.getInstance(ClassAnalyzer.class, ClassAnalyzer.DEFAULT_IMPLEMENTATION_NAME); @@ -628,7 +642,7 @@ private StringBuilder listElements(final StringBuilder logMsgBuilder, final Coll } @SuppressWarnings("unchecked") - private abstract class InjectionManagerInjectedCdiTarget implements InjectionManagerInjectedTarget { + /* package */ abstract class InjectionManagerInjectedCdiTarget implements InjectionManagerInjectedTarget { private final InjectionTarget delegate; private volatile InjectionManager effectiveInjectionManager; @@ -642,16 +656,19 @@ public InjectionManagerInjectedCdiTarget(InjectionTarget delegate) { @Override public void inject(final Object t, final CreationalContext cc) { - delegate.inject(t, cc); - InjectionManager injectingManager = getEffectiveInjectionManager(); if (injectingManager == null) { injectingManager = effectiveInjectionManager; + threadInjectionManagers.set(injectingManager); } + delegate.inject(t, cc); // here the injection manager is used in HK2Bean + if (injectingManager != null) { injectingManager.inject(t, CdiComponentProvider.CDI_CLASS_ANALYZER); } + + threadInjectionManagers.remove(); } @Override @@ -705,7 +722,12 @@ public boolean isNullable() { @Override public Object create(final CreationalContext creationalContext) { - return getEffectiveInjectionManager().getInstance(t); + InjectionManager injectionManager = getEffectiveInjectionManager(); + if (injectionManager == null) { + injectionManager = threadInjectionManagers.get(); + } + + return injectionManager.getInstance(t); } @Override @@ -824,5 +846,39 @@ private void beforeBeanDiscovery(@Observes final BeforeBeanDiscovery beforeBeanD "Jersey " + ProcessJAXRSAnnotatedTypes.class.getName() ); } + + /** + * Add a predicate to test HK2 dependency to create a CDI bridge bean to HK2 for it. + * @param predicate to test whether given class is a HK2 dependency. + */ + public void addHK2DepenendencyCheck(Predicate> predicate) { + jerseyOrDependencyTypes.add(new DependencyPredicate(predicate)); + } + + private final class DependencyPredicate implements Predicate> { + private final Predicate> predicate; + + public DependencyPredicate(Predicate> predicate) { + this.predicate = predicate; + } + + @Override + public boolean test(Class aClass) { + return predicate.test(aClass); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DependencyPredicate that = (DependencyPredicate) o; + return predicate.getClass().equals(that.predicate); + } + + @Override + public int hashCode() { + return predicate.getClass().hashCode(); + } + } } diff --git a/ext/cdi/pom.xml b/ext/cdi/pom.xml index 853c69ba7b..ba8a50f62e 100644 --- a/ext/cdi/pom.xml +++ b/ext/cdi/pom.xml @@ -36,6 +36,7 @@ jersey-cdi1x jersey-cdi1x-ban-custom-hk2-binding + jersey-cdi-rs-inject jersey-cdi1x-servlet jersey-cdi1x-transaction jersey-cdi1x-validation diff --git a/tests/integration/cdi-integration/context-inject-on-server/pom.xml b/tests/integration/cdi-integration/context-inject-on-server/pom.xml new file mode 100644 index 0000000000..721c0a311f --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/pom.xml @@ -0,0 +1,89 @@ + + + + + 4.0.0 + + org.glassfish.jersey.tests.integration.cdi + cdi-integration-project + 2.34-SNAPSHOT + + + context-inject-on-server + jersey-tests-context-inject-on-server + + CDI works on a client on a server resource + + + + jakarta.ws.rs + jakarta.ws.rs-api + provided + + + jakarta.annotation + jakarta.annotation-api + provided + + + javax.enterprise + cdi-api + 2.0 + provided + + + jakarta.servlet + jakarta.servlet-api + ${servlet4.version} + + + org.glassfish.jersey.test-framework.providers + jersey-test-framework-provider-grizzly2 + test + + + org.glassfish.jersey.ext.cdi + jersey-weld2-se + test + + + org.jboss.weld.se + weld-se-core + + 3.1.7.Final + test + + + org.glassfish.jersey.ext.cdi + jersey-cdi1x + + + org.glassfish.jersey.ext.cdi + jersey-cdi-rs-inject + + + org.glassfish.jersey.media + jersey-media-sse + + + org.glassfish.jersey.containers + jersey-container-servlet-core + + + diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java new file mode 100644 index 0000000000..fc6894a6fc --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ApplicationInjectParent.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.internal.PropertiesDelegate; +import org.glassfish.jersey.servlet.WebConfig; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.container.ResourceContext; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Configuration; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.ext.ParamConverterProvider; +import javax.ws.rs.ext.Providers; +import java.lang.reflect.Field; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +public class ApplicationInjectParent extends Application { + @Context + protected HttpHeaders contextHttpHeaders; + + @Inject + protected HttpHeaders injectHttpHeaders; + + @Context + ParamConverterProvider contextParamConverterProvider; + + @Inject + ParamConverterProvider injectParamConverterProvider; + + @Context + protected Providers contextProviders; + + @Inject + protected Providers injectProviders; + + @Context + protected ResourceContext contextResourceContext; + + @Inject + protected ResourceContext injectResourceContext; + + @Context + protected Request contextRequest; + + @Inject + protected Request injectRequest; + + @Context + protected ResourceInfo contextResourceInfo; + + @Inject + protected ResourceInfo injectResourceInfo; + + @Context + protected SecurityContext contextSecurityContext; + + @Inject + protected SecurityContext injectSecurityContext; + + @Context + protected UriInfo contextUriInfo; + + @Inject + protected UriInfo injectUriInfo; + + @Context + protected HttpServletRequest contextHttpServletRequest; + + @Inject + protected HttpServletRequest injectHttpServletRequest; + + @Context + protected WebConfig contextWebConfig; + + @Inject + protected WebConfig injectWebConfig; + + @Context + protected HttpServletResponse contextHttpServletResponse; + + @Inject + protected HttpServletResponse injectHttpServletResponse; + + @Context + protected ServletConfig contextServletConfig; + + @Inject + protected ServletConfig injectServletConfig; + + @Context + protected ServletContext contextServletContext; + + @Inject + protected ServletContext injectServletContext; + + static class InjectHolder extends ParentInject { + + @Override + protected boolean checkApplication(Application application, StringBuilder stringBuilder) { + return true; + } + + @Override + protected boolean checkConfiguration(Configuration configuration, StringBuilder stringBuilder) { + return true; + } + + @Override + protected boolean checkPropertiesDelegate(PropertiesDelegate propertiesDelegate, StringBuilder stringBuilder) { + return true; + } + }; + + private InjectHolder injectHolder = new InjectHolder(); + + @PostConstruct + void postConstruct() { + try { + setInjectHolder("context"); + setInjectHolder("inject"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void setInjectHolder(String prefix) throws NoSuchFieldException, IllegalAccessException { + for (Field field : ApplicationInjectParent.class.getDeclaredFields()) { + if (field.getType() != InjectHolder.class && field.getName().startsWith(prefix)) { + Field holders = InjectHolder.class.getSuperclass().getDeclaredField(field.getName()); + holders.setAccessible(true); + holders.set(injectHolder, field.get(this)); + } + } + } + + @Override + public Set getSingletons() { + final Set set = new LinkedHashSet<>(); + set.add(injectHolder); + return set; + } + + public static class ResourceParent { + @Context + Application contextApplication; + + @Inject + Application injectApplication; + + @Context + PropertiesDelegate propertiesDelegate; + + @GET + @Path("context") + public Response checkAppContexted() { + return checkApp(true); + } + + @GET + @Path("inject") + public Response checkAppInjected() { + return checkApp(false); + } + + private Response checkApp(boolean contexted) { + StringBuilder sb = new StringBuilder(); + Iterator singletons = contextApplication.getSingletons().iterator(); + final InjectHolder injectHolder = (InjectHolder) singletons.next(); + final boolean injected = contexted ? injectHolder.checkContexted(sb) : injectHolder.checkInjected(sb); + if (injected) { + return Response.ok().entity("All injected").build(); + } else { + propertiesDelegate.setProperty(ParentWriterInterceptor.STATUS, Response.Status.EXPECTATION_FAILED); + return Response.status(Response.Status.EXPECTATION_FAILED).entity(sb.toString()).build(); + } + } + } + +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/InjectionChecker.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/InjectionChecker.java new file mode 100644 index 0000000000..938599f602 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/InjectionChecker.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + + +import org.glassfish.jersey.internal.PropertiesDelegate; +import org.glassfish.jersey.servlet.ServletContainer; +import org.glassfish.jersey.servlet.WebConfig; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.HttpMethod; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ResourceContext; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Configuration; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.ParamConverterProvider; +import javax.ws.rs.ext.Providers; +import java.lang.annotation.Annotation; +import java.util.Iterator; + +class InjectionChecker { + static final String APPLICATION_PROPERTY = "ApplicationProperty"; + static final String HEADER = "HttpHeader"; + static final String ROOT = "resource"; + + static boolean checkApplication(Application application, StringBuilder sb) { + if (application == null) { + sb.append("Application is null."); + return false; + } + if (!application.getProperties().containsKey(APPLICATION_PROPERTY)) { + sb.append("Application does not contain expected key."); + return false; + } + if (!APPLICATION_PROPERTY.equals(application.getProperties().get(APPLICATION_PROPERTY))) { + sb.append("Application does not contain expected value."); + return false; + } + return true; + } + + static boolean checkConfiguration(Configuration configuration, StringBuilder sb) { + if (configuration == null) { + sb.append("Configuration is null."); + return false; + } + if (!configuration.getProperties().containsKey(APPLICATION_PROPERTY)) { + sb.append("Configuration does not contain expected key."); + return false; + } + if (!APPLICATION_PROPERTY.equals(configuration.getProperties().get(APPLICATION_PROPERTY))) { + sb.append("Configuration does not contain expected value."); + return false; + } + return true; + } + + static boolean checkContainerRequestContext(ContainerRequestContext containerRequestContext, StringBuilder sb) { + if (containerRequestContext == null) { + sb.append("ContainerRequestContext is null."); + return false; + } + + return checkRequest(containerRequestContext.getRequest(), sb) && checkUriInfo(containerRequestContext.getUriInfo(), sb); + } + + static boolean checkHttpHeaders(HttpHeaders headers, StringBuilder sb) { + if (headers == null) { + sb.append("HttpHeaders is null."); + return false; + } + if (headers.getHeaderString(HEADER) == null) { + sb.append("HttpHeaders does not contain expected header."); + return false; + } + if (!HEADER.equals(headers.getHeaderString(HEADER))) { + sb.append("HttpHeaders does not contain expected header value."); + return false; + } + return true; + } + + static boolean checkParamConverterProvider(ParamConverterProvider provider, StringBuilder sb) { + if (provider == null) { + sb.append("ParamConverterProvider is null."); + return false; + } + return true; + } + + static boolean checkPropertiesDelegate(PropertiesDelegate propertiesDelegate, StringBuilder sb) { + if (propertiesDelegate == null) { + sb.append("PropertiesDelegate is null."); + return false; + } + if (null == propertiesDelegate.getProperty(APPLICATION_PROPERTY)) { + sb.append("PropertiesDelegate does not contain expected key."); + return false; + } + return true; + } + + static boolean checkProviders(Providers providers, StringBuilder sb) { + if (providers == null) { + sb.append("Providers is null."); + return false; + } + MessageBodyWriter mbw = + providers.getMessageBodyWriter(String.class, String.class, new Annotation[]{}, MediaType.TEXT_PLAIN_TYPE); + if (mbw == null) { + sb.append("String MessageBodyWriter is null."); + return false; + } + return true; + } + + static boolean checkRequest(Request request, StringBuilder sb) { + if (request == null) { + sb.append("Request is null."); + return false; + } + final String method = request.getMethod(); + if (method == null) { + sb.append("Request did not get a method."); + return false; + } + if (!HttpMethod.GET.equals(method)) { + sb.append("Request did not correct method, but ").append(method).append(" ."); + return false; + } + return true; + } + + static boolean checkResourceContext(ResourceContext context, StringBuilder sb) { + if (context == null) { + sb.append("ResourceContext is null."); + return false; + } + ScopedResource resource = context.getResource(ScopedResource.class); + if (resource == null) { + sb.append("ResourceContext did not get the resource."); + return false; + } + return true; + } + + static boolean checkResourceInfo(ResourceInfo info, StringBuilder sb) { + if (info == null) { + sb.append("ResourceInfo is null."); + return false; + } + final Class resourceClass = info.getResourceClass(); + if (resourceClass == null) { + sb.append("ResourceInfo did not get the resource."); + return false; + } + if (!resourceClass.getSimpleName().endsWith("ScopedResource")) { + sb.append("ResourceInfo did not get the proper resource."); + return false; + } + return true; + } + + static boolean checkSecurityContext(SecurityContext context, StringBuilder sb) { + if (context == null) { + sb.append("SecurityContext is null."); + return false; + } + if (context.isSecure()) { + sb.append("SecurityContext returned unexpected security."); + return false; + } + return true; + } + + static boolean checkUriInfo(UriInfo info, StringBuilder sb) { + if (info == null) { + sb.append("UriInfo is null."); + return false; + } + if (!info.getPath().startsWith(ROOT)) { + sb.append("UriInfo does not start with expected ").append(ROOT) + .append(" but it is ").append(info.getPath()).append("."); + } + return true; + } + + static boolean checkWebConfig(WebConfig config, StringBuilder sb) { + if (config == null) { + sb.append("WebConfig is null."); + return false; + } + if (config.getServletContext() == null) { + sb.append("WebConfig#getServletContext() is null."); + return false; + } + if (!checkServletContext(config.getServletContext(), sb)) { + return false; + } + if (!checkServletConfig(config.getServletConfig(), sb)) { + return false; + } + return true; + } + + static boolean checkServletContext(ServletContext context, StringBuilder sb) { + if (context == null) { + sb.append("ServletContext is null."); + return false; + } + if (context.getServletRegistrations() == null) { + sb.append("ServletContext#getServletRegistrations is null."); + return false; + } + Iterator it = context.getServletRegistrations().keySet().iterator(); + if (!it.hasNext()) { + sb.append("ServletContext#getServletRegistrations is empty."); + return false; + } + if (!ServletContainer.class.getName().equals(it.next())) { + sb.append("ServletContext#getServletRegistrations does not contain ServletContainer registration."); + return false; + } + return true; + } + + static boolean checkServletConfig(ServletConfig config, StringBuilder sb) { + if (config == null) { + sb.append("ServletConfig is null."); + return false; + } + if (!ServletContainer.class.getName().equals(config.getServletName())) { + sb.append("ServletConfig has unexpected servlet name ").append(config.getServletName()).append(" ."); + return false; + } + return true; + } + + static boolean checkHttpServletRequest(HttpServletRequest request, StringBuilder sb) { + if (request == null) { + sb.append("HttpServletRequest is null."); + return false; + } + if (request.getHeaderNames() == null) { + sb.append("HttpServletRequest header names is null."); + return false; + } + if (request.getHeader(HEADER) == null) { + sb.append("HttpServletRequest does not contain expected header."); + return false; + } + if (!HEADER.equals(request.getHeader(HEADER))) { + sb.append("HttpServletRequest does not contain expected header value."); + return false; + } + return true; + } + + static boolean checkHttpServletResponse(HttpServletResponse response, StringBuilder sb) { + if (response == null) { + sb.append("HttpServletResponse is null."); + return false; + } + if (response.getStatus() != 200) { + sb.append("HttpServletResponse has unexpectes status."); + return false; + } + return true; + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplication.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplication.java new file mode 100644 index 0000000000..8fd1a0443b --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplication.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; + +public class NonScopedApplication extends ResourceConfig { + public NonScopedApplication() { + register(PropertySettingFilter.class); + register(NonScopedResource.class); + register(NonScopedContainerRequestFilter.class); + register(NonScopedContainerResponseFilter.class); + register(NonScopedExceptionMapper.class); + register(NonScopedWriterInterceptor.class); + property(InjectionChecker.APPLICATION_PROPERTY, InjectionChecker.APPLICATION_PROPERTY); + property(ServerProperties.WADL_FEATURE_DISABLE, true); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInject.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInject.java new file mode 100644 index 0000000000..8d78b90643 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInject.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.ws.rs.Path; +import java.util.Collections; +import java.util.Set; + +public class NonScopedApplicationInject extends ApplicationInjectParent { + @Path(InjectionChecker.ROOT + "/nonscoped") + public static class NonScopedResource extends ApplicationInjectParent.ResourceParent { + + } + + @Override + public Set> getClasses() { + return Collections.singleton(NonScopedResource.class); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerRequestFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerRequestFilter.java new file mode 100644 index 0000000000..efe5bb96df --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerRequestFilter.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +public class NonScopedContainerRequestFilter extends ParentInject implements ParentContainerRequestFilter { +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerResponseFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerResponseFilter.java new file mode 100644 index 0000000000..1601786da5 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedContainerResponseFilter.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +public class NonScopedContainerResponseFilter extends ParentInject implements ParentContainerResponseFilter { + +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedExceptionMapper.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedExceptionMapper.java new file mode 100644 index 0000000000..37a8dfb8a8 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedExceptionMapper.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +public class NonScopedExceptionMapper extends ParentExceptionMapper { +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedResource.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedResource.java new file mode 100644 index 0000000000..fcc866191c --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedResource.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.ws.rs.Path; + + +@Path(InjectionChecker.ROOT + "/nonscope") +public class NonScopedResource extends ParentResource { + +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedWriterInterceptor.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedWriterInterceptor.java new file mode 100644 index 0000000000..b1fc6acd7f --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/NonScopedWriterInterceptor.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import java.net.URI; + +public class NonScopedWriterInterceptor extends ParentInject implements ParentWriterInterceptor { + + @Override + public URI getRequestUri() { + return contextUriInfo.getRequestUri(); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentChecker.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentChecker.java new file mode 100644 index 0000000000..b8314ebf85 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentChecker.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +public interface ParentChecker { + boolean checkInjected(StringBuilder stringBuilder); + boolean checkContexted(StringBuilder stringBuilder); +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java new file mode 100644 index 0000000000..a326454a40 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerRequestFilter.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.Response; +import java.io.IOException; + +public interface ParentContainerRequestFilter extends ParentChecker, ContainerRequestFilter { + + @Override + default void filter(ContainerRequestContext requestContext) throws IOException { + StringBuilder stringBuilder = new StringBuilder(); + boolean injected = false; + + if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("injected")) { + injected = checkInjected(stringBuilder); + } + + if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("contexted")) { + injected = checkContexted(stringBuilder); + } + + if (!injected) { + requestContext.setProperty(ParentWriterInterceptor.STATUS, Response.Status.EXPECTATION_FAILED); + stringBuilder.insert(0, "InjectContainerRequestFilter: "); + requestContext.abortWith( + Response.status(Response.Status.EXPECTATION_FAILED).entity(stringBuilder.toString()).build() + ); + } + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java new file mode 100644 index 0000000000..585f04548b --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentContainerResponseFilter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerResponseContext; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.Response; +import java.io.IOException; + +public interface ParentContainerResponseFilter extends ParentChecker, ContainerResponseFilter { + @Override + default void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { + StringBuilder stringBuilder = new StringBuilder(); + boolean injected = false; + + if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("injected")) { + injected = checkInjected(stringBuilder); + } + + if (requestContext.getUriInfo().getRequestUri().toASCIIString().contains("contexted")) { + injected = checkContexted(stringBuilder); + } + + if (!injected) { + requestContext.setProperty(ParentWriterInterceptor.STATUS, Response.Status.EXPECTATION_FAILED); + stringBuilder.insert(0, "InjectContainerResponseFilter: "); + responseContext.setEntity(stringBuilder.toString()); + responseContext.setStatus(Response.Status.EXPECTATION_FAILED.getStatusCode()); + } + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentExceptionMapper.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentExceptionMapper.java new file mode 100644 index 0000000000..283f9901cc --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentExceptionMapper.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; + +public class ParentExceptionMapper extends RequestScopedParentInject implements ExceptionMapper { + + @Override + public Response toResponse(IllegalArgumentException exception) { + StringBuilder sb = new StringBuilder(); + boolean injected = true; + switch (exception.getMessage()) { + case "inject": + injected = checkInjected(sb); + break; + default: + injected = checkContexted(sb); + break; + } + + if (!injected) { + contextContainerRequestContext.setProperty(ParentWriterInterceptor.STATUS, Response.Status.EXPECTATION_FAILED); + sb.insert(0, exception.getMessage() + "ExceptionMapper: "); + return Response.status(Response.Status.EXPECTATION_FAILED).entity(sb.toString()).build(); + } + return Response.ok("All " + exception.getMessage() + "ed on ExceptionMapper.").build(); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java new file mode 100644 index 0000000000..29e11d81f8 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentInject.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.internal.PropertiesDelegate; +import org.glassfish.jersey.servlet.WebConfig; + +import javax.inject.Inject; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.container.ResourceContext; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Configuration; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.SecurityContext; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.ext.ParamConverterProvider; +import javax.ws.rs.ext.Providers; + +public class ParentInject implements ParentChecker { + @Context + protected Application contextApplication; + + @Inject + protected Application injectApplication; + + @Context + protected Configuration contextConfiguration; + + @Inject + protected Configuration injectConfiguration; + + @Context + protected HttpHeaders contextHttpHeaders; + + @Inject + protected HttpHeaders injectHttpHeaders; + + @Context + protected ParamConverterProvider contextParamConverterProvider; + + @Inject + protected ParamConverterProvider injectParamConverterProvider; + + @Context + protected PropertiesDelegate contextPropertiesDelegate; + + @Inject + protected PropertiesDelegate injectPropertiesDelegate; + + @Context + protected Providers contextProviders; + + @Inject + protected Providers injectProviders; + + @Context + protected ResourceContext contextResourceContext; + + @Inject + protected ResourceContext injectResourceContext; + + @Context + protected Request contextRequest; + + @Inject + protected Request injectRequest; + + @Context + protected ResourceInfo contextResourceInfo; + + @Inject + protected ResourceInfo injectResourceInfo; + + @Context + protected SecurityContext contextSecurityContext; + + @Inject + protected SecurityContext injectSecurityContext; + + @Context + protected UriInfo contextUriInfo; + + @Inject + protected UriInfo injectUriInfo; + + @Context + protected HttpServletRequest contextHttpServletRequest; + + @Inject + protected HttpServletRequest injectHttpServletRequest; + + @Context + protected WebConfig contextWebConfig; + + @Inject + protected WebConfig injectWebConfig; + + @Context + protected HttpServletResponse contextHttpServletResponse; + + @Inject + protected HttpServletResponse injectHttpServletResponse; + + @Context + protected ServletConfig contextServletConfig; + + @Inject + protected ServletConfig injectServletConfig; + + @Context + protected ServletContext contextServletContext; + + @Inject + protected ServletContext injectServletContext; + + @Override + public boolean checkInjected(StringBuilder stringBuilder) { + boolean injected = true; + injected &= checkApplication(injectApplication, stringBuilder); + injected &= checkConfiguration(injectConfiguration, stringBuilder); + injected &= InjectionChecker.checkHttpHeaders(injectHttpHeaders, stringBuilder); + injected &= checkPropertiesDelegate(injectPropertiesDelegate, stringBuilder); + injected &= InjectionChecker.checkParamConverterProvider(injectParamConverterProvider, stringBuilder); + injected &= InjectionChecker.checkProviders(injectProviders, stringBuilder); + injected &= InjectionChecker.checkRequest(injectRequest, stringBuilder); + injected &= InjectionChecker.checkResourceContext(injectResourceContext, stringBuilder); + injected &= InjectionChecker.checkResourceInfo(injectResourceInfo, stringBuilder); + injected &= InjectionChecker.checkSecurityContext(injectSecurityContext, stringBuilder); + injected &= InjectionChecker.checkUriInfo(injectUriInfo, stringBuilder); + + injected &= InjectionChecker.checkHttpServletRequest(injectHttpServletRequest, stringBuilder); + injected &= InjectionChecker.checkHttpServletResponse(injectHttpServletResponse, stringBuilder); + injected &= InjectionChecker.checkWebConfig(injectWebConfig, stringBuilder); + injected &= InjectionChecker.checkServletConfig(injectServletConfig, stringBuilder); + injected &= InjectionChecker.checkServletContext(injectServletContext, stringBuilder); + + return injected; + } + + @Override + public boolean checkContexted(StringBuilder stringBuilder) { + boolean injected = true; + injected &= checkApplication(contextApplication, stringBuilder); + injected &= checkConfiguration(contextConfiguration, stringBuilder); + injected &= InjectionChecker.checkHttpHeaders(contextHttpHeaders, stringBuilder); + injected &= InjectionChecker.checkParamConverterProvider(contextParamConverterProvider, stringBuilder); + injected &= checkPropertiesDelegate(contextPropertiesDelegate, stringBuilder); + injected &= InjectionChecker.checkProviders(contextProviders, stringBuilder); + injected &= InjectionChecker.checkRequest(contextRequest, stringBuilder); + injected &= InjectionChecker.checkResourceContext(contextResourceContext, stringBuilder); + injected &= InjectionChecker.checkResourceInfo(contextResourceInfo, stringBuilder); + injected &= InjectionChecker.checkSecurityContext(contextSecurityContext, stringBuilder); + injected &= InjectionChecker.checkUriInfo(contextUriInfo, stringBuilder); + + injected &= InjectionChecker.checkHttpServletRequest(contextHttpServletRequest, stringBuilder); + injected &= InjectionChecker.checkHttpServletResponse(contextHttpServletResponse, stringBuilder); + injected &= InjectionChecker.checkWebConfig(contextWebConfig, stringBuilder); + injected &= InjectionChecker.checkServletConfig(contextServletConfig, stringBuilder); + injected &= InjectionChecker.checkServletContext(contextServletContext, stringBuilder); + + return injected; + } + + protected boolean checkApplication(Application application, StringBuilder stringBuilder) { + return InjectionChecker.checkApplication(contextApplication, stringBuilder); + } + + protected boolean checkConfiguration(Configuration configuration, StringBuilder stringBuilder) { + return InjectionChecker.checkConfiguration(configuration, stringBuilder); + } + + protected boolean checkPropertiesDelegate(PropertiesDelegate propertiesDelegate, StringBuilder stringBuilder) { + return InjectionChecker.checkPropertiesDelegate(propertiesDelegate, stringBuilder); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentResource.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentResource.java new file mode 100644 index 0000000000..9fd1b976d2 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentResource.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; + +public class ParentResource extends RequestScopedParentInject { + + @Context + ContainerRequestContext requestContext; + + @GET + @Path("injected") + public Response areInjected() { + StringBuilder stringBuilder = new StringBuilder(); + boolean injected = checkInjected(stringBuilder); + + if (injected) { + return Response.ok().entity("All injected").build(); + } else { + requestContext.setProperty(ParentWriterInterceptor.STATUS, Response.Status.EXPECTATION_FAILED); + return Response.status(Response.Status.EXPECTATION_FAILED).entity(stringBuilder.toString()).build(); + } + } + + @GET + @Path("contexted") + public Response areContexted() { + StringBuilder stringBuilder = new StringBuilder(); + boolean contexted = checkContexted(stringBuilder); + + if (contexted) { + return Response.ok().entity("All contexted").build(); + } else { + requestContext.setProperty(ParentWriterInterceptor.STATUS, Response.Status.EXPECTATION_FAILED); + return Response.status(Response.Status.EXPECTATION_FAILED).entity(stringBuilder.toString()).build(); + } + } + + @GET + @Path("iae/{x}") + public Response iae(@PathParam("x") String injected) { + throw new IllegalArgumentException(injected); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentWriterInterceptor.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentWriterInterceptor.java new file mode 100644 index 0000000000..a58d092214 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ParentWriterInterceptor.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.ext.WriterInterceptor; +import javax.ws.rs.ext.WriterInterceptorContext; +import java.io.IOException; +import java.net.URI; + +public interface ParentWriterInterceptor extends ParentChecker, WriterInterceptor { + + static final String STATUS = "status"; + + @Override + default void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { + StringBuilder stringBuilder = new StringBuilder(); + boolean injected = false; + + if (context.getProperty(STATUS) == null) { + if (getRequestUri().toASCIIString().contains("injected")) { + injected = checkInjected(stringBuilder); + } + + if (getRequestUri().toASCIIString().contains("contexted")) { + injected = checkContexted(stringBuilder); + } + + if (injected) { + context.setEntity(context.getEntity().toString().replace("All", "Everything")); + } else { + stringBuilder.insert(0, "InjectWriterInterceptor: "); + context.setEntity(stringBuilder.toString()); + } + } + context.proceed(); + } + + URI getRequestUri(); +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/PropertySettingFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/PropertySettingFilter.java new file mode 100644 index 0000000000..aede0b108b --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/PropertySettingFilter.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.internal.PropertiesDelegate; + +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Context; +import java.io.IOException; + +@PreMatching +public class PropertySettingFilter implements ContainerRequestFilter { + @Context + PropertiesDelegate contextPropertiesDelegate; + + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + contextPropertiesDelegate.setProperty(InjectionChecker.APPLICATION_PROPERTY, InjectionChecker.APPLICATION_PROPERTY); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/RequestScopedParentInject.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/RequestScopedParentInject.java new file mode 100644 index 0000000000..3958ec2fb2 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/RequestScopedParentInject.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.inject.Inject; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.core.Context; + +public abstract class RequestScopedParentInject extends ParentInject { + @Context + ContainerRequestContext contextContainerRequestContext; + + @Inject + ContainerRequestContext injectContainerRequestContext; + + // CDI Scoped only +// @Inject +// protected javax.enterprise.inject.spi.BeanManager beanManager; + + @Override + public boolean checkContexted(StringBuilder stringBuilder) { + boolean contexted = super.checkContexted(stringBuilder); + contexted &= InjectionChecker.checkContainerRequestContext(contextContainerRequestContext, stringBuilder); + return contexted; + } + + @Override + public boolean checkInjected(StringBuilder stringBuilder) { + boolean injected = super.checkInjected(stringBuilder); + injected &= InjectionChecker.checkContainerRequestContext(injectContainerRequestContext, stringBuilder); + return injected; + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplication.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplication.java new file mode 100644 index 0000000000..fa85427256 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplication.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.ServerProperties; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ScopedApplication extends ResourceConfig { + public ScopedApplication() { + register(PropertySettingFilter.class); + register(ScopedResource.class); + register(ScopedContainerRequestFilter.class); + register(ScopedContainerResponseFilter.class); + register(ScopedExceptionMapper.class); + register(ScopedWriterInterceptor.class); + property(InjectionChecker.APPLICATION_PROPERTY, InjectionChecker.APPLICATION_PROPERTY); + property(ServerProperties.WADL_FEATURE_DISABLE, true); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInject.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInject.java new file mode 100644 index 0000000000..d518270ce9 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInject.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.RequestScoped; +import javax.enterprise.inject.Alternative; +import javax.ws.rs.Path; +import java.util.Collections; +import java.util.Set; + +@ApplicationScoped +@Alternative +public class ScopedApplicationInject extends ApplicationInjectParent { + @RequestScoped + @Path(InjectionChecker.ROOT + "/scoped") + public static class ScopedResource extends ResourceParent { + } + + @Override + public Set> getClasses() { + return Collections.singleton(ScopedResource.class); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerRequestFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerRequestFilter.java new file mode 100644 index 0000000000..1fefff505f --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerRequestFilter.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.enterprise.context.RequestScoped; + +@RequestScoped +public class ScopedContainerRequestFilter extends RequestScopedParentInject implements ParentContainerRequestFilter { +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerResponseFilter.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerResponseFilter.java new file mode 100644 index 0000000000..219bf5fb91 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedContainerResponseFilter.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.enterprise.context.RequestScoped; + +@RequestScoped +public class ScopedContainerResponseFilter extends RequestScopedParentInject implements ParentContainerResponseFilter { +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedExceptionMapper.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedExceptionMapper.java new file mode 100644 index 0000000000..a8b5244d5a --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedExceptionMapper.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.enterprise.context.ApplicationScoped; + +@ApplicationScoped +public class ScopedExceptionMapper extends ParentExceptionMapper { +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedResource.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedResource.java new file mode 100644 index 0000000000..c1f07156a6 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedResource.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.enterprise.context.RequestScoped; +import javax.ws.rs.Path; + + +@RequestScoped +@Path(InjectionChecker.ROOT + "/scope") +public class ScopedResource extends ParentResource { + +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedWriterInterceptor.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedWriterInterceptor.java new file mode 100644 index 0000000000..d6c968624d --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/ScopedWriterInterceptor.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import javax.enterprise.context.RequestScoped; +import java.net.URI; + +@RequestScoped +public class ScopedWriterInterceptor extends RequestScopedParentInject implements ParentWriterInterceptor { + @Override + public URI getRequestUri() { + return injectUriInfo.getRequestUri(); + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/SseAplication.java b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/SseAplication.java new file mode 100644 index 0000000000..df402b134c --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/java/org/glassfish/jersey/tests/cdi/inject/SseAplication.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.server.ServerProperties; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.sse.Sse; +import javax.ws.rs.sse.SseBroadcaster; +import javax.ws.rs.sse.SseEventSink; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class SseAplication extends Application { + + @Path(InjectionChecker.ROOT) + @ApplicationScoped + public static class ApplicationScopedResource { + @Context + Sse contextSse; + + @Inject + Sse injectSse; + + private static SseBroadcaster contextSseBroadcaster; + private static SseBroadcaster injectSseBroadcaster; + + @GET + @Path("register/{x}") + @Produces(MediaType.SERVER_SENT_EVENTS) + public void register(@PathParam("x") String inject, @Context SseEventSink eventSink) { + if (inject.contains("context")) { + contextSseBroadcaster = contextSse.newBroadcaster(); + contextSseBroadcaster.register(eventSink); + eventSink.send(contextSse.newEvent(inject)); + } else { + injectSseBroadcaster = injectSse.newBroadcaster(); + injectSseBroadcaster.register(eventSink); + eventSink.send(injectSse.newEvent(inject)); + } + } + + @POST + @Path("broadcast/{x}") + @Consumes(MediaType.MULTIPART_FORM_DATA) + public void broadcast(@PathParam("x") String inject, String event) { + if (inject.contains("context")) { + if (contextSseBroadcaster == null) { + throw new IllegalStateException("contextSseBroadcaster is null"); + } else if (contextSse == null) { + throw new IllegalStateException("contextSse is null"); + } + contextSseBroadcaster.broadcast(contextSse.newEvent(event)); + contextSseBroadcaster.close(); + } else { + if (injectSseBroadcaster == null) { + throw new IllegalStateException("injectSseBroadcaster is null"); + } else if (injectSse == null) { + throw new IllegalStateException("injectSse is null"); + } + injectSseBroadcaster.broadcast(injectSse.newEvent(event)); + injectSseBroadcaster.close(); + } + } + } + + @Override + public Set> getClasses() { + return Collections.singleton(ApplicationScopedResource.class); + } + + @Override + public Map getProperties() { + Map props = new HashMap<>(1); + props.put(ServerProperties.WADL_FEATURE_DISABLE, true); + return props; + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/main/resources/META-INF/beans.xml b/tests/integration/cdi-integration/context-inject-on-server/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000..70897bddc7 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/main/resources/META-INF/beans.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInjectTest.java b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInjectTest.java new file mode 100644 index 0000000000..95c0ae1292 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedApplicationInjectTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; +import org.glassfish.jersey.servlet.ServletProperties; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.ServletDeploymentContext; +import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.jboss.weld.environment.se.Weld; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; + +public class NonScopedApplicationInjectTest extends JerseyTest { + private Weld weld; + + @Before + public void setup() { + Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy()); + } + + @Override + public void setUp() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld = new Weld(); + weld.initialize(); + super.setUp(); + } + } + + @Override + public void tearDown() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld.shutdown(); + super.tearDown(); + } + } + + @Override + protected Application configure() { + return new NonScopedApplicationInject(); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + return new GrizzlyWebTestContainerFactory(); + } + + @Override + protected DeploymentContext configureDeployment() { + return ServletDeploymentContext.builder(configure()) + .initParam(ServletProperties.JAXRS_APPLICATION_CLASS, NonScopedApplicationInject.class.getName()) + .build(); + } + + @Test + public void testIsInjectedOnApplication() { + try (Response r = target(InjectionChecker.ROOT).path("nonscoped").path("inject").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsContextedOnApplication() { + try (Response r = target(InjectionChecker.ROOT).path("nonscoped").path("context").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedInjectionTest.java b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedInjectionTest.java new file mode 100644 index 0000000000..acb77b4088 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/NonScopedInjectionTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; +import org.glassfish.jersey.servlet.ServletProperties; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.ServletDeploymentContext; +import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.jboss.weld.environment.se.Weld; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; + +public class NonScopedInjectionTest extends JerseyTest { + private Weld weld; + + @Before + public void setup() { + Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy()); + } + + @Override + public void setUp() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld = new Weld(); + weld.initialize(); + super.setUp(); + } + } + + @Override + public void tearDown() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld.shutdown(); + super.tearDown(); + } + } + + @Override + protected Application configure() { + return new NonScopedApplication(); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + return new GrizzlyWebTestContainerFactory(); + } + + @Override + protected DeploymentContext configureDeployment() { + return ServletDeploymentContext.builder(configure()) +// .initParam(ServerProperties.PROVIDER_PACKAGES, this.getClass().getPackage().getName()) + .initParam(ServletProperties.JAXRS_APPLICATION_CLASS, NonScopedApplication.class.getName()) + .build(); + } + + @Test + public void testIsInjectedOnResource() { + try (Response r = target(InjectionChecker.ROOT).path("nonscope").path("injected").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsContextedOnResource() { + try (Response r = target(InjectionChecker.ROOT).path("nonscope").path("contexted").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testNegativeContext() { + try (Response r = target(InjectionChecker.ROOT).path("nonexisting").path("contexted").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.EXPECTATION_FAILED.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testNegativeInject() { + try (Response r = target(InjectionChecker.ROOT).path("nonexisting").path("injected").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.EXPECTATION_FAILED.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsInjectedMapper() { + try (Response r = target(InjectionChecker.ROOT).path("nonscope").path("iae").path("injected").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsContextedMapper() { + try (Response r = target(InjectionChecker.ROOT).path("nonscope").path("iae").path("contexted").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInjectTest.java b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInjectTest.java new file mode 100644 index 0000000000..155c80a6ee --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedApplicationInjectTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; +import org.glassfish.jersey.servlet.ServletProperties; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.ServletDeploymentContext; +import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.jboss.weld.environment.se.Weld; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; + +public class ScopedApplicationInjectTest extends JerseyTest { + private Weld weld; + + @Before + public void setup() { + Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy()); + } + + @Override + public void setUp() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld = new Weld(); + weld.initialize(); + super.setUp(); + } + } + + @Override + public void tearDown() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld.shutdown(); + super.tearDown(); + } + } + + @Override + protected Application configure() { + return new ScopedApplicationInject(); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + return new GrizzlyWebTestContainerFactory(); + } + + @Override + protected DeploymentContext configureDeployment() { + return ServletDeploymentContext.builder(configure()) + .initParam(ServletProperties.JAXRS_APPLICATION_CLASS, ScopedApplicationInject.class.getName()) + .build(); + } + + @Test + public void testIsInjectedOnApplication() { + try (Response r = target(InjectionChecker.ROOT).path("scoped").path("inject").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsContextedOnApplication() { + try (Response r = target(InjectionChecker.ROOT).path("scoped").path("context").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedInjectionTest.java b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedInjectionTest.java new file mode 100644 index 0000000000..fc15cb147a --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/ScopedInjectionTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; +import org.glassfish.jersey.servlet.ServletProperties; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.ServletDeploymentContext; +import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.jboss.weld.environment.se.Weld; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; + +public class ScopedInjectionTest extends JerseyTest { + private Weld weld; + + @Before + public void setup() { + Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy()); + } + + @Override + public void setUp() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld = new Weld(); + weld.initialize(); + super.setUp(); + } + } + + @Override + public void tearDown() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld.shutdown(); + super.tearDown(); + } + } + + @Override + protected Application configure() { + return new ScopedApplication(); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + return new GrizzlyWebTestContainerFactory(); + } + + @Override + protected DeploymentContext configureDeployment() { + return ServletDeploymentContext.builder(configure()) + .initParam(ServletProperties.JAXRS_APPLICATION_CLASS, ScopedApplication.class.getName()) + .build(); + } + + @Test + public void testIsInjectedOnResource() { + try (Response r = target(InjectionChecker.ROOT).path("scope").path("injected").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsContextedOnResource() { + try (Response r = target(InjectionChecker.ROOT).path("scope").path("contexted").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testNegativeContext() { + try (Response r = target(InjectionChecker.ROOT).path("nonexisting").path("contexted").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.EXPECTATION_FAILED.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testNegativeInject() { + try (Response r = target(InjectionChecker.ROOT).path("nonexisting").path("injected").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.EXPECTATION_FAILED.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsInjectedMapper() { + try (Response r = target(InjectionChecker.ROOT).path("scope").path("iae").path("injected").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } + + @Test + public void testIsContextedMapper() { + try (Response r = target(InjectionChecker.ROOT).path("scope").path("iae").path("contexted").request() + .header(InjectionChecker.HEADER, InjectionChecker.HEADER).get()) { + System.out.println(r.readEntity(String.class)); + Assert.assertEquals(Response.Status.OK.getStatusCode(), r.getStatus()); + } + } +} diff --git a/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/SseTest.java b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/SseTest.java new file mode 100644 index 0000000000..331cf3b512 --- /dev/null +++ b/tests/integration/cdi-integration/context-inject-on-server/src/test/java/org/glassfish/jersey/tests/cdi/inject/SseTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.tests.cdi.inject; + +import org.glassfish.jersey.inject.hk2.Hk2InjectionManagerFactory; +import org.glassfish.jersey.servlet.ServletProperties; +import org.glassfish.jersey.test.DeploymentContext; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.ServletDeploymentContext; +import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; +import org.glassfish.jersey.test.spi.TestContainerException; +import org.glassfish.jersey.test.spi.TestContainerFactory; +import org.jboss.weld.environment.se.Weld; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.sse.SseEventSource; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class SseTest extends JerseyTest { + private Weld weld; + + @Before + public void setup() { + Assume.assumeTrue(Hk2InjectionManagerFactory.isImmediateStrategy()); + } + + @Override + public void setUp() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld = new Weld(); + weld.initialize(); + super.setUp(); + } + } + + @Override + public void tearDown() throws Exception { + if (Hk2InjectionManagerFactory.isImmediateStrategy()) { + weld.shutdown(); + super.tearDown(); + } + } + + @Override + protected Application configure() { + return new SseAplication(); + } + + @Override + protected TestContainerFactory getTestContainerFactory() throws TestContainerException { + return new GrizzlyWebTestContainerFactory(); + } + + @Override + protected DeploymentContext configureDeployment() { + return ServletDeploymentContext.builder(configure()) + .initParam(ServletProperties.JAXRS_APPLICATION_CLASS, SseAplication.class.getName()) + .build(); + } + + @Test + public void testContextSse() throws InterruptedException { + testSse("contexted"); + } + + @Test + public void testInjectSse() throws InterruptedException { + testSse("injected"); + } + + private void testSse(String injectType) throws InterruptedException { + final String entity = "Everyone !!!"; + final CountDownLatch broadcastLatch = new CountDownLatch(2); + final CountDownLatch registerLatch = new CountDownLatch(1); + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + final WebTarget target = target(InjectionChecker.ROOT).path("register").path(injectType); + try (SseEventSource source = SseEventSource.target(target).build()) { + source.register(inboundSseEvent -> { + try { + byteArrayOutputStream.write(inboundSseEvent.readData(String.class).getBytes()); + registerLatch.countDown(); + broadcastLatch.countDown(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + source.open(); + registerLatch.await(5000, TimeUnit.MILLISECONDS); + Assert.assertEquals(0, registerLatch.getCount()); + + try (Response response = target(InjectionChecker.ROOT).path("broadcast").path(injectType) + .request() + .post(Entity.entity(entity, MediaType.MULTIPART_FORM_DATA_TYPE))) { + String readEntity = response.readEntity(String.class); + // System.out.println(readEntity); + Assert.assertEquals(readEntity, response.getStatus(), Response.Status.NO_CONTENT.getStatusCode()); + + } + broadcastLatch.await(5000, TimeUnit.MILLISECONDS); + } + Assert.assertTrue(byteArrayOutputStream.toString().contains(entity)); + Assert.assertEquals(0, broadcastLatch.getCount()); + } +} diff --git a/tests/integration/cdi-integration/pom.xml b/tests/integration/cdi-integration/pom.xml index abb646817c..f050fb4054 100644 --- a/tests/integration/cdi-integration/pom.xml +++ b/tests/integration/cdi-integration/pom.xml @@ -45,6 +45,7 @@ cdi-with-jersey-injection-custom-cfg-webapp cdi-with-jersey-injection-custom-hk2-banned-webapp cdi-with-jersey-injection-webapp + context-inject-on-server From fecc6f003ad984a797b6d3bb4b8c9d1e71992707 Mon Sep 17 00:00:00 2001 From: jansupol Date: Thu, 15 Apr 2021 19:23:00 +0200 Subject: [PATCH 4/5] Updated properties for netty connection pooling Signed-off-by: jansupol --- .../connector/NettyClientProperties.java | 12 ++++++++-- .../netty/connector/NettyConnector.java | 23 +++++++++++-------- .../netty/connector/localization.properties | 5 ++-- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java index 3ee79d7839..17e55a937a 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyClientProperties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -29,11 +29,19 @@ public class NettyClientProperties { /** *

* This property determines the maximum number of idle connections that will be simultaneously kept alive - * in total, rather than per destination. The default is 60. + * in total, rather than per destination. The default is 60. Specify 0 to disable. *

*/ public static final String MAX_CONNECTIONS_TOTAL = "jersey.config.client.maxTotalConnections"; + /** + *

+ * This property determines the number of seconds the idle connections are kept in the pool before pruned. + * The default is 60. Specify 0 to disable. + *

+ */ + public static final String IDLE_CONNECTION_PRUNE_TIMEOUT = "jersey.config.client.idleConnectionPruneTimeout"; + /** *

* This property determines the maximum number of idle connections that will be simultaneously kept alive, per destination. diff --git a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java index c2fdf410a5..f941e66572 100644 --- a/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java +++ b/connectors/netty-connector/src/main/java/org/glassfish/jersey/netty/connector/NettyConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -94,9 +94,12 @@ class NettyConnector implements Connector { // http.maxConnections (default: 5) private static final int DEFAULT_MAX_POOL_SIZE = 5; private static final int MAX_POOL_SIZE = Integer.getInteger("http.maxConnections", DEFAULT_MAX_POOL_SIZE); - private static final int MAX_POOL_IDLE = 60; + private static final int DEFAULT_MAX_POOL_IDLE = 60; // seconds + private static final int DEFAULT_MAX_POOL_SIZE_TOTAL = 60; // connections + private final Integer maxPoolSize; // either from system property, or from Jersey config, or default + private final Integer maxPoolSizeTotal; //either from Jersey config, or default private final Integer maxPoolIdle; // either from Jersey config, or default private static final String INACTIVE_POOLED_CONNECTION_HANDLER = "inactive_pooled_connection_handler"; @@ -119,20 +122,22 @@ class NettyConnector implements Connector { this.client = client; - final Object maxPoolIdleProperty = properties.get(NettyClientProperties.MAX_CONNECTIONS_TOTAL); + final Object maxPoolSizeTotalProperty = properties.get(NettyClientProperties.MAX_CONNECTIONS_TOTAL); + final Object maxPoolIdleProperty = properties.get(NettyClientProperties.IDLE_CONNECTION_PRUNE_TIMEOUT); final Object maxPoolSizeProperty = properties.get(NettyClientProperties.MAX_CONNECTIONS); - maxPoolIdle = maxPoolIdleProperty != null ? (Integer) maxPoolIdleProperty : MAX_POOL_IDLE; + maxPoolSizeTotal = maxPoolSizeTotalProperty != null ? (Integer) maxPoolSizeTotalProperty : DEFAULT_MAX_POOL_SIZE_TOTAL; + maxPoolIdle = maxPoolIdleProperty != null ? (Integer) maxPoolIdleProperty : DEFAULT_MAX_POOL_IDLE; maxPoolSize = maxPoolSizeProperty != null ? (Integer) maxPoolSizeProperty : (HTTP_KEEPALIVE ? MAX_POOL_SIZE : DEFAULT_MAX_POOL_SIZE); - if (maxPoolIdle == null || maxPoolIdle < 0) { - throw new ProcessingException(LocalizationMessages.WRONG_MAX_POOL_IDLE(maxPoolIdle)); + if (maxPoolSizeTotal < 0) { + throw new ProcessingException(LocalizationMessages.WRONG_MAX_POOL_TOTAL(maxPoolSizeTotal)); } - if (maxPoolSize == null || maxPoolSize < 0) { - throw new ProcessingException(LocalizationMessages.WRONG_MAX_POOL_SIZE(maxPoolIdle)); + if (maxPoolSize < 0) { + throw new ProcessingException(LocalizationMessages.WRONG_MAX_POOL_SIZE(maxPoolSize)); } } @@ -270,7 +275,7 @@ protected void initChannel(SocketChannel ch) throws Exception { connections.put(key, conns1); } else { synchronized (conns1) { - if (conns1.size() < maxPoolSize) { + if ((maxPoolSizeTotal == 0 || connections.size() < maxPoolSizeTotal) && conns1.size() < maxPoolSize) { conns1.add(ch); } else { // else do not add the Channel to the idle pool added = false; diff --git a/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties b/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties index 8f9bf8f70e..bf12db6c02 100644 --- a/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties +++ b/connectors/netty-connector/src/main/resources/org/glassfish/jersey/netty/connector/localization.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2020 Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved. # # This program and the accompanying materials are made available under the # terms of the Eclipse Public License v. 2.0, which is available at @@ -17,5 +17,6 @@ wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI. wrong.read.timeout=Unexpected ("{0}") READ_TIMEOUT. wrong.max.pool.size=Unexpected ("{0}") maximum number of connections per destination. -wrong.max.pool.idle=Unexpected ("{0}") maximum number of connections total. +wrong.max.pool.total=Unexpected ("{0}") maximum number of connections total. +wrong.max.pool.idle=Unexpected ("{0}") maximum number of idle seconds. From ab9622bc89c59f08b722f2e6ef5c800e22d0b2c2 Mon Sep 17 00:00:00 2001 From: Maxim Nesen <24524084+senivam@users.noreply.github.com> Date: Fri, 16 Apr 2021 21:19:13 +0200 Subject: [PATCH 5/5] Javadoc for non-public classes (cdi-rs-inject) (#4770) Signed-off-by: Maxim Nesen --- ext/cdi/jersey-cdi-rs-inject/pom.xml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ext/cdi/jersey-cdi-rs-inject/pom.xml b/ext/cdi/jersey-cdi-rs-inject/pom.xml index a2720f61fc..9ee1a48273 100644 --- a/ext/cdi/jersey-cdi-rs-inject/pom.xml +++ b/ext/cdi/jersey-cdi-rs-inject/pom.xml @@ -47,4 +47,16 @@ - \ No newline at end of file + + + + org.apache.maven.plugins + maven-javadoc-plugin + + package + + + + + +