diff --git a/extensions-support/httpclient5/deployment/src/main/java/org/apache/camel/quarkus/support/httpclient5/deployment/HttpClient5Processor.java b/extensions-support/httpclient5/deployment/src/main/java/org/apache/camel/quarkus/support/httpclient5/deployment/HttpClient5Processor.java index 57b66323b448..919fa54fb7c8 100644 --- a/extensions-support/httpclient5/deployment/src/main/java/org/apache/camel/quarkus/support/httpclient5/deployment/HttpClient5Processor.java +++ b/extensions-support/httpclient5/deployment/src/main/java/org/apache/camel/quarkus/support/httpclient5/deployment/HttpClient5Processor.java @@ -16,12 +16,24 @@ */ package org.apache.camel.quarkus.support.httpclient5.deployment; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Modifier; + +import io.quarkus.deployment.GeneratedClassGizmoAdaptor; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.GeneratedClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; +import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild; +import io.quarkus.gizmo.ClassCreator; +import io.quarkus.gizmo.MethodCreator; +import io.quarkus.gizmo.MethodDescriptor; +import org.apache.camel.quarkus.support.httpclient5.graal.BrotliAbsentBooleanSupplier; class HttpClient5Processor { + private static final String BROTLI_INPUT_STREAM_CLASS_NAME = "org.brotli.dec.BrotliInputStream"; private static final String NTLM_ENGINE_IMPL = "org.apache.hc.client5.http.impl.auth.NTLMEngineImpl"; @BuildStep @@ -34,4 +46,54 @@ NativeImageResourceBuildItem suffixListResource() { void runtimeInitializedClasses(BuildProducer runtimeInitializedClasses) { runtimeInitializedClasses.produce(new RuntimeInitializedClassBuildItem(NTLM_ENGINE_IMPL)); } + + @BuildStep(onlyIf = { NativeOrNativeSourcesBuild.class, BrotliAbsentBooleanSupplier.class }) + void generateBrotliInputStreamClass(BuildProducer generatedClass) { + try (ClassCreator classCreator = ClassCreator.builder() + .className(BROTLI_INPUT_STREAM_CLASS_NAME) + .superClass(InputStream.class) + .classOutput(new GeneratedClassGizmoAdaptor(generatedClass, false)) + .build()) { + + /* + * Creates a simplified impl of BrotliInputStream to satisfy the native compiler: + * + * public class BrotliInputStream extends InputStream { + * public BrotliInputStream() { + * } + * + * public BrotliInputStream(InputStream stream) { + * } + * + * public int read() { + * throw new UnsupportedOperationException(); + * } + * } + */ + + try (MethodCreator defaultConstructor = classCreator.getMethodCreator("", void.class)) { + defaultConstructor.setModifiers(Modifier.PUBLIC); + defaultConstructor.invokeSpecialMethod( + MethodDescriptor.ofMethod(BROTLI_INPUT_STREAM_CLASS_NAME, "", void.class), + defaultConstructor.getThis()); + defaultConstructor.returnValue(null); + } + + try (MethodCreator constructorWithInputStreamArg = classCreator.getMethodCreator("", void.class, + InputStream.class)) { + constructorWithInputStreamArg.setModifiers(Modifier.PUBLIC); + constructorWithInputStreamArg.invokeSpecialMethod( + MethodDescriptor.ofMethod(BROTLI_INPUT_STREAM_CLASS_NAME, "", void.class), + constructorWithInputStreamArg.getThis()); + constructorWithInputStreamArg.returnValue(null); + } + + try (MethodCreator readMethod = classCreator.getMethodCreator("read", int.class)) { + readMethod.setModifiers(Modifier.PUBLIC); + readMethod.addException(IOException.class); + readMethod.throwException(UnsupportedOperationException.class, + "Cannot read from BrotliInputStream. Add org.brotli:dec to the application classpath"); + } + } + } } diff --git a/extensions-support/httpclient5/runtime/pom.xml b/extensions-support/httpclient5/runtime/pom.xml index cc80f4e949a5..dce09d3f5de0 100644 --- a/extensions-support/httpclient5/runtime/pom.xml +++ b/extensions-support/httpclient5/runtime/pom.xml @@ -38,8 +38,9 @@ httpclient5 - org.brotli - dec + org.graalvm.sdk + nativeimage + provided diff --git a/extensions-support/httpclient5/runtime/src/main/java/org/apache/camel/quarkus/support/httpclient5/graal/BrotliAbsentBooleanSupplier.java b/extensions-support/httpclient5/runtime/src/main/java/org/apache/camel/quarkus/support/httpclient5/graal/BrotliAbsentBooleanSupplier.java new file mode 100644 index 000000000000..62b0c600d2bc --- /dev/null +++ b/extensions-support/httpclient5/runtime/src/main/java/org/apache/camel/quarkus/support/httpclient5/graal/BrotliAbsentBooleanSupplier.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.camel.quarkus.support.httpclient5.graal; + +import java.util.function.BooleanSupplier; + +public class BrotliAbsentBooleanSupplier implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + try { + Thread.currentThread().getContextClassLoader().loadClass("org.brotli.dec.BrotliInputStream"); + return false; + } catch (ClassNotFoundException e) { + return true; + } + } +} diff --git a/extensions-support/httpclient5/runtime/src/main/java/org/apache/camel/quarkus/support/httpclient5/graal/BrotliSubstitutions.java b/extensions-support/httpclient5/runtime/src/main/java/org/apache/camel/quarkus/support/httpclient5/graal/BrotliSubstitutions.java new file mode 100644 index 000000000000..bc2ffeba2dd6 --- /dev/null +++ b/extensions-support/httpclient5/runtime/src/main/java/org/apache/camel/quarkus/support/httpclient5/graal/BrotliSubstitutions.java @@ -0,0 +1,48 @@ +/* + * 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.support.httpclient5.graal; + +import java.io.IOException; +import java.io.InputStream; + +import com.oracle.svm.core.annotate.Substitute; +import com.oracle.svm.core.annotate.TargetClass; +import org.apache.hc.client5.http.entity.BrotliDecompressingEntity; +import org.apache.hc.client5.http.entity.BrotliInputStreamFactory; + +/** + * Remove references to optional brotli:dec dependency. + */ +final class BrotliSubstitutions { +} + +@TargetClass(value = BrotliInputStreamFactory.class, onlyWith = { BrotliAbsentBooleanSupplier.class }) +final class SubstituteBrotliInputStreamFactory { + @Substitute + public InputStream create(InputStream inputStream) throws IOException { + throw new UnsupportedOperationException( + "Cannot create BrotliInputStream. Add org.brotli:dec to the application classpath."); + } +} + +@TargetClass(value = BrotliDecompressingEntity.class, onlyWith = { BrotliAbsentBooleanSupplier.class }) +final class SubstituteBrotliDecompressingEntity { + @Substitute + public static boolean isAvailable() { + return false; + } +} diff --git a/extensions/saxon/deployment/pom.xml b/extensions/saxon/deployment/pom.xml index 0961cae76824..f04c5a1681d3 100644 --- a/extensions/saxon/deployment/pom.xml +++ b/extensions/saxon/deployment/pom.xml @@ -34,6 +34,10 @@ org.apache.camel.quarkus camel-quarkus-core-deployment + + org.apache.camel.quarkus + camel-quarkus-support-httpclient5-deployment + org.apache.camel.quarkus camel-quarkus-saxon diff --git a/extensions/saxon/runtime/pom.xml b/extensions/saxon/runtime/pom.xml index 6c595c5412af..26f00227dfad 100644 --- a/extensions/saxon/runtime/pom.xml +++ b/extensions/saxon/runtime/pom.xml @@ -41,12 +41,12 @@ camel-quarkus-core - org.apache.camel - camel-saxon + org.apache.camel.quarkus + camel-quarkus-support-httpclient5 - org.brotli - dec + org.apache.camel + camel-saxon diff --git a/extensions/xslt-saxon/deployment/pom.xml b/extensions/xslt-saxon/deployment/pom.xml index 35682994a71d..cb4e1b74f5a1 100644 --- a/extensions/xslt-saxon/deployment/pom.xml +++ b/extensions/xslt-saxon/deployment/pom.xml @@ -34,6 +34,10 @@ org.apache.camel.quarkus camel-quarkus-xslt-deployment + + org.apache.camel.quarkus + camel-quarkus-support-httpclient5-deployment + org.apache.camel.quarkus camel-quarkus-xslt-saxon diff --git a/extensions/xslt-saxon/runtime/pom.xml b/extensions/xslt-saxon/runtime/pom.xml index 0d3f7b81eb58..e6ab65c82c18 100644 --- a/extensions/xslt-saxon/runtime/pom.xml +++ b/extensions/xslt-saxon/runtime/pom.xml @@ -41,17 +41,12 @@ camel-quarkus-xslt - org.apache.camel - camel-xslt-saxon - - - org.brotli - dec + org.apache.camel.quarkus + camel-quarkus-support-httpclient5 - - org.apache.httpcomponents.core5 - httpcore5 + org.apache.camel + camel-xslt-saxon diff --git a/pom.xml b/pom.xml index e90c6092fb5f..ea30c5b05b94 100644 --- a/pom.xml +++ b/pom.xml @@ -82,7 +82,6 @@ 1.0.0-beta.21 3.7.1 1.79 - 0.1.2 3.1.8 ${commons-beanutils-version} 1.8.0 diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml index d8ce18c34f28..3a92a05d7650 100644 --- a/poms/bom/pom.xml +++ b/poms/bom/pom.xml @@ -7237,11 +7237,6 @@ bcutil-jdk18on ${bouncycastle.version} - - org.brotli - dec - ${brotli.version} - org.eclipse.angus angus-mail diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml b/poms/bom/src/main/generated/flattened-full-pom.xml index 9201fa30124a..00b96071ed1c 100644 --- a/poms/bom/src/main/generated/flattened-full-pom.xml +++ b/poms/bom/src/main/generated/flattened-full-pom.xml @@ -7159,11 +7159,6 @@ bcutil-jdk18on 1.79 - - org.brotli - dec - 0.1.2 - org.eclipse.angus angus-mail diff --git a/poms/bom/src/main/generated/flattened-reduced-pom.xml b/poms/bom/src/main/generated/flattened-reduced-pom.xml index 3fdbd164d1d7..19df91c8ce2e 100644 --- a/poms/bom/src/main/generated/flattened-reduced-pom.xml +++ b/poms/bom/src/main/generated/flattened-reduced-pom.xml @@ -7109,11 +7109,6 @@ bcutil-jdk18on 1.79 - - org.brotli - dec - 0.1.2 - org.eclipse.angus angus-mail diff --git a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml index 4ea40052f010..262d7ce295bd 100644 --- a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml +++ b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml @@ -7109,11 +7109,6 @@ bcutil-jdk18on 1.79 - - org.brotli - dec - 0.1.2 - org.eclipse.angus angus-mail