You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2022/02/21 03:08:30 UTC
[tomee] 02/09: TOMEE-3844 Improve logging for JAX-RS application deployment
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 <db...@tomitribe.com>
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);
+ }
+}