You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwebbeans.apache.org by rm...@apache.org on 2018/03/10 16:01:24 UTC
svn commit: r1826411 - in /openwebbeans/meecrowave/trunk/meecrowave-core/src:
main/java/org/apache/meecrowave/ main/java/org/apache/meecrowave/cxf/
test/java/org/apache/meecrowave/cxf/
Author: rmannibucau
Date: Sat Mar 10 16:01:24 2018
New Revision: 1826411
URL: http://svn.apache.org/viewvc?rev=1826411&view=rev
Log:
MEECROWAVE-104 untrack jsonb instance for client jsonbjaxrsproviders
Added:
openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListener.java
openwebbeans/meecrowave/trunk/meecrowave-core/src/test/java/org/apache/meecrowave/cxf/
openwebbeans/meecrowave/trunk/meecrowave-core/src/test/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListenerTest.java
Modified:
openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java
openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/ConfigurableBus.java
Modified: openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java?rev=1826411&r1=1826410&r2=1826411&view=diff
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java (original)
+++ openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/Meecrowave.java Sat Mar 10 16:01:24 2018
@@ -103,6 +103,7 @@ import org.apache.meecrowave.api.StartLi
import org.apache.meecrowave.api.StopListening;
import org.apache.meecrowave.cxf.ConfigurableBus;
import org.apache.meecrowave.cxf.CxfCdiAutoSetup;
+import org.apache.meecrowave.cxf.MeecrowaveClientLifecycleListener;
import org.apache.meecrowave.io.IO;
import org.apache.meecrowave.logging.jul.Log4j2Logger;
import org.apache.meecrowave.logging.log4j2.Log4j2Shutdown;
@@ -655,6 +656,7 @@ public class Meecrowave implements AutoC
clientBus = new ConfigurableBus();
clientBus.initProviders(configuration,
ofNullable(Thread.currentThread().getContextClassLoader()).orElseGet(ClassLoader::getSystemClassLoader));
+ clientBus.addClientLifecycleListener();
}
try {
Modified: openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/ConfigurableBus.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/ConfigurableBus.java?rev=1826411&r1=1826410&r2=1826411&view=diff
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/ConfigurableBus.java (original)
+++ openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/ConfigurableBus.java Sat Mar 10 16:01:24 2018
@@ -66,6 +66,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.apache.cxf.bus.extension.ExtensionManagerBus;
+import org.apache.cxf.bus.managers.ClientLifeCycleManagerImpl;
+import org.apache.cxf.endpoint.ClientLifeCycleManager;
import org.apache.johnzon.core.AbstractJsonFactory;
import org.apache.johnzon.core.JsonGeneratorFactoryImpl;
import org.apache.johnzon.core.JsonParserFactoryImpl;
@@ -147,6 +149,15 @@ public class ConfigurableBus extends Ext
}
}
+ public void addClientLifecycleListener() {
+ ClientLifeCycleManager manager = getExtension(ClientLifeCycleManager.class);
+ if (manager == null) {
+ manager = new ClientLifeCycleManagerImpl();
+ setExtension(manager, ClientLifeCycleManager.class);
+ }
+ manager.registerListener(new MeecrowaveClientLifecycleListener());
+ }
+
@Provider
@Produces({MediaType.APPLICATION_JSON, "*/*+json"})
@Consumes({MediaType.APPLICATION_JSON, "*/*+json"})
@@ -174,6 +185,10 @@ public class ConfigurableBus extends Ext
setPretty(pretty);
}
+ public Jsonb getProvider() {
+ return delegate.get();
+ }
+
protected Jsonb createJsonb() {
return JsonbBuilder.newBuilder()
.withProvider(provider)
Added: openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListener.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListener.java?rev=1826411&view=auto
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListener.java (added)
+++ openwebbeans/meecrowave/trunk/meecrowave-core/src/main/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListener.java Sat Mar 10 16:01:24 2018
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.meecrowave.cxf;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.enterprise.inject.spi.CDI;
+import javax.json.bind.Jsonb;
+
+import org.apache.cxf.endpoint.Client;
+import org.apache.cxf.endpoint.ClientLifeCycleListener;
+import org.apache.cxf.jaxrs.client.ClientProviderFactory;
+import org.apache.cxf.jaxrs.model.ProviderInfo;
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.johnzon.jaxrs.jsonb.jaxrs.JsonbJaxrsProvider;
+import org.apache.johnzon.jsonb.JohnzonJsonb;
+import org.apache.johnzon.jsonb.cdi.JohnzonCdiExtension;
+import org.apache.meecrowave.logging.tomcat.LogFacade;
+
+// ensure client providers don't leak if the user relies on johnzon JsonbJaxrsProvider
+// in a scope < application (see JohnzonCdiExtension integration)
+public class MeecrowaveClientLifecycleListener implements ClientLifeCycleListener {
+ private final Method getReadersWriters;
+ private final Field delegate;
+
+ public MeecrowaveClientLifecycleListener() {
+ try {
+ getReadersWriters = ProviderFactory.class.getDeclaredMethod("getReadersWriters");
+ getReadersWriters.setAccessible(true);
+ } catch (final NoSuchMethodException e) {
+ throw new IllegalArgumentException("Incompatible cxf version detected", e);
+ }
+ try {
+ delegate = JsonbJaxrsProvider.class.getDeclaredField("delegate");
+ delegate.setAccessible(true);
+ } catch (final NoSuchFieldException e) {
+ throw new IllegalArgumentException("Incompatible johnzon version detected", e);
+ }
+ }
+
+ @Override
+ public void clientCreated(final Client client) {
+ // no-op
+ }
+
+ @Override
+ public void clientDestroyed(final Client client) {
+ try {
+ final ClientProviderFactory cpf = ClientProviderFactory.class.cast(
+ client.getEndpoint().get(ClientProviderFactory.class.getName()));
+ final Collection<Object> invoke = Collection.class.cast(getReadersWriters.invoke(cpf));
+ invoke.stream()
+ .map(p -> ProviderInfo.class.isInstance(p) ? ProviderInfo.class.cast(p).getProvider() : p)
+ .filter(p -> !ConfigurableBus.ConfiguredJsonbJaxrsProvider.class.isInstance(p) && JsonbJaxrsProvider.class.isInstance(p))
+ .map(JsonbJaxrsProvider.class::cast)
+ .map(p -> {
+ try {
+ return ((AtomicReference<Jsonb>) delegate.get(p)).get();
+ } catch (final IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ }
+ })
+ .filter(Objects::nonNull)
+ .filter(JohnzonJsonb.class::isInstance)
+ .map(JohnzonJsonb.class::cast)
+ .distinct()
+ .forEach(jsonb -> CDI.current().select(JohnzonCdiExtension.class).get().untrack(jsonb));
+ } catch (final RuntimeException re) {
+ new LogFacade(MeecrowaveClientLifecycleListener.class.getName())
+ .debug(re.getMessage(), re);
+ } catch (final Exception re) { // reflection etc which shouldn't fail
+ new LogFacade(MeecrowaveClientLifecycleListener.class.getName())
+ .error(re.getMessage(), re);
+ }
+ }
+}
Added: openwebbeans/meecrowave/trunk/meecrowave-core/src/test/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListenerTest.java
URL: http://svn.apache.org/viewvc/openwebbeans/meecrowave/trunk/meecrowave-core/src/test/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListenerTest.java?rev=1826411&view=auto
==============================================================================
--- openwebbeans/meecrowave/trunk/meecrowave-core/src/test/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListenerTest.java (added)
+++ openwebbeans/meecrowave/trunk/meecrowave-core/src/test/java/org/apache/meecrowave/cxf/MeecrowaveClientLifecycleListenerTest.java Sat Mar 10 16:01:24 2018
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.meecrowave.cxf;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.Collection;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.CDI;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.johnzon.jaxrs.jsonb.jaxrs.JsonbJaxrsProvider;
+import org.apache.johnzon.jsonb.cdi.JohnzonCdiExtension;
+import org.apache.meecrowave.Meecrowave;
+import org.junit.Test;
+
+public class MeecrowaveClientLifecycleListenerTest {
+ @Test
+ public void autoClose() throws IOException, NoSuchFieldException, IllegalAccessException {
+ try (final Meecrowave meecrowave = new Meecrowave(new Meecrowave.Builder()
+ .randomHttpPort()
+ .includePackages(MeecrowaveClientLifecycleListenerTest.class.getName())).bake()) {
+ final JohnzonCdiExtension johnzonCdiExtension = CDI.current().select(JohnzonCdiExtension.class).get();
+ final Field jsonbs = JohnzonCdiExtension.class.getDeclaredField("jsonbs");
+ jsonbs.setAccessible(true);
+ final BeanManager beanManager = CDI.current().getBeanManager();
+ final JohnzonCdiExtension extensionInstance = JohnzonCdiExtension.class.cast(beanManager.getContext(ApplicationScoped.class).get(
+ beanManager.resolve(beanManager.getBeans(JohnzonCdiExtension.class))));
+ final Collection<?> o = Collection.class.cast(jsonbs.get(extensionInstance));
+
+ { // ensure server is init whatever test suite we run in
+ final Client client = ClientBuilder.newClient();
+ get(meecrowave, client);
+ client.close();
+ }
+
+ final int origin = o.size();
+ final Client client = ClientBuilder.newClient();
+ final JsonbJaxrsProvider<?> provider = new JsonbJaxrsProvider<>();
+ client.register(provider);
+ get(meecrowave, client);
+ assertEquals(origin + 1, o.size());
+ client.close();
+ assertEquals(origin, o.size());
+ }
+ }
+
+ private void get(final Meecrowave meecrowave, final Client client) {
+ client.target("http://localhost:" + meecrowave.getConfiguration().getHttpPort() + "/MeecrowaveClientLifecycleListenerTest")
+ .request(MediaType.APPLICATION_JSON_TYPE)
+ .get(Foo.class);
+ }
+
+ @Path("MeecrowaveClientLifecycleListenerTest")
+ @ApplicationScoped
+ public static class Endpoint {
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Foo get() {
+ return new Foo();
+ }
+ }
+
+ public static class Foo {
+ }
+}