Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CUSTCOM-70 Additional Fix to JAXRS Client With Embedded Dependency #4491

Merged
merged 2 commits into from
Feb 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,111 +40,125 @@

package fish.payara.requesttracing.jaxrs.client;

import fish.payara.nucleus.requesttracing.RequestTracingService;
import fish.payara.opentracing.OpenTracingService;

import io.opentracing.Tracer;

import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.Globals;
import org.glassfish.internal.deployment.Deployment;

import fish.payara.nucleus.requesttracing.RequestTracingService;
import fish.payara.opentracing.OpenTracingService;
import io.opentracing.Tracer;

/**
* This is a class hiding internal mechanism of lookup of HK2 services.
* The lookup is lazy, done with first request, but this may be simply changed later.
* <p>
* The lazy lookup prevents problems with embedded distributions, when jersey lookups
* may detect filters in this package and try to use them before Payara started, which
* is not supported use case.
* This is a class hiding internal mechanism of lookup of HK2 services. The
* required services will be eagerly initialised using their service handles,
* and throwing an exception if the handle is available but not the service
* itself.
*
* @author David Matejcek
*/
public final class PayaraTracingServices {

private static volatile boolean initialized;
private final RequestTracingService requestTracingService;
private final OpenTracingService openTracingService;

private static ServiceLocator basicServiceLocator;
private static RequestTracingService requestTracingService;
private static OpenTracingService openTracingService;
private final InvocationManager invocationManager;
private final Deployment deployment;

/**
* Initialise the tracing services if they are available.
*
* @throws RuntimeException if an exception occurs initialising the services.
*/
public PayaraTracingServices() {
final ServiceLocator baseServiceLocator = Globals.getStaticBaseServiceLocator();

private static void checkInitialized() {
if (initialized) {
return;
}
synchronized (PayaraTracingServices.class) {
if (initialized) {
return;
}
basicServiceLocator = Globals.getStaticBaseServiceLocator();
requestTracingService = basicServiceLocator.getService(RequestTracingService.class);
openTracingService = basicServiceLocator.getService(OpenTracingService.class);
initialized = true;
}
requestTracingService = getFromServiceHandle(baseServiceLocator, RequestTracingService.class);
openTracingService = getFromServiceHandle(baseServiceLocator, OpenTracingService.class);
invocationManager = getFromServiceHandle(baseServiceLocator, InvocationManager.class);
deployment = getFromServiceHandle(baseServiceLocator, Deployment.class);
}


/**
* @return default service locator, same as {@link Globals#getStaticBaseServiceLocator()}.
* @return true if the Request Tracing services are available and have been
* initialised, or false if the services are not available.
*/
public ServiceLocator getBasicServiceLocator() {
checkInitialized();
return basicServiceLocator;
public boolean isTracingAvailable() {
return requestTracingService != null && openTracingService != null;
}


/**
* @return {@link RequestTracingService}
* @return {@link RequestTracingService}, or null if the HK2 service couldn't be
* initialised.
*/
public RequestTracingService getRequestTracingService() {
checkInitialized();
return requestTracingService;
if (isTracingAvailable()) {
return requestTracingService;
}
return null;
}


/**
* @return {@link OpenTracingService}
* @return {@link OpenTracingService}, or null if the HK2 service couldn't be
* initialised.
*/
public OpenTracingService getOpenTracingService() {
checkInitialized();
return openTracingService;
if (isTracingAvailable()) {
return openTracingService;
}
return null;
}


/**
* @return {@link InvocationManager}
*/
public InvocationManager getInvocationManager() {
checkInitialized();
return basicServiceLocator.getService(InvocationManager.class);
return invocationManager;
}

/**
* @return {@link Deployment}
*/
public Deployment getDeployment() {
return deployment;
}

/**
* @return application name known to the actual {@link InvocationManager}.
* @return application name known to the actual {@link InvocationManager}, or
* null if no invocation manager can be found.
*/
public String getApplicationName() {
final InvocationManager invocationManager = getInvocationManager();
if (invocationManager == null) {
return null;
if (isTracingAvailable()) {
return openTracingService.getApplicationName(invocationManager);
}
final OpenTracingService otService = getOpenTracingService();
return otService == null ? null : otService.getApplicationName(invocationManager);
return null;
}


/**
* @return actually active {@link Tracer} for the current application.
* @return actually active {@link Tracer} for the current application, or null
* if the tracing service is not available.
*/
public Tracer getActiveTracer() {
final String applicationName = getApplicationName();
if (applicationName == null) {
if (applicationName == null || !isTracingAvailable()) {
return null;
}
final OpenTracingService otService = getOpenTracingService();
if (otService == null) {
return null;
return openTracingService.getTracer(applicationName);
}

/**
* Create a service from the given service locator. Throw an exception if the
* service handle is available but not the service.
*
* @return the specified service, or null if the service handle isn't available.
* @throws RuntimeException if the service initialisation failed.
*/
private static final <T> T getFromServiceHandle(ServiceLocator serviceLocator, Class<T> serviceClass) {
ServiceHandle<T> serviceHandle = serviceLocator.getServiceHandle(serviceClass);
if (serviceHandle != null && serviceHandle.isActive()) {
return serviceHandle.getService();
}
return otService.getTracer(applicationName);
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,13 @@
*/
package fish.payara.microprofile.opentracing.jaxrs;

import fish.payara.requesttracing.jaxrs.client.PayaraTracingServices;

import javax.ws.rs.core.FeatureContext;

import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.jersey.internal.spi.ForcedAutoDiscoverable;

import fish.payara.requesttracing.jaxrs.client.PayaraTracingServices;

/**
* AutoDiscoverable that registers the {@link OpenTracingApplicationEventListener}.
*
Expand All @@ -58,8 +57,8 @@ public class JerseyOpenTracingAutoDiscoverable implements ForcedAutoDiscoverable
@Override
public void configure(FeatureContext context) {
// Only register for application deployments (not the admin console)
final ServiceLocator serviceLocator = new PayaraTracingServices().getBasicServiceLocator();
if (serviceLocator.getService(Deployment.class).getCurrentDeploymentContext() == null) {
final Deployment deployment = new PayaraTracingServices().getDeployment();
if (deployment == null || deployment.getCurrentDeploymentContext() == null) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,22 @@
*/
package fish.payara.microprofile.opentracing.jaxrs.client;

import fish.payara.nucleus.requesttracing.RequestTracingService;
import fish.payara.opentracing.OpenTracingService;
import fish.payara.requesttracing.jaxrs.client.PayaraTracingServices;

import java.security.KeyStore;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Configuration;

import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.client.Initializable;

import fish.payara.requesttracing.jaxrs.client.PayaraTracingServices;

/**
* Decorator for the default JerseyClientBuilder class to allow us to add our ClientFilter and instrument asynchronous
* clients.
Expand Down Expand Up @@ -145,7 +139,7 @@ public ClientBuilder readTimeout(long timeout, TimeUnit unit) {

@Override
public Client build() {
if (!requestTracingPresent()) {
if (!PAYARA_SERVICES.isTracingAvailable()) {
return clientBuilder.build();
}

Expand All @@ -156,30 +150,13 @@ public Client build() {
Object earlyInit = getConfiguration().getProperty(EARLY_BUILDER_INIT);
if (earlyInit instanceof Boolean && (Boolean) earlyInit) {
if (client instanceof Initializable) {
((Initializable) client).preInitialize();
((Initializable<?>) client).preInitialize();
}
}

return new JaxrsClientDecorator(client);
}

private boolean requestTracingPresent() {
try {
ServiceLocator locator = PAYARA_SERVICES.getBasicServiceLocator();
if (locator == null) {
return false;
}
ServiceHandle<RequestTracingService> requestTracing = locator.getServiceHandle(RequestTracingService.class);
ServiceHandle<OpenTracingService> openTracing = locator.getServiceHandle(OpenTracingService.class);
return requestTracing != null && openTracing != null && requestTracing.isActive() && openTracing.isActive();
} catch (Exception e) {
Logger logger = Logger.getLogger(JaxrsClientBuilderDecorator.class.getName());
logger.log(Level.WARNING, "Cannot find required service handles.", e);
// means that we likely cannot do request tracing anyway
return false;
}
}

@Override
public Configuration getConfiguration() {
return this.clientBuilder.getConfiguration();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) [2019] Payara Foundation and/or its affiliates. All rights reserved.
* Copyright (c) [2019-2020] Payara Foundation and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
Expand Down Expand Up @@ -40,20 +40,35 @@

package fish.payara.samples.classpath.embeddedvsjersey;

import org.junit.Test;
import java.io.IOException;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;

import org.glassfish.grizzly.PortRange;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
import org.junit.Test;

/**
* Tests if it is possible to use jersey client with embedded payara on the classpath.
* Response does not matter, it is only required to execute the request.
*/
public class JerseyClasspathTest {

@Test
public void jerseyShouldInitialize() {
Client client = ClientBuilder.newClient();
client.target("http://localhost:8080").request().buildGet();
public void jerseyShouldInitialize() throws IOException {
HttpServer server = HttpServer.createSimpleServer();
NetworkListener listener = new NetworkListener("my-listener", "127.0.0.1", new PortRange(1025, 65535), true);
server.addListener(listener);

try {
server.start();

Client client = ClientBuilder.newClient();
client.target("http://127.0.0.1:" + listener.getPort()).request().get();
} finally {
server.shutdownNow();
}
}
}