Skip to content

Commit

Permalink
4.x: Enable disabled TCKs (helidon-io#7781)
Browse files Browse the repository at this point in the history
Contains JakartaEE10 TCKs and changes in Helidon to pass them.

Signed-off-by: Jorge Bescos Gascon <[email protected]>
  • Loading branch information
jbescos authored Dec 15, 2023
1 parent bc82e61 commit e19d535
Show file tree
Hide file tree
Showing 47 changed files with 1,588 additions and 390 deletions.
2 changes: 1 addition & 1 deletion dependencies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<version.lib.jboss.classfilewriter>1.3.0.Final</version.lib.jboss.classfilewriter>
<version.lib.jboss.logging>3.5.3.Final</version.lib.jboss.logging>
<version.lib.jaxb-runtime>4.0.3</version.lib.jaxb-runtime>
<version.lib.jersey>3.1.3</version.lib.jersey>
<version.lib.jersey>3.1.4</version.lib.jersey>
<version.lib.jgit>6.7.0.202309050840-r</version.lib.jgit>
<version.lib.junit>5.9.3</version.lib.junit>
<version.lib.kafka>3.6.0</version.lib.kafka>
Expand Down
6 changes: 4 additions & 2 deletions http/http/src/main/java/io/helidon/http/PathMatchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.regex.Pattern;

import io.helidon.common.parameters.Parameters;
import io.helidon.common.uri.UriEncoding;
import io.helidon.common.uri.UriPath;

/**
Expand Down Expand Up @@ -276,8 +277,9 @@ static final class ExactPathMatcher implements PathMatcher {
private final String pathWithTrailingSlash;

ExactPathMatcher(String path) {
this.path = path;
this.pathWithTrailingSlash = path + "/";
// We work with decoded URIs
this.path = UriEncoding.decodeUri(path);
this.pathWithTrailingSlash = this.path + "/";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.IntStream;

import io.helidon.microprofile.server.CatchAllExceptionMapper;
import io.helidon.microprofile.testing.junit5.AddBean;
import io.helidon.microprofile.testing.junit5.HelidonTest;

Expand All @@ -41,6 +42,7 @@
*/
@HelidonTest
@AddBean(HelloWorldResource.class)
@AddBean(CatchAllExceptionMapper.class)
public class HelloWorldTest {

@Inject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Handler;
Expand All @@ -46,6 +45,8 @@
import jakarta.enterprise.context.BeforeDestroyed;
import jakarta.enterprise.context.Destroyed;
import jakarta.enterprise.context.Initialized;
import jakarta.enterprise.event.Startup;
import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.enterprise.inject.spi.CDI;
Expand Down Expand Up @@ -96,6 +97,8 @@ final class HelidonContainerImpl extends Weld implements HelidonContainer {
private static final Context ROOT_CONTEXT;
// whether the current shutdown was invoked by the shutdown hook
private static final AtomicBoolean FROM_SHUTDOWN_HOOK = new AtomicBoolean();
// Default Weld container id. TCKs assumes this value.
private static final String STATIC_INSTANCE = "STATIC_INSTANCE";

static {
HelidonFeatures.flavor(HelidonFlavor.MP);
Expand All @@ -119,7 +122,7 @@ final class HelidonContainerImpl extends Weld implements HelidonContainer {

HelidonContainerImpl() {
this.bootstrap = new WeldBootstrap();
id = UUID.randomUUID().toString();
this.id = STATIC_INSTANCE;
}

/**
Expand Down Expand Up @@ -205,6 +208,7 @@ public Collection<URL> getResources(String name) {
}
deployment.getServices().add(ExternalConfiguration.class, configurationBuilder.build());

// CDI TCK tests expects SE to be excluded, which means Helidon may require to do things that Weld is supposed to do.
bootstrap.startContainer(id, Environments.SE, deployment);

bootstrap.startInitialization();
Expand Down Expand Up @@ -315,6 +319,7 @@ private HelidonContainerImpl doStart() {
keepLoggingActive(shutdownHook);

bm.getEvent().select(Initialized.Literal.APPLICATION).fire(new ContainerInitialized(id));
bm.getEvent().select(Any.Literal.INSTANCE).fire(new Startup());

now = System.currentTimeMillis() - now;
LOGGER.fine("Container started in " + now + " millis (this excludes the initialization time)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.context.spi.CreationalContext;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.Vetoed;
import jakarta.enterprise.inject.spi.AfterBeanDiscovery;
import jakarta.enterprise.inject.spi.AfterDeploymentValidation;
import jakarta.enterprise.inject.spi.Annotated;
Expand Down Expand Up @@ -136,7 +137,7 @@ private void processAnnotatedType(@Observes @WithAnnotations(ConfigProperties.cl
private <X> void harvestConfigPropertyInjectionPointsFromEnabledObserverMethod(@Observes ProcessObserverMethod<?, X> event,
BeanManager beanManager) {
AnnotatedMethod<X> annotatedMethod = event.getAnnotatedMethod();
if (annotatedMethod != null) {
if (annotatedMethod != null && !annotatedMethod.getDeclaringType().isAnnotationPresent(Vetoed.class)) {
List<AnnotatedParameter<X>> annotatedParameters = annotatedMethod.getParameters();
if (annotatedParameters != null) {
for (AnnotatedParameter<?> annotatedParameter : annotatedParameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import io.helidon.microprofile.lra.resources.StartAndAfter;
import io.helidon.microprofile.lra.resources.Timeout;
import io.helidon.microprofile.lra.resources.Work;
import io.helidon.microprofile.server.CatchAllExceptionMapper;
import io.helidon.microprofile.server.JaxRsCdiExtension;
import io.helidon.microprofile.server.ServerCdiExtension;
import io.helidon.microprofile.testing.junit5.AddBean;
Expand Down Expand Up @@ -94,7 +95,8 @@
@AddExtension(CdiComponentProvider.class)
// LRA client
@AddExtension(LraCdiExtension.class)
// Test resources
// resources
@AddBean(CatchAllExceptionMapper.class)
@AddBean(JaxRsCompleteOrCompensate.class)
@AddBean(NonJaxRsCompleteOrCompensate.class)
@AddBean(NonJaxRsCompleteOrCompensateCS.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import java.util.regex.Pattern;
import java.util.stream.IntStream;

import io.helidon.microprofile.server.CatchAllExceptionMapper;
import io.helidon.microprofile.testing.junit5.AddBean;
import io.helidon.microprofile.testing.junit5.AddConfig;
import io.helidon.microprofile.testing.junit5.HelidonTest;

Expand Down Expand Up @@ -55,6 +57,7 @@
@HelidonTest
@AddConfig(key = "metrics." + MetricsCdiExtension.REST_ENDPOINTS_METRIC_ENABLED_PROPERTY_NAME, value = "true")
@AddConfig(key = "metrics.permit-all", value = "true")
@AddBean(CatchAllExceptionMapper.class)
class HelloWorldTest {

@Inject
Expand Down
5 changes: 5 additions & 0 deletions microprofile/server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
<name>Helidon Microprofile Server</name>
<description>Server of the microprofile implementation</description>

<properties>
<surefire.argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Dorg.jboss.weld.construction.relaxed=false</surefire.argLine>
<failsafe.argLine>-Xmx1024m -Dfile.encoding=UTF-8 -Dorg.jboss.weld.construction.relaxed=false</failsafe.argLine>
</properties>

<dependencies>
<dependency>
<groupId>io.helidon.config</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
*
* Licensed 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 io.helidon.microprofile.server;

import java.lang.System.Logger.Level;

import io.helidon.webserver.http.ServerRequest;

import jakarta.annotation.Priority;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

/**
* Mapper for exceptions that are not caught.
*
* It is not configured by default in Helidon but it is provided for explicit usage.
*/
@Provider
@Priority(5000)
public class CatchAllExceptionMapper implements ExceptionMapper<Exception> {

private static final System.Logger LOGGER = System.getLogger(CatchAllExceptionMapper.class.getName());

@Context
private ServerRequest serverRequest;

/**
* Default empty constructor.
*/
public CatchAllExceptionMapper() {
}

@Override
public Response toResponse(Exception exception) {
serverRequest.context().register("unmappedException", exception);
if (exception instanceof WebApplicationException wae) {
return wae.getResponse();
} else {
LOGGER.log(Level.WARNING, () -> "Internal server error", exception);
return Response.serverError().build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,14 @@
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import io.helidon.webserver.http.ServerRequest;

import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Initialized;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.spi.Extension;
import jakarta.enterprise.inject.spi.ProcessManagedBean;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
Expand Down Expand Up @@ -277,29 +271,11 @@ JaxRsService toJerseySupport(JaxRsApplication jaxRsApplication,
InjectionManager injectionManager) {

ResourceConfig resourceConfig = jaxRsApplication.resourceConfig();
resourceConfig.register(new CatchAllExceptionMapper());

return JaxRsService.create(resourceConfig,
injectionManager);
}

@Provider
private static class CatchAllExceptionMapper implements ExceptionMapper<Exception> {
@Context
private ServerRequest serverRequest;

@Override
public Response toResponse(Exception exception) {
serverRequest.context().register("unmappedException", exception);
if (exception instanceof WebApplicationException wae) {
return wae.getResponse();
} else {
LOGGER.log(Level.WARNING, () -> "Internal server error", exception);
return Response.serverError().build();
}
}
}

Optional<String> findContextRoot(io.helidon.config.Config config, JaxRsApplication jaxRsApplication) {
return config.get(jaxRsApplication.appClassName() + "." + RoutingPath.CONFIG_KEY_PATH)
.asString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@
import org.glassfish.jersey.server.spi.Container;
import org.glassfish.jersey.server.spi.ContainerResponseWriter;

import static org.glassfish.jersey.CommonProperties.PROVIDER_DEFAULT_DISABLE;
import static org.glassfish.jersey.server.ServerProperties.WADL_FEATURE_DISABLE;

class JaxRsService implements HttpService {
/**
* If set to {@code "true"}, Jersey will ignore responses in exceptions.
Expand All @@ -98,8 +95,6 @@ private JaxRsService(ResourceConfig resourceConfig,
}

static JaxRsService create(ResourceConfig resourceConfig, InjectionManager injectionManager) {
resourceConfig.property(PROVIDER_DEFAULT_DISABLE, "ALL");
resourceConfig.property(WADL_FEATURE_DISABLE, "true");

InjectionManager ij = injectionManager == null ? null : new InjectionManagerWrapper(injectionManager, resourceConfig);
ApplicationHandler appHandler = new ApplicationHandler(resourceConfig,
Expand All @@ -121,7 +116,7 @@ static JaxRsService create(ResourceConfig resourceConfig, InjectionManager injec
return new JaxRsService(resourceConfig, appHandler, container);
}

static String basePath(UriPath path) {
private static String basePath(UriPath path) {
String reqPath = path.path();
String absPath = path.absolute().path();
String basePath = absPath.substring(0, absPath.length() - reqPath.length() + 1);
Expand Down Expand Up @@ -179,14 +174,6 @@ private static Application getApplication(ResourceConfig resourceConfig) {
return application;
}

private static URI baseUri(ServerRequest req) {
String uri = (req.isSecure() ? "https" : "http")
+ "://" + req.authority()
+ basePath(req.path());

return URI.create(uri);
}

private void handle(ServerRequest req, ServerResponse res) {
Context context = req.context();

Expand All @@ -199,19 +186,9 @@ private void handle(ServerRequest req, ServerResponse res) {
}

private void doHandle(Context ctx, ServerRequest req, ServerResponse res) {
URI baseUri = baseUri(req);
URI requestUri;

String rawPath = req.path().rawPath();
rawPath = rawPath.startsWith("/") ? rawPath.substring(1) : rawPath;
if (req.query().isEmpty()) {
requestUri = baseUri.resolve(rawPath);
} else {
requestUri = baseUri.resolve(rawPath + "?" + req.query().rawValue());
}

ContainerRequest requestContext = new ContainerRequest(baseUri,
requestUri,
BaseUriRequestUri uris = BaseUriRequestUri.resolve(req);
ContainerRequest requestContext = new ContainerRequest(uris.baseUri,
uris.requestUri,
req.prologue().method().text(),
new HelidonMpSecurityContext(), new MapPropertiesDelegate(),
resourceConfig);
Expand Down Expand Up @@ -357,7 +334,7 @@ public OutputStream writeResponseStatusAndHeaders(long contentLengthParam,
if (contentLength > 0) {
res.header(HeaderValues.create(HeaderNames.CONTENT_LENGTH, String.valueOf(contentLength)));
}
this.outputStream = new NoFlushOutputStream(res.outputStream());
this.outputStream = res.outputStream();
return outputStream;
}

Expand Down Expand Up @@ -414,36 +391,25 @@ public void await() {
}
}

private static class NoFlushOutputStream extends OutputStream {
private final OutputStream delegate;

private NoFlushOutputStream(OutputStream delegate) {
this.delegate = delegate;
}

@Override
public void write(byte[] b) throws IOException {
delegate.write(b);
}

@Override
public void write(byte[] b, int off, int len) throws IOException {
delegate.write(b, off, len);
}
private static class BaseUriRequestUri {
private final URI baseUri;
private final URI requestUri;

@Override
public void flush() {
// intentional no-op, flush did not work nicely with Jersey
private BaseUriRequestUri(URI baseUri, URI requestUri) {
this.baseUri = baseUri;
this.requestUri = requestUri;
}

@Override
public void close() throws IOException {
delegate.close();
}

@Override
public void write(int b) throws IOException {
delegate.write(b);
private static BaseUriRequestUri resolve(ServerRequest req) {
String processedBasePath = basePath(req.path());
String rawPath = req.path().absolute().rawPath();
String prefix = (req.isSecure() ? "https" : "http") + "://" + req.authority();
String serverBasePath = prefix + processedBasePath;
String requestPath = prefix + rawPath;
if (!req.query().isEmpty()) {
requestPath = requestPath + "?" + req.query().rawValue();
}
return new BaseUriRequestUri(URI.create(serverBasePath), URI.create(requestPath));
}
}
}
Loading

0 comments on commit e19d535

Please sign in to comment.