From 569b6c6ae568443f80bee5404312e98c9894737a Mon Sep 17 00:00:00 2001 From: Guillaume Dufour Date: Sat, 14 Sep 2019 03:58:39 +0200 Subject: [PATCH] Init CXF extension fix #4005 --- bom/deployment/pom.xml | 5 + bom/runtime/pom.xml | 16 +++ .../builditem/FeatureBuildItem.java | 1 + extensions/cxf/deployment/pom.xml | 53 +++++++++ .../io/quarkus/cxf/deployment/CxfConfig.java | 23 ++++ .../quarkus/cxf/deployment/CxfProcessor.java | 105 ++++++++++++++++++ .../deployment/CxfServerConfigBuildItem.java | 28 +++++ extensions/cxf/pom.xml | 21 ++++ extensions/cxf/runtime/pom.xml | 55 +++++++++ .../cxf/runtime/CXFQuarkusServlet.java | 76 +++++++++++++ extensions/pom.xml | 3 + 11 files changed, 386 insertions(+) create mode 100644 extensions/cxf/deployment/pom.xml create mode 100644 extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfConfig.java create mode 100755 extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfProcessor.java create mode 100644 extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfServerConfigBuildItem.java create mode 100644 extensions/cxf/pom.xml create mode 100644 extensions/cxf/runtime/pom.xml create mode 100644 extensions/cxf/runtime/src/main/java/io/quarkus/cxf/runtime/CXFQuarkusServlet.java diff --git a/bom/deployment/pom.xml b/bom/deployment/pom.xml index 36db4d9d9e542..1a140bda658f8 100644 --- a/bom/deployment/pom.xml +++ b/bom/deployment/pom.xml @@ -226,6 +226,11 @@ quarkus-resteasy-jsonb-deployment ${project.version} + + io.quarkus + quarkus-cxf-deployment + ${project.version} + io.quarkus quarkus-smallrye-jwt-deployment diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml index 5d013febb2d55..6fd1a5f4764c9 100644 --- a/bom/runtime/pom.xml +++ b/bom/runtime/pom.xml @@ -164,6 +164,7 @@ 2.1.9.RELEASE 2.4.4.Final 3.0.0 + 3.3.3 @@ -463,6 +464,11 @@ quarkus-resteasy-server-common ${project.version} + + io.quarkus + quarkus-cxf + ${project.version} + io.quarkus quarkus-narayana-jta @@ -1116,6 +1122,16 @@ artemis-jms-client ${artemis.version} + + org.apache.cxf + cxf-rt-frontend-jaxws + ${cxf.version} + + + org.apache.cxf + cxf-rt-transports-http + ${cxf.version} + org.apache.httpcomponents httpclient diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java index d210e04984d7e..3199b4a207edd 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/FeatureBuildItem.java @@ -13,6 +13,7 @@ public final class FeatureBuildItem extends MultiBuildItem { public static final String ARTEMIS_CORE = "artemis-core"; public static final String ARTEMIS_JMS = "artemis-jms"; public static final String CDI = "cdi"; + public static final String CXF = "cxf"; public static final String DYNAMODB = "dynamodb"; public static final String ELASTICSEARCH_REST_CLIENT = "elasticsearch-rest-client"; public static final String FLYWAY = "flyway"; diff --git a/extensions/cxf/deployment/pom.xml b/extensions/cxf/deployment/pom.xml new file mode 100644 index 0000000000000..ee7d1b5ffd739 --- /dev/null +++ b/extensions/cxf/deployment/pom.xml @@ -0,0 +1,53 @@ + + + + quarkus-cxf-parent + io.quarkus + 999-SNAPSHOT + ../ + + 4.0.0 + + quarkus-cxf-deployment + Quarkus - CXF - Deployment + + + + io.quarkus + quarkus-core-deployment + + + io.quarkus + quarkus-cxf + + + io.quarkus + quarkus-undertow-deployment + + + org.jboss.spec.javax.xml.ws + jboss-jaxws-api_2.3_spec + 2.0.0.Final + + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + + diff --git a/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfConfig.java b/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfConfig.java new file mode 100644 index 0000000000000..649acf583d0d0 --- /dev/null +++ b/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfConfig.java @@ -0,0 +1,23 @@ +package io.quarkus.cxf.deployment; + +import java.util.Map; + +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot(name = "cxf") +final class CxfConfig { + + /** + * Set this to override the default path for JAX-RS resources if there are no + * annotated application classes. + */ + @ConfigItem(defaultValue = "/") + String path; + + /** + * Choose the path of each web services. + */ + @ConfigItem(name = "webservice") + Map webServicesByPaths; +} \ No newline at end of file diff --git a/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfProcessor.java b/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfProcessor.java new file mode 100755 index 0000000000000..173deee4f84e0 --- /dev/null +++ b/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfProcessor.java @@ -0,0 +1,105 @@ +package io.quarkus.cxf.deployment; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; + +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.DotName; +import org.jboss.jandex.IndexView; + +import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem; +import io.quarkus.arc.deployment.UnremovableBeanBuildItem; +import io.quarkus.cxf.runtime.CXFQuarkusServlet; +import io.quarkus.deployment.annotations.BuildProducer; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem; +import io.quarkus.deployment.builditem.CombinedIndexBuildItem; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.substrate.ReflectiveClassBuildItem; +import io.quarkus.deployment.builditem.substrate.ReflectiveHierarchyBuildItem; +import io.quarkus.deployment.builditem.substrate.RuntimeInitializedClassBuildItem; +import io.quarkus.deployment.builditem.substrate.SubstrateProxyDefinitionBuildItem; +import io.quarkus.deployment.builditem.substrate.SubstrateResourceBuildItem; +import io.quarkus.undertow.deployment.ServletBuildItem; +import io.quarkus.undertow.deployment.ServletInitParamBuildItem; + +/** + * Processor that finds JAX-RS classes in the deployment + */ +public class CxfProcessor { + + private static final String JAX_WS_CXF_SERVLET = "org.apache.cxf.transport.servlet.CXFNonSpringServlet"; + + private static final DotName WEBSERVICE_ANNOTATION = DotName.createSimple("javax.jws.WebService"); + + /** + * JAX-RS configuration. + */ + CxfConfig cxfConfig; + + @BuildStep + public void build( + BuildProducer reflectiveClass, + BuildProducer reflectiveHierarchy, + BuildProducer proxyDefinition, + BuildProducer resource, + BuildProducer runtimeClasses, + BuildProducer transformers, + BuildProducer cxfServerConfig, + BuildProducer unremovableBeans, + CombinedIndexBuildItem combinedIndexBuildItem, + BeanArchiveIndexBuildItem beanArchiveIndexBuildItem) throws Exception { + IndexView index = combinedIndexBuildItem.getIndex(); + + for (AnnotationInstance annotation : index.getAnnotations(WEBSERVICE_ANNOTATION)) { + if (annotation.target().kind() == AnnotationTarget.Kind.CLASS) { + reflectiveClass + .produce(new ReflectiveClassBuildItem(true, true, annotation.target().asClass().name().toString())); + } + } + + Map cxfInitParameters = new HashMap<>(); + + cxfServerConfig.produce(new CxfServerConfigBuildItem(cxfConfig.path, cxfInitParameters)); + } + + @BuildStep + public void build( + Optional cxfServerConfig, + BuildProducer feature, + BuildProducer servlet, + BuildProducer reflectiveClass, + BuildProducer servletInitParameters) throws Exception { + feature.produce(new FeatureBuildItem(FeatureBuildItem.CXF)); + + if (cxfServerConfig.isPresent()) { + String path = cxfServerConfig.get().getPath(); + + String mappingPath = getMappingPath(path); + servlet.produce(ServletBuildItem.builder(JAX_WS_CXF_SERVLET, CXFQuarkusServlet.class.getName()) + .setLoadOnStartup(1).addMapping(mappingPath).setAsyncSupported(true).build()); + reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, CXFQuarkusServlet.class.getName())); + + for (Entry initParameter : cxfServerConfig.get().getInitParameters().entrySet()) { + servletInitParameters.produce(new ServletInitParamBuildItem(initParameter.getKey(), initParameter.getValue())); + } + + for (Entry webServicesByPath : cxfConfig.webServicesByPaths.entrySet()) { + CXFQuarkusServlet.publish(webServicesByPath.getKey(), webServicesByPath.getValue()); + } + } + } + + private String getMappingPath(String path) { + String mappingPath; + if (path.endsWith("/")) { + mappingPath = path + "*"; + } else { + mappingPath = path + "/*"; + } + return mappingPath; + } +} diff --git a/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfServerConfigBuildItem.java b/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfServerConfigBuildItem.java new file mode 100644 index 0000000000000..f989b8724c6c0 --- /dev/null +++ b/extensions/cxf/deployment/src/main/java/io/quarkus/cxf/deployment/CxfServerConfigBuildItem.java @@ -0,0 +1,28 @@ +package io.quarkus.cxf.deployment; + +import java.util.Map; + +import io.quarkus.builder.item.SimpleBuildItem; + +/** + * A build item that represents the configuration of the RESTEasy server. + */ +public final class CxfServerConfigBuildItem extends SimpleBuildItem { + + private final String path; + + private final Map initParameters; + + public CxfServerConfigBuildItem(String path, Map initParameters) { + this.path = path; + this.initParameters = initParameters; + } + + public String getPath() { + return path; + } + + public Map getInitParameters() { + return initParameters; + } +} diff --git a/extensions/cxf/pom.xml b/extensions/cxf/pom.xml new file mode 100644 index 0000000000000..c9cb89668fa13 --- /dev/null +++ b/extensions/cxf/pom.xml @@ -0,0 +1,21 @@ + + + + quarkus-build-parent + io.quarkus + 999-SNAPSHOT + ../../build-parent/pom.xml + + 4.0.0 + + quarkus-cxf-parent + Quarkus - CXF + pom + + deployment + runtime + + + diff --git a/extensions/cxf/runtime/pom.xml b/extensions/cxf/runtime/pom.xml new file mode 100644 index 0000000000000..942ee3b5a3d36 --- /dev/null +++ b/extensions/cxf/runtime/pom.xml @@ -0,0 +1,55 @@ + + + + quarkus-cxf-parent + io.quarkus + 999-SNAPSHOT + ../ + + 4.0.0 + + quarkus-cxf + Quarkus - CXF - Runtime + + + + org.apache.cxf + cxf-rt-frontend-jaxws + + + org.apache.cxf + cxf-rt-transports-http + + + org.jboss.spec.javax.servlet + jboss-servlet-api_4.0_spec + + + org.slf4j + slf4j-api + + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + diff --git a/extensions/cxf/runtime/src/main/java/io/quarkus/cxf/runtime/CXFQuarkusServlet.java b/extensions/cxf/runtime/src/main/java/io/quarkus/cxf/runtime/CXFQuarkusServlet.java new file mode 100644 index 0000000000000..c00cb171d36c5 --- /dev/null +++ b/extensions/cxf/runtime/src/main/java/io/quarkus/cxf/runtime/CXFQuarkusServlet.java @@ -0,0 +1,76 @@ +package io.quarkus.cxf.runtime; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.ServletConfig; + +import org.apache.cxf.Bus; +import org.apache.cxf.BusFactory; +import org.apache.cxf.frontend.ServerFactoryBean; +import org.apache.cxf.transport.servlet.CXFNonSpringServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CXFQuarkusServlet extends CXFNonSpringServlet { + + private static final Logger LOGGER = LoggerFactory.getLogger(CXFQuarkusServlet.class); + + public static class WebServiceConfig { + private String path; + private String className; + + public WebServiceConfig(String path, String className) { + super(); + this.path = path; + this.className = className; + } + + public String getClassName() { + return className; + } + + public String getPath() { + return path; + } + + @Override + public String toString() { + return "Web Service " + className + " on " + path; + } + + } + + private static final long serialVersionUID = 1L; + + private static final List WEB_SERVICES = new ArrayList<>(); + + @Override + public void loadBus(ServletConfig servletConfig) { + super.loadBus(servletConfig); + + // You could add the endpoint publish codes here + Bus bus = getBus(); + BusFactory.setDefaultBus(bus); + + // You can als use the simple frontend API to do this + ServerFactoryBean factory = new ServerFactoryBean(); + factory.setBus(bus); + + for (WebServiceConfig config : WEB_SERVICES) { + try { + Class serviceClass = Thread.currentThread().getContextClassLoader().loadClass(config.getClassName()); + + factory.setServiceClass(serviceClass); + factory.setAddress(config.getPath()); + factory.create(); + } catch (ClassNotFoundException e) { + LOGGER.error("Cannot initialize " + config.toString(), e); + } + } + } + + public static void publish(String path, String webService) { + WEB_SERVICES.add(new WebServiceConfig(path, webService)); + } +} diff --git a/extensions/pom.xml b/extensions/pom.xml index a7c5552c02d95..756fe8c17e315 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -48,6 +48,9 @@ smallrye-openapi swagger-ui + + cxf + vertx vertx-web