Skip to content

Commit

Permalink
Workaround for RestProducer on Java 11
Browse files Browse the repository at this point in the history
  • Loading branch information
lburgazzoli committed Apr 2, 2020
1 parent 075bf62 commit c3ef475
Show file tree
Hide file tree
Showing 8 changed files with 778 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,86 @@
*/
package org.apache.camel.quarkus.component.rest.deployment;

import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import org.apache.camel.component.rest.RestComponent;
import org.apache.camel.quarkus.component.rest.RestRecorder;
import org.apache.camel.quarkus.component.rest.graal.NoJAXBContext;
import org.apache.camel.quarkus.core.deployment.CamelBeanBuildItem;
import org.apache.camel.quarkus.core.deployment.CamelServiceFilter;
import org.apache.camel.quarkus.core.deployment.CamelServiceFilterBuildItem;
import org.apache.camel.quarkus.support.common.CamelCapabilities;

class RestProcessor {

private static final String FEATURE = "camel-rest";

@BuildStep
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}

//
// RestAssured brings XML bind APIs to the classpath:
//
// [INFO] +- io.rest-assured:rest-assured:jar:4.3.0:test
// [INFO] | +- org.codehaus.groovy:groovy:jar:3.0.2:test
// [INFO] | +- org.codehaus.groovy:groovy-xml:jar:3.0.2:test
// [INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.11:test
// [INFO] | | +- org.apache.httpcomponents:httpcore:jar:4.4.13:test
// [INFO] | | \- commons-codec:commons-codec:jar:1.13:test
// [INFO] | +- org.apache.httpcomponents:httpmime:jar:4.5.3:test
// [INFO] | +- org.hamcrest:hamcrest:jar:2.1:test
// [INFO] | +- org.ccil.cowan.tagsoup:tagsoup:jar:1.2.1:test
// [INFO] | +- io.rest-assured:json-path:jar:4.3.0:test
// [INFO] | | +- org.codehaus.groovy:groovy-json:jar:3.0.2:test
// [INFO] | | \- io.rest-assured:rest-assured-common:jar:4.3.0:test
// >> [INFO] | \- io.rest-assured:xml-path:jar:4.3.0:test
// [INFO] | +- org.apache.commons:commons-lang3:jar:3.9:test
// >> [INFO] | +- jakarta.xml.bind:jakarta.xml.bind-api:jar:2.3.2:test
// [INFO] | | \- jakarta.activation:jakarta.activation-api:jar:1.2.1:test
// [INFO] | \- org.apache.sling:org.apache.sling.javax.activation:jar:0.1.0:test
//
// For tests in JVM mode the condition NoJAXBContext is always false as a consequence of
// RestAssured transitive dependencies so we need an additional check on the presence of
// the org.apache.camel.xml.jaxb feature to make the behaviour consistent ion both modes.
//
// Excluding io.rest-assured:xml-path from the transitive dependencies does not seem to work
// as it lead to the RestAssured framework to fail to instantiate.
//

@BuildStep(onlyIf = NoJAXBContext.class)
void serviceFilter(
Capabilities capabilities,
BuildProducer<CamelServiceFilterBuildItem> serviceFilter) {

// if jaxb is configured, don't replace the method
if (capabilities.isCapabilityPresent(CamelCapabilities.XML_JAXB)) {
return;
}

serviceFilter.produce(new CamelServiceFilterBuildItem(CamelServiceFilter.forComponent("rest")));
}

@Record(ExecutionTime.STATIC_INIT)
@BuildStep(onlyIf = NoJAXBContext.class)
void restComponent(
RestRecorder recorder,
Capabilities capabilities,
BuildProducer<CamelBeanBuildItem> camelBeans) {

// if jaxb is configured, don't replace the method
if (capabilities.isCapabilityPresent(CamelCapabilities.XML_JAXB)) {
return;
}

camelBeans.produce(
new CamelBeanBuildItem(
"rest",
RestComponent.class.getName(),
recorder.createRestComponent()));
}
}
5 changes: 5 additions & 0 deletions extensions/rest/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-rest</artifactId>
</dependency>

<dependency>
<groupId>org.graalvm.nativeimage</groupId>
<artifactId>svm</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* 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.camel.quarkus.component.rest;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.component.rest.RestComponent;
import org.apache.camel.spi.RestConfiguration;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.URISupport;

