This is an automated email from the ASF dual-hosted git repository. dblevins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 61372ce4f5d1bcd25b4f42ec78b2024f301558e5 Author: David Blevins <[email protected]> AuthorDate: Sun Feb 20 03:28:03 2022 -0500 TOMEE-3844 Improve logging for JAX-RS application deployment --- itests/jaxrs/pom.xml | 80 +++++++++ .../itests/jaxrs/applogging/AnnotatedWriter.java | 31 ++++ .../jaxrs/applogging/ApplicationLoggingTest.java | 196 +++++++++++++++++++++ .../itests/jaxrs/applogging/CircleResource.java | 29 +++ .../jaxrs/applogging/DiscoveredResources.java | 24 +++ .../tomee/itests/jaxrs/applogging/GetClasses.java | 35 ++++ .../jaxrs/applogging/GetClassesNoProviders.java | 34 ++++ .../applogging/GetClassesNonAnnotatedProvider.java | 35 ++++ .../itests/jaxrs/applogging/GetSingletons.java | 35 ++++ .../jaxrs/applogging/NotAnnotatedWriter.java | 29 +++ .../itests/jaxrs/applogging/SquareResource.java | 29 +++ .../itests/jaxrs/applogging/TriangleResource.java | 28 +++ itests/pom.xml | 1 + .../openejb/server/cxf/rs/ApplicationData.java | 173 ++++++++++++++++++ .../openejb/server/cxf/rs/CxfRsHttpListener.java | 96 +++++++++- .../server/cxf/rs/NoResourcesFoundException.java | 23 +++ 16 files changed, 877 insertions(+), 1 deletion(-) diff --git a/itests/jaxrs/pom.xml b/itests/jaxrs/pom.xml new file mode 100644 index 0000000..880a6c3 --- /dev/null +++ b/itests/jaxrs/pom.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + <version>8.0.11-SNAPSHOT</version> + + <parent> + <artifactId>itests</artifactId> + <groupId>org.apache.tomee</groupId> + <version>8.0.11-SNAPSHOT</version> + </parent> + + <groupId>org.apache.tomee.itests</groupId> + <artifactId>jaxrs</artifactId> + <packaging>jar</packaging> + <name>TomEE :: iTests :: JAX-RS</name> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <systemPropertyVariables> + <version>${project.version}</version> + </systemPropertyVariables> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.apache.tomee</groupId> + <artifactId>tomee-server-composer</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomee</groupId> + <artifactId>apache-tomee</artifactId> + <version>8.0.11-SNAPSHOT</version> + <type>tar.gz</type> + <classifier>microprofile</classifier> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.tomee.bom</groupId> + <artifactId>tomee-webprofile-api</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> + </dependencies> +</project> + diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/AnnotatedWriter.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/AnnotatedWriter.java new file mode 100644 index 0000000..291f00a --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/AnnotatedWriter.java @@ -0,0 +1,31 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.ext.Provider; +import javax.ws.rs.ext.WriterInterceptor; +import javax.ws.rs.ext.WriterInterceptorContext; +import java.io.IOException; + +@Provider +public class AnnotatedWriter implements WriterInterceptor { + @Override + public void aroundWriteTo(final WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException { + + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/ApplicationLoggingTest.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/ApplicationLoggingTest.java new file mode 100644 index 0000000..4d02e89 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/ApplicationLoggingTest.java @@ -0,0 +1,196 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import org.apache.tomee.server.composer.Archive; +import org.apache.tomee.server.composer.TomEE; +import org.junit.Ignore; +import org.junit.Test; +import org.tomitribe.util.Join; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ApplicationLoggingTest { + + @Test + public void discovered() throws Exception { + + final ArrayList<String> output = new ArrayList<>(); + final TomEE tomee = TomEE.webprofile() + .add("webapps/test/WEB-INF/lib/app.jar", Archive.archive() + .add(DiscoveredResources.class) + .add(SquareResource.class) + .add(TriangleResource.class) + .add(AnnotatedWriter.class) + .asJar()) + .watch("org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logApplication ", "\n", output::add) + .build(); + + Collections.sort(output); + + final String join = Join.join("\n", output); + assertEquals("Application{path='http://localhost:0/test/blue', class=org.apache.tomee.itests.jaxrs.applogging.DiscoveredResources, resources=2, providers=1, invalids=0}\n" + + "Provider{clazz=org.apache.tomee.itests.jaxrs.applogging.AnnotatedWriter, discovered=true, singleton=false}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.SquareResource, discovered=true, singleton=false}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.TriangleResource, discovered=true, singleton=false}", normalize(join)); + } + + @Test + public void getClasses() throws Exception { + + final ArrayList<String> output = new ArrayList<>(); + final TomEE tomee = TomEE.webprofile() + .add("webapps/test/WEB-INF/lib/app.jar", Archive.archive() + .add(GetClasses.class) + .add(SquareResource.class) + .add(TriangleResource.class) + .add(AnnotatedWriter.class) + .asJar()) + .watch("org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logApplication ", "\n", output::add) + .build(); + + Collections.sort(output); + + final String join = Join.join("\n", output); + assertEquals("Application{path='http://localhost:0/test/red', class=org.apache.tomee.itests.jaxrs.applogging.GetClasses, resources=2, providers=1, invalids=0}\n" + + "Provider{clazz=org.apache.tomee.itests.jaxrs.applogging.AnnotatedWriter, discovered=false, singleton=false}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.SquareResource, discovered=false, singleton=false}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.TriangleResource, discovered=false, singleton=false}", normalize(join)); + } + + /** + * This test shows two bugs: + * - singletons show up as discovered when they were explicitly configured + * + * @throws Exception + */ + @Ignore + @Test + public void getSingletons() throws Exception { + + final ArrayList<String> output = new ArrayList<>(); + final TomEE tomee = TomEE.webprofile() + .add("webapps/test/WEB-INF/lib/app.jar", Archive.archive() + .add(GetSingletons.class) + .add(SquareResource.class) + .add(TriangleResource.class) + .add(AnnotatedWriter.class) + .asJar()) + .watch("org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logApplication ", "\n", output::add) +// .debug(5005) + .build(); + + Collections.sort(output); + + final String join = Join.join("\n", output); + assertEquals("Application{path='http://localhost:0/test/red', class=org.apache.tomee.itests.jaxrs.applogging.GetSingletons, resources=2, providers=2, invalids=0}\n" + + "Provider{clazz=org.apache.tomee.itests.jaxrs.applogging.AnnotatedWriter, discovered=false, singleton=true}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.SquareResource, discovered=false, singleton=true}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.TriangleResource, discovered=false, singleton=true}", normalize(join)); + } + + + /** + * We appear to be breaking the second sentence of this requirement of the JAX-RS specification: + * + * ---- + * When an Application subclass is present in the archive, if both Application.getClasses + * and Application.getSingletons return an empty collection then all root resource classes and + * providers packaged in the web application MUST be included and the JAX-RS implementation is + * REQUIRED to discover them automatically by scanning a .war file as described above. If either + * getClasses or getSingletons returns a non-empty collection then only those classes or singletons + * returned MUST be included in the published JAX-RS application. + * ---- + * + * Despite there being a getClasses() method, we still scan for @Provider implementations in the classpath + * add them to the application. + */ + @Ignore() + @Test + public void getClassesNoProviders() throws Exception { + + final ArrayList<String> output = new ArrayList<>(); + final TomEE tomee = TomEE.webprofile() + .add("webapps/test/WEB-INF/lib/app.jar", Archive.archive() + .add(GetClassesNoProviders.class) + .add(SquareResource.class) + .add(TriangleResource.class) + .add(CircleResource.class) + .add(AnnotatedWriter.class) + .add(NotAnnotatedWriter.class) + .asJar()) + .watch("org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logApplication ", "\n", output::add) + .build(); + + Collections.sort(output); + final String join = Join.join("\n", output); + assertEquals("Application{path='http://localhost:0/test/red', class=org.apache.tomee.itests.jaxrs.applogging.GetClassesNoProviders, resources=2, providers=1, invalids=0}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.SquareResource, discovered=false, singleton=false}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.TriangleResource, discovered=false, singleton=false}", normalize(join)); + } + + @Test + public void getClassesNonAnnotatedProvider() throws Exception { + + final ArrayList<String> output = new ArrayList<>(); + final TomEE tomee = TomEE.webprofile() + .add("webapps/test/WEB-INF/lib/app.jar", Archive.archive() + .add(GetClassesNonAnnotatedProvider.class) + .add(SquareResource.class) + .add(TriangleResource.class) + .add(CircleResource.class) + .add(NotAnnotatedWriter.class) + .asJar()) + .watch("org.apache.openejb.server.cxf.rs.CxfRsHttpListener.logApplication ", "\n", output::add) + .build(); + + Collections.sort(output); + final String join = Join.join("\n", output); + assertEquals("Application{path='http://localhost:0/test/red', class=org.apache.tomee.itests.jaxrs.applogging.GetClassesNonAnnotatedProvider, resources=2, providers=1, invalids=0}\n" + + "Provider{clazz=org.apache.tomee.itests.jaxrs.applogging.NotAnnotatedWriter, discovered=false, singleton=false}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.SquareResource, discovered=false, singleton=false}\n" + + "Resource{clazz=org.apache.tomee.itests.jaxrs.applogging.TriangleResource, discovered=false, singleton=false}", normalize(join)); + } + + private String normalize(final String join) { + return join.replaceAll("localhost:[0-9]+", "localhost:0"); + } + + public void assertPresent(final ArrayList<String> output, final String s) { + final Optional<String> actual = output.stream() + .filter(line -> line.contains(s)) + .findFirst(); + + assertTrue(actual.isPresent()); + } + + public void assertNotPresent(final ArrayList<String> output, final String s) { + final Optional<String> actual = output.stream() + .filter(line -> line.contains(s)) + .findFirst(); + + assertTrue(!actual.isPresent()); + } + +} \ No newline at end of file diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/CircleResource.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/CircleResource.java new file mode 100644 index 0000000..4136db5 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/CircleResource.java @@ -0,0 +1,29 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +@Path("/circle") +public class CircleResource { + + @GET + public String get() { + return ""; + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/DiscoveredResources.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/DiscoveredResources.java new file mode 100644 index 0000000..7b2ece7 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/DiscoveredResources.java @@ -0,0 +1,24 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/blue") +public class DiscoveredResources extends Application { +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClasses.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClasses.java new file mode 100644 index 0000000..0aa72d8 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClasses.java @@ -0,0 +1,35 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; +import java.util.HashSet; +import java.util.Set; + +@ApplicationPath("/red") +public class GetClasses extends Application { + + @Override + public Set<Class<?>> getClasses() { + final Set<Class<?>> classes = new HashSet<>(); + classes.add(SquareResource.class); + classes.add(TriangleResource.class); + classes.add(AnnotatedWriter.class); + return classes; + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClassesNoProviders.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClassesNoProviders.java new file mode 100644 index 0000000..5678d14 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClassesNoProviders.java @@ -0,0 +1,34 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; +import java.util.HashSet; +import java.util.Set; + +@ApplicationPath("/red") +public class GetClassesNoProviders extends Application { + + @Override + public Set<Class<?>> getClasses() { + final Set<Class<?>> classes = new HashSet<>(); + classes.add(SquareResource.class); + classes.add(TriangleResource.class); + return classes; + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClassesNonAnnotatedProvider.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClassesNonAnnotatedProvider.java new file mode 100644 index 0000000..ba65d16 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetClassesNonAnnotatedProvider.java @@ -0,0 +1,35 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; +import java.util.HashSet; +import java.util.Set; + +@ApplicationPath("/red") +public class GetClassesNonAnnotatedProvider extends Application { + + @Override + public Set<Class<?>> getClasses() { + final Set<Class<?>> classes = new HashSet<>(); + classes.add(SquareResource.class); + classes.add(TriangleResource.class); + classes.add(NotAnnotatedWriter.class); + return classes; + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetSingletons.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetSingletons.java new file mode 100644 index 0000000..d38f75a --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/GetSingletons.java @@ -0,0 +1,35 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; +import java.util.HashSet; +import java.util.Set; + +@ApplicationPath("/red") +public class GetSingletons extends Application { + + @Override + public Set<Object> getSingletons() { + final Set<Object> singletons = new HashSet<>(); + singletons.add(new SquareResource()); + singletons.add(new TriangleResource()); + singletons.add(new AnnotatedWriter()); + return singletons; + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/NotAnnotatedWriter.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/NotAnnotatedWriter.java new file mode 100644 index 0000000..4d5a840 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/NotAnnotatedWriter.java @@ -0,0 +1,29 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.ext.WriterInterceptor; +import javax.ws.rs.ext.WriterInterceptorContext; +import java.io.IOException; + +public class NotAnnotatedWriter implements WriterInterceptor { + @Override + public void aroundWriteTo(final WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException { + + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/SquareResource.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/SquareResource.java new file mode 100644 index 0000000..fe4d572 --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/SquareResource.java @@ -0,0 +1,29 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +@Path("/square") +public class SquareResource { + + @GET + public String get() { + return ""; + } +} diff --git a/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/TriangleResource.java b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/TriangleResource.java new file mode 100644 index 0000000..cbce53f --- /dev/null +++ b/itests/jaxrs/src/test/java/org/apache/tomee/itests/jaxrs/applogging/TriangleResource.java @@ -0,0 +1,28 @@ +/* + * 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.tomee.itests.jaxrs.applogging; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +@Path("/triangle") +public class TriangleResource { + @GET + public String get() { + return ""; + } +} diff --git a/itests/pom.xml b/itests/pom.xml index a186f95..9db4403 100644 --- a/itests/pom.xml +++ b/itests/pom.xml @@ -46,6 +46,7 @@ <module>openejb-itests-interceptor-beans</module> <module>openejb-itests-servlets</module> <module>openejb-itests-web</module> + <module>jaxrs</module> </modules> </project> diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/ApplicationData.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/ApplicationData.java new file mode 100644 index 0000000..488cce7 --- /dev/null +++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/ApplicationData.java @@ -0,0 +1,173 @@ +/* + * 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.openejb.server.cxf.rs; + +import org.apache.openejb.server.rest.InternalApplication; + +import javax.ws.rs.core.Application; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class ApplicationData { + + private final String path; + private final Application application; + private final Class<?> applicationClass; + final List<Resource> resources = new ArrayList<>(); + final List<Provider> providers = new ArrayList<>(); + final List<Invalid> invalids = new ArrayList<>(); + + public ApplicationData(final String path, final Application application) { + this.path = path; + this.application = application; + + if (application instanceof InternalApplication) { + final InternalApplication internalApplication = (InternalApplication) application; + this.applicationClass = internalApplication.getOriginal().getClass(); + } else { + this.applicationClass = application.getClass(); + } + } + + public String getPath() { + return path; + } + + public Application getApplication() { + return application; + } + + public Class<?> getApplicationClass() { + return applicationClass; + } + + public List<Resource> getResources() { + return resources; + } + + public List<Class<?>> getResourceClasses() { + return resources.stream() + .map(Resource::getClazz) + .collect(Collectors.toList()); + } + + public List<Provider> getProviders() { + return providers; + } + + public List<Invalid> getInvalids() { + return invalids; + } + + public void addProvider(final boolean discovered, final Class<?> clazz, final Object singleton) { + providers.add(new Provider(discovered, clazz, singleton)); + } + + public void addResource(final boolean discovered, final Class<?> clazz, final Object singleton){ + resources.add(new Resource(discovered, clazz, singleton)); + } + + public void addInvalid(final Class<?> clazz, final String reason) { + invalids.add(new Invalid(clazz, reason)); + } + + @Override + public String toString() { + return "Application{" + + "path='" + path + '\'' + + ", class=" + applicationClass.getName() + + ", resources=" + resources.size() + + ", providers=" + providers.size() + + ", invalids=" + invalids.size() + + '}'; + } + + public static class Resource { + private final Class<?> clazz; + private final boolean discovered; + private final Object singleton; + + public Resource(final boolean discovered, final Class<?> clazz, final Object singleton) { + this.discovered = discovered; + this.clazz = clazz; + this.singleton = singleton; + } + + public boolean isDiscovered() { + return discovered; + } + + public Class<?> getClazz() { + return clazz; + } + + public Object getSingleton() { + return singleton; + } + + @Override + public String toString() { + return "Resource{" + + "clazz=" + clazz.getName() + + ", discovered=" + discovered + + ", singleton=" + (singleton != null) + + '}'; + } + } + + public static class Provider { + private final Class<?> clazz; + private final boolean discovered; + private final Object singleton; + + public Provider(final boolean discovered, final Class<?> clazz, final Object singleton) { + this.discovered = discovered; + this.clazz = clazz; + this.singleton = singleton; + } + + @Override + public String toString() { + return "Provider{" + + "clazz=" + clazz.getName() + + ", discovered=" + discovered + + ", singleton=" + (singleton != null) + + '}'; + } + } + + public static class Invalid { + private final Class<?> clazz; + private final String reason; + + public Invalid(final Class<?> clazz, final String reason) { + this.clazz = clazz; + this.reason = reason; + } + + @Override + public String toString() { + return "Invalid{" + + "clazz=" + clazz.getName() + + ", reason='" + reason + '\'' + + '}'; + } + } + + +} diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java index c612b4a..dd9580c 100644 --- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java +++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java @@ -653,6 +653,14 @@ public class CxfRsHttpListener implements RsHttpListener { final ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(CxfUtil.initBusLoader()); try { + final ApplicationData applicationData = getApplicationData(application, prefix, additionalProviders); + + logApplication(applicationData); + + if (applicationData.getResources().size() == 0) { + throw new NoResourcesFoundException(applicationData); + } + final JAXRSServerFactoryBean factory = newFactory(prefix, createServiceJmxName(classLoader), createEndpointName(application)); configureFactory(additionalProviders, serviceConfiguration, factory, owbCtx, application); factory.setApplication(application); @@ -808,6 +816,92 @@ public class CxfRsHttpListener implements RsHttpListener { } } + private void logApplication(final ApplicationData applicationData) { + LOGGER.info(applicationData.toString()); + for (ApplicationData.Resource resource : applicationData.getResources()) { + String toString = resource.toString(); + LOGGER.info(toString); + } + for (ApplicationData.Provider provider1 : applicationData.getProviders()) { + String toString = provider1.toString(); + LOGGER.info(toString); + } + for (ApplicationData.Invalid invalid : applicationData.getInvalids()) { + String toString = invalid.toString(); + LOGGER.warning(toString); + } + } + + private ApplicationData getApplicationData(final Application application, final String prefix, final Collection<Object> additionalProviders) { + + final ApplicationData applicationData = new ApplicationData(prefix, application); + + final Set<Class<?>> declaredClasses = new HashSet<>(); + final Set<Object> declaredSingletons = new HashSet<>(); + + if (application instanceof InternalApplication) { + final InternalApplication internalApplication = (InternalApplication) application; + declaredClasses.addAll(internalApplication.getOriginal().getClasses()); + declaredSingletons.addAll(internalApplication.getOriginal().getSingletons()); + } else { + declaredClasses.addAll(application.getClasses()); + declaredSingletons.addAll(application.getSingletons()); + } + + for (final Object additionalProvider : additionalProviders) { + if (additionalProvider instanceof Class) { + + final boolean discovered = !declaredSingletons.contains(additionalProvider); + + applicationData.addProvider(discovered, (Class<?>) additionalProvider, null); + + } else { + final boolean discovered = !declaredSingletons.contains(additionalProvider); + + applicationData.addProvider(discovered, additionalProvider.getClass(), null); + + } + } + + for (final Class<?> clazz : application.getClasses()) { + // We've already added the provider above. This is a duplicate + if (additionalProviders.contains(clazz)) continue; + + if (clazz.isInterface()) { + + applicationData.addInvalid(clazz, "is interface"); + + } else if (clazz.isEnum()) { + + applicationData.addInvalid(clazz, "is enum"); + + } else if (clazz.isPrimitive()) { + + applicationData.addInvalid(clazz, "is primitive"); + + } else { + + final boolean discovered = !declaredClasses.contains(clazz); + + applicationData.addResource(discovered, clazz, null); + + } + } + + for (final Object singleton : application.getSingletons()) { + // We've already added the provider above. This is a duplicate + if (additionalProviders.contains(singleton)) continue; + + final Class<?> clazz = realClass(singleton.getClass()); + + final boolean configured = declaredClasses.contains(clazz) || declaredClasses.contains(singleton.getClass()); + + applicationData.addResource(!configured, clazz, singleton); + } + + return applicationData; + } + /** * JAX-RS allows for the Application subclass to have @Context injectable fields, as is * the case for Resources and Providers. CXF will do the injection on the Application @@ -836,7 +930,7 @@ public class CxfRsHttpListener implements RsHttpListener { injectApplication(original, factory); return; } - + final Bus bus = factory.getBus(); new ApplicationInfo(application, bus); } diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/NoResourcesFoundException.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/NoResourcesFoundException.java new file mode 100644 index 0000000..310e735 --- /dev/null +++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/NoResourcesFoundException.java @@ -0,0 +1,23 @@ +/* + * 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.openejb.server.cxf.rs; + +public class NoResourcesFoundException extends IllegalArgumentException { + public NoResourcesFoundException(final ApplicationData applicationData) { + super("Application must contain at least one JAX-RS resource class: " + applicationData); + } +}
