Skip to content
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
2 changes: 1 addition & 1 deletion rt/rs/microprofile-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
org.apache.aries.blueprint.NamespaceHandler;osgi.service.blueprint.namespace="http://cxf.apache.org/blueprint/jaxrs-client"
</cxf.export.service>
<cxf.bundle.activator>org.apache.cxf.jaxrs.client.blueprint.Activator</cxf.bundle.activator>
<mp.rest.client.version>1.2-m2</mp.rest.client.version>
<mp.rest.client.version>1.2-RC1</mp.rest.client.version>
</properties>
<dependencies>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,12 @@
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

import javax.ws.rs.core.Configurable;
import javax.ws.rs.core.Configuration;

import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.microprofile.client.config.ConfigFacade;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.spi.RestClientListener;
Expand All @@ -47,9 +43,6 @@
import static org.apache.cxf.jaxrs.client.ClientProperties.HTTP_RECEIVE_TIMEOUT_PROP;

public class CxfTypeSafeClientBuilder implements RestClientBuilder, Configurable<RestClientBuilder> {
private static final Logger LOG = LogUtils.getL7dLogger(CxfTypeSafeClientBuilder.class);
private static final String REST_CONN_TIMEOUT_FORMAT = "%s/mp-rest/connectTimeout";
private static final String REST_READ_TIMEOUT_FORMAT = "%s/mp-rest/readTimeout";
private static final Map<ClassLoader, Collection<RestClientListener>> REST_CLIENT_LISTENERS =
new WeakHashMap<>();

Expand Down Expand Up @@ -136,24 +129,6 @@ public <T> T build(Class<T> aClass) {
}
}

final String interfaceName = aClass.getName();

ConfigFacade.getOptionalLong(String.format(REST_CONN_TIMEOUT_FORMAT, interfaceName)).ifPresent(
timeoutValue -> {
connectTimeout(timeoutValue, TimeUnit.MILLISECONDS);
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("readTimeout set by MP Config: " + timeoutValue);
}
});

ConfigFacade.getOptionalLong(String.format(REST_READ_TIMEOUT_FORMAT, interfaceName)).ifPresent(
timeoutValue -> {
readTimeout(timeoutValue, TimeUnit.MILLISECONDS);
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("readTimeout set by MP Config: " + timeoutValue);
}
});

listeners().forEach(l -> l.onNewClient(aClass, this));