public class QuarkusRestComponent extends RestComponent {
@Override
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
String cname = getAndRemoveParameter(parameters, "consumerComponentName", String.class, getConsumerComponentName());
String pname = getAndRemoveParameter(parameters, "producerComponentName", String.class, getProducerComponentName());

QuarkusRestEndpoint answer = new QuarkusRestEndpoint(uri, this);
answer.setConsumerComponentName(cname);
answer.setProducerComponentName(pname);
answer.setApiDoc(getApiDoc());

RestConfiguration config = new RestConfiguration();
mergeConfigurations(getCamelContext(), config, findGlobalRestConfiguration());
mergeConfigurations(getCamelContext(), config, getCamelContext().getRestConfiguration(cname, false));
mergeConfigurations(getCamelContext(), config, getCamelContext().getRestConfiguration(pname, false));

// if no explicit host was given, then fallback and use default configured host
String h = getAndRemoveOrResolveReferenceParameter(parameters, "host", String.class, getHost());
if (h == null) {
h = config.getHost();
int port = config.getPort();
// is there a custom port number
if (port > 0 && port != 80 && port != 443) {
h += ":" + port;
}
}
// host must start with http:// or https://
if (h != null && !(h.startsWith("http://") || h.startsWith("https://"))) {
h = "http://" + h;
}
answer.setHost(h);

setProperties(answer, parameters);
if (!parameters.isEmpty()) {
// use only what remains and at this point parameters that have been used have been removed
// without overwriting any query parameters set via queryParameters endpoint option
final Map<String, Object> queryParameters = new LinkedHashMap<>(parameters);
final Map<String, Object> existingQueryParameters = URISupport.parseQuery(answer.getQueryParameters());
queryParameters.putAll(existingQueryParameters);

final String remainingParameters = URISupport.createQueryString(queryParameters);
answer.setQueryParameters(remainingParameters);
}

answer.setParameters(parameters);

if (!remaining.contains(":")) {
throw new IllegalArgumentException(
"Invalid syntax. Must be rest:method:path[:uriTemplate] where uriTemplate is optional");
}

String method = StringHelper.before(remaining, ":");
String s = StringHelper.after(remaining, ":");

String path;
String uriTemplate;
if (s != null && s.contains(":")) {
path = StringHelper.before(s, ":");
uriTemplate = StringHelper.after(s, ":");
} else {
path = s;
uriTemplate = null;
}

// remove trailing slashes
path = FileUtil.stripTrailingSeparator(path);
uriTemplate = FileUtil.stripTrailingSeparator(uriTemplate);

answer.setMethod(method);
answer.setPath(path);
answer.setUriTemplate(uriTemplate);

// if no explicit component name was given, then fallback and use default configured component name
if (answer.getProducerComponentName() == null) {
String name = config.getProducerComponent();
answer.setProducerComponentName(name);
}
if (answer.getConsumerComponentName() == null) {
String name = config.getComponent();
answer.setConsumerComponentName(name);
}
// if no explicit producer api was given, then fallback and use default configured
if (answer.getApiDoc() == null) {
answer.setApiDoc(config.getProducerApiDoc());
}

return answer;
}

private RestConfiguration findGlobalRestConfiguration() {
CamelContext context = getCamelContext();

RestConfiguration conf = CamelContextHelper.lookup(context, DEFAULT_REST_CONFIGURATION_ID, RestConfiguration.class);
if (conf == null) {
conf = CamelContextHelper.findByType(getCamelContext(), RestConfiguration.class);
}

return conf;
}

private RestConfiguration mergeConfigurations(CamelContext camelContext, RestConfiguration conf, RestConfiguration from)
throws Exception {
if (conf == from) {
return conf;
}
if (from != null) {
// Merge properties
conf.setComponent(or(conf.getComponent(), from.getComponent()));
conf.setApiComponent(or(conf.getApiComponent(), from.getApiComponent()));
conf.setProducerComponent(or(conf.getProducerComponent(), from.getProducerComponent()));
conf.setProducerApiDoc(or(conf.getProducerApiDoc(), from.getProducerApiDoc()));
conf.setScheme(or(conf.getScheme(), from.getScheme()));
conf.setHost(or(conf.getHost(), from.getHost()));
conf.setUseXForwardHeaders(or(conf.isUseXForwardHeaders(), from.isUseXForwardHeaders()));
conf.setApiHost(or(conf.getApiHost(), from.getApiHost()));
conf.setPort(or(conf.getPort(), from.getPort()));
conf.setContextPath(or(conf.getContextPath(), from.getContextPath()));
conf.setApiContextPath(or(conf.getApiContextPath(), from.getApiContextPath()));
conf.setApiContextRouteId(or(conf.getApiContextRouteId(), from.getApiContextRouteId()));
conf.setApiContextIdPattern(or(conf.getApiContextIdPattern(), from.getApiContextIdPattern()));
conf.setApiContextListing(or(conf.isApiContextListing(), from.isApiContextListing()));
conf.setApiVendorExtension(or(conf.isApiVendorExtension(), from.isApiVendorExtension()));
conf.setHostNameResolver(or(conf.getHostNameResolver(), from.getHostNameResolver(),
RestConfiguration.RestHostNameResolver.allLocalIp));
conf.setBindingMode(or(conf.getBindingMode(), from.getBindingMode(), RestConfiguration.RestBindingMode.off));
conf.setSkipBindingOnErrorCode(or(conf.isSkipBindingOnErrorCode(), from.isSkipBindingOnErrorCode()));
conf.setClientRequestValidation(or(conf.isClientRequestValidation(), from.isClientRequestValidation()));
conf.setEnableCORS(or(conf.isEnableCORS(), from.isEnableCORS()));
conf.setJsonDataFormat(or(conf.getJsonDataFormat(), from.getJsonDataFormat()));
conf.setXmlDataFormat(or(conf.getXmlDataFormat(), from.getXmlDataFormat()));
conf.setComponentProperties(mergeProperties(conf.getComponentProperties(), from.getComponentProperties()));
conf.setEndpointProperties(mergeProperties(conf.getEndpointProperties(), from.getEndpointProperties()));
conf.setConsumerProperties(mergeProperties(conf.getConsumerProperties(), from.getConsumerProperties()));
conf.setDataFormatProperties(mergeProperties(conf.getDataFormatProperties(), from.getDataFormatProperties()));
conf.setApiProperties(mergeProperties(conf.getApiProperties(), from.getApiProperties()));
conf.setCorsHeaders(mergeProperties(conf.getCorsHeaders(), from.getCorsHeaders()));
}

return conf;
}

private <T> T or(T t1, T t2) {
return t2 != null ? t2 : t1;
}

private <T> T or(T t1, T t2, T def) {
return t2 != null && t2 != def ? t2 : t1;
}

private <T> Map<String, T> mergeProperties(Map<String, T> base, Map<String, T> addons) {
if (base != null || addons != null) {
Map<String, T> result = new HashMap<>();
if (base != null) {
result.putAll(base);
}
if (addons != null) {
result.putAll(addons);
}
return result;
}
return base;
}
}

0 comments on commit c3ef475

Please sign in to comment.