MicroProfileClientFactoryBean bean = new MicroProfileClientFactoryBean(configImpl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@ ASYNC_INTERCEPTOR_EXCEPTION_PREPARE_CONTEXT=The AsyncInvocationInterceptor, {0}
ASYNC_INTERCEPTOR_EXCEPTION_APPLY_CONTEXT=The AsyncInvocationInterceptor, {0} has thrown an exception during the invocation of the applyContext method.
ASYNC_INTERCEPTOR_EXCEPTION_REMOVE_CONTEXT=The AsyncInvocationInterceptor, {0} has thrown an exception during the invocation of the removeContext method.

INVALID_TIMEOUT_PROPERTY=The timeout property, {0} is specified as {1}, and is invalid. It must be a non-negative integer.
INVALID_TIMEOUT_PROPERTY=The timeout property, {0} is specified as {1}, and is invalid. It must be a non-negative integer.

CLIENT_HEADER_NO_NAME=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it has a null or empty name.
CLIENT_HEADER_NO_VALUE=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it does not define a valid value attribute.
CLIENT_HEADER_INVALID_COMPUTE_METHOD=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it's value attribute specifies a method, {1}, that does not exist, is not accessible, or contains an incorrect signature. The signature must return a String or String[] and must contain either no arguments or contain exactly one String argument.
CLIENT_HEADER_MULTI_METHOD=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it's value attribute specifies multiple values and at least one of those values is a compute method. If the value attribute specifies a compute method, that must be the only value.
CLIENT_HEADER_COMPUTE_CLASS_NOT_FOUND=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it specifies a compute method on a class that cannot be found.
CLIENT_HEADER_MULTIPLE_SAME_HEADER_NAMES=A @ClientHeaderParam annotation specified in the {0} interface is invalid because it specifies a header name that is already specified on the same target. A header name may only be specified in one @ClientHeaderParam per target.
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ Configuration getConfiguration() {
private Set<Object> processProviders() {
Set<Object> providers = new LinkedHashSet<>();
for (Object provider : configuration.getInstances()) {
Class<?> providerCls = ClassHelper.getRealClass(bus, provider);
Class<?> providerCls = ClassHelper.getRealClass(getBus(), provider);
if (provider instanceof ClientRequestFilter || provider instanceof ClientResponseFilter) {
FilterProviderInfo<Object> filter = new FilterProviderInfo<>(providerCls, providerCls,
provider, bus, configuration.getContracts(providerCls));
provider, getBus(), configuration.getContracts(providerCls));
providers.add(filter);
} else {
providers.add(provider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,35 @@

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;

import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.i18n.BundleUtils;
import org.apache.cxf.common.i18n.Message;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.jaxrs.model.URITemplate;
import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;

final class Validator {
private static final Logger LOG = LogUtils.getL7dLogger(Validator.class);
private static final ResourceBundle BUNDLE = BundleUtils.getBundle(Validator.class);

private Validator() {
Expand All @@ -53,6 +62,7 @@ public static void checkValid(Class<?> userType) throws RestClientDefinitionExce
Method[] methods = userType.getMethods();
checkMethodsForMultipleHTTPMethodAnnotations(methods);
checkMethodsForInvalidURITemplates(userType, methods);
checkForInvalidClientHeaderParams(userType, methods);
}

private static void checkMethodsForMultipleHTTPMethodAnnotations(Method[] clientMethods)
Expand Down Expand Up @@ -129,6 +139,88 @@ private static void checkMethodsForInvalidURITemplates(Class<?> userType, Method
}
}

private static void checkForInvalidClientHeaderParams(Class<?> userType, Method[] methods) {
ClientHeaderParam[] interfaceAnnotations = userType.getAnnotationsByType(ClientHeaderParam.class);
checkClientHeaderParamAnnotation(interfaceAnnotations, userType, methods);
for (Method method : methods) {
ClientHeaderParam[] methodAnnotations = method.getAnnotationsByType(ClientHeaderParam.class);
checkClientHeaderParamAnnotation(methodAnnotations, userType, methods);
}
}

private static void checkClientHeaderParamAnnotation(ClientHeaderParam[] annos, Class<?> userType,
Method[] methods) {
Set<String> headerNames = new HashSet<>();
for (ClientHeaderParam anno : annos) {
String name = anno.name();
if (headerNames.contains(name)) {
throwException("CLIENT_HEADER_MULTIPLE_SAME_HEADER_NAMES", userType.getName());
}
headerNames.add(name);

if (name == null || "".equals(name)) {
throwException("CLIENT_HEADER_NO_NAME", userType.getName());
}

String[] values = anno.value();

for (String value : values) {
if (StringUtils.isEmpty(value)) {
throwException("CLIENT_HEADER_NO_VALUE", userType.getName());
}

if (value.startsWith("{") && value.endsWith("}")) {
if (values.length > 1) {
throwException("CLIENT_HEADER_MULTI_METHOD", userType.getName());
}
String computeValue = value.substring(1, value.length() - 1);
boolean usingOtherClass = false;
if (computeValue.contains(".")) {
usingOtherClass = true;
String className = computeValue.substring(0, computeValue.lastIndexOf('.'));
computeValue = computeValue.substring(computeValue.lastIndexOf('.') + 1);
try {
Class<?> computeClass = ClassLoaderUtils.loadClass(className, userType);
methods = Arrays.stream(computeClass.getDeclaredMethods())
.filter(m -> {
int i = m.getModifiers();
return Modifier.isPublic(i)
&& Modifier.isStatic(i);
})
.toArray(Method[]::new);
} catch (ClassNotFoundException ex) {
if (LOG.isLoggable(Level.FINEST)) {
LOG.log(Level.FINEST, "Unable to load specified compute method class", ex);
}
throwException("CLIENT_HEADER_COMPUTE_CLASS_NOT_FOUND", userType.getName(), ex);
}

}
boolean foundMatchingMethod = false;
for (Method method : methods) {
Class<?> returnType = method.getReturnType();
if ((usingOtherClass || method.isDefault())
&& (String.class.equals(returnType) || String[].class.equals(returnType))
&& computeValue.equals(method.getName())) {

Class<?>[] args = method.getParameterTypes();
if (args.length == 0 || (args.length == 1 && String.class.equals(args[0]))) {
foundMatchingMethod = true;
break;
}

}
}
if (!foundMatchingMethod) {
throwException("CLIENT_HEADER_INVALID_COMPUTE_METHOD",
userType.getName(),
computeValue);
}
}
}
}
}

private static void throwException(String msgKey, Object...msgParams) throws RestClientDefinitionException {
Message msg = new Message(msgKey, BUNDLE, msgParams);
throw new RestClientDefinitionException(msg.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -55,6 +56,8 @@ public class RestClientBean implements Bean<Object>, PassivationCapable {
public static final String REST_URI_FORMAT = "%s/mp-rest/uri";
public static final String REST_SCOPE_FORMAT = "%s/mp-rest/scope";
public static final String REST_PROVIDERS_FORMAT = "%s/mp-rest/providers";
public static final String REST_CONN_TIMEOUT_FORMAT = "%s/mp-rest/connectTimeout";
public static final String REST_READ_TIMEOUT_FORMAT = "%s/mp-rest/readTimeout";
public static final String REST_PROVIDERS_PRIORITY_FORMAT = "%s/mp-rest/providers/%s/priority";
private static final Logger LOG = LogUtils.getL7dLogger(RestClientBean.class);
private static final Default DEFAULT_LITERAL = new DefaultLiteral();
Expand Down Expand Up @@ -98,6 +101,7 @@ public Object create(CreationalContext<Object> creationalContext) {
builder = (CxfTypeSafeClientBuilder) builder.register(providerClass,
providerPriorities.getOrDefault(providerClass, Priorities.USER));
}
setTimeouts(builder);
return builder.build(clientInterface);
}

Expand Down Expand Up @@ -229,4 +233,24 @@ private static final class DefaultLiteral extends AnnotationLiteral<Default> imp
private static final long serialVersionUID = 1L;

}

private void setTimeouts(CxfTypeSafeClientBuilder builder) {
final String interfaceName = clientInterface.getName();

ConfigFacade.getOptionalLong(String.format(REST_CONN_TIMEOUT_FORMAT, interfaceName)).ifPresent(
timeoutValue -> {
builder.connectTimeout(timeoutValue, TimeUnit.MILLISECONDS);
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("readTimeout set by MP Config: " + timeoutValue);
}
});

ConfigFacade.getOptionalLong(String.format(REST_READ_TIMEOUT_FORMAT, interfaceName)).ifPresent(
timeoutValue -> {
builder.readTimeout(timeoutValue, TimeUnit.MILLISECONDS);
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("readTimeout set by MP Config: " + timeoutValue);
}
});
}
}
Loading