You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/03/06 04:52:35 UTC
(camel) branch main updated: CAMEL-20519: Servlet documentation improvements (#13385)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 0958ebb0f2a CAMEL-20519: Servlet documentation improvements (#13385)
0958ebb0f2a is described below
commit 0958ebb0f2ab51cb5576b62eb27c6be50aec7f17
Author: James Netherton <ja...@users.noreply.github.com>
AuthorDate: Wed Mar 6 04:52:30 2024 +0000
CAMEL-20519: Servlet documentation improvements (#13385)
---
.../src/main/docs/servlet-component.adoc | 379 +++++----------------
1 file changed, 94 insertions(+), 285 deletions(-)
diff --git a/components/camel-servlet/src/main/docs/servlet-component.adoc b/components/camel-servlet/src/main/docs/servlet-component.adoc
index 7bf03d341b4..2400c355df6 100644
--- a/components/camel-servlet/src/main/docs/servlet-component.adoc
+++ b/components/camel-servlet/src/main/docs/servlet-component.adoc
@@ -84,114 +84,24 @@ Therefore, it should be used only as input into your Camel routes. To
issue HTTP requests against other HTTP endpoints, use the
xref:http-component.adoc[HTTP Component].
-== Putting Camel JARs in the app server boot classpath
+== Example `CamelHttpTransportServlet` configuration
-If you put the Camel JARs such as `camel-core`, `camel-servlet`, etc. in
-the boot classpath of your application server (e.g., usually in its lib
-directory), then mind that the servlet mapping list is now shared
-between multiple deployed Camel application in the app server.
+=== Camel Spring Boot / Camel Quarkus
-Mind that putting Camel JARs in the boot classpath of the application
-server is generally not best practice!
+When running camel-servlet on the Spring Boot or Camel Quarkus runtimes, `CamelHttpTransportServlet` is configured for
+you automatically and is driven by configuration properties. Refer to the camel-servlet configuration documentation for these runtimes.
-So in those situations you *must* define a custom and unique servlet
-name in each of your Camel applications, e.g., in the `web.xml` define:
+=== Servlet container / application server
-[source,xml]
----------------------------------------------------------------------------------------------
-<servlet>
- <servlet-name>MyServlet</servlet-name>
- <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
- <load-on-startup>1</load-on-startup>
-</servlet>
-
-<servlet-mapping>
- <servlet-name>MyServlet</servlet-name>
- <url-pattern>/*</url-pattern>
-</servlet-mapping>
----------------------------------------------------------------------------------------------
-
-And in your Camel endpoints then include the servlet name as well
-
-[source,xml]
----------------------------------------------------
-<route>
- <from uri="servlet://foo?servletName=MyServlet"/>
- ...
-</route>
----------------------------------------------------
-
-Camel detects this duplicate and fails to
-start the application. You can control to ignore this duplicate by
-setting the servlet init-parameter ignoreDuplicateServletName to true as
-follows:
-
-[source,xml]
------------------------------------------------------------------------------------------------
- <servlet>
- <servlet-name>CamelServlet</servlet-name>
- <display-name>Camel Http Transport Servlet</display-name>
- <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
- <init-param>
- <param-name>ignoreDuplicateServletName</param-name>
- <param-value>true</param-value>
- </init-param>
- </servlet>
------------------------------------------------------------------------------------------------
-
-But it is *strongly advised* to use unique `servlet-name` for each Camel
-application to avoid this duplication clash, as well any unforeseen
-side effects.
-
-== Servlet >= 3.0 and AsyncContext
-
-To enable Camel to benefit from Servlet asynchronous support, you must:
+If you're running Camel standalone on a Servlet container or application server, you can use `web.xml` to configure `CamelHttpTransportServlet`.
-. Enable `async` boolean init parameter by setting it to `true`
-. Without more configuration it will reuse servlet thread pool to handle the processing, but you can set `executorRef` to an executor service reference to let another pool handle the processing of the exchange.
-It will use camel context registry by default and potentially fallback on an executor policy or default executor service if no bean matches this name.
-
-Note that to force camel to get back pre-3.7.0 behavior which was to wait in another container background thread, you can set `forceAwait` boolean init parameter to `true`.
-
-Sample async configuration:
-
-[source,xml]
------------------------------------------------------------------------------------------------
- <servlet>
- <servlet-name>CamelServlet</servlet-name>
- <display-name>Camel Http Transport Servlet</display-name>
- <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
- <init-param>
- <param-name>async</param-name>
- <param-value>true</param-value>
- </init-param>
- <init-param>
- <param-name>executorRef</param-name>
- <param-value>my-threads</param-value>
- </init-param>
- </servlet>
------------------------------------------------------------------------------------------------
-
-
-== Sample
-
-Use xref:servlet-component.adoc[Servlet] in Spring web applications for simplicity's sake.
-In this sample, we define a route that exposes an HTTP service at
-http://localhost:8080/camel/services/hello.
-
-First, you need to publish the
-https://github.com/apache/camel/blob/main/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java[CamelHttpTransportServlet]
-through the normal Web Container, or OSGi Service. Use the `Web.xml` file to publish the
-https://github.com/apache/camel/blob/main/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java[CamelHttpTransportServlet]
-as follows:
+For example, to define a route that exposes an HTTP service under the path `/services`.
[source,xml]
-------------------------------------------------------------------------
<web-app>
-
<servlet>
<servlet-name>CamelServlet</servlet-name>
- <display-name>Camel Http Transport Servlet</display-name>
<servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
</servlet>
@@ -199,226 +109,125 @@ as follows:
<servlet-name>CamelServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
-
</web-app>
-------------------------------------------------------------------------
-
-Then you can define your route as follows:
+== Example route
[source,java]
-------------------------------------------------------------------------
-from("servlet:hello?matchOnUriPrefix=true").process(new Processor() {
+from("servlet:hello").process(new Processor() {
public void process(Exchange exchange) throws Exception {
- String contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class);
- String path = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
- path = path.substring(path.lastIndexOf("/"));
-
- assertEquals(CONTENT_TYPE, contentType, "Get a wrong content type");
- // assert camel http header
- String charsetEncoding = exchange.getIn().getHeader(Exchange.HTTP_CHARACTER_ENCODING, String.class);
- assertEquals(charsetEncoding, "Get a wrong charset name from the message heaer", "UTF-8");
- // assert exchange charset
- assertEquals(exchange.getProperty(Exchange.CHARSET_NAME), "Get a wrong charset naem from the exchange property", "UTF-8");
- exchange.getOut().setHeader(Exchange.CONTENT_TYPE, contentType + "; charset=UTF-8");
- exchange.getOut().setHeader("PATH", path);
- exchange.getOut().setBody("<b>Hello World</b>");
+ // Access HTTP headers sent by the client
+ Message message = exchange.getMessage();
+ String contentType = message.getHeader(Exchange.CONTENT_TYPE, String.class);
+ String httpUri = message.getHeader(Exchange.HTTP_URI, String.class);
+
+ // Set the response body
+ message.setBody("<b>Got Content-Type: " + contentType = ", URI: " + httpUri + "</b>");
}
});
-------------------------------------------------------------------------
-[NOTE]
-====
-*Specify the relative path for camel-servlet endpoint*
-
-Since we are binding the HTTP transport with a published servlet, and we
-don't know the servlet's application context path, the `camel-servlet`
-endpoint uses the relative path to specify the endpoint's URL. A client
-can access the `camel-servlet` endpoint through the servlet publish
-address: `("http://localhost:8080/camel/services") + RELATIVE_PATH("/hello")`
-====
+== Camel Servlet HTTP endpoint path
-=== Sample when using Spring
+The full path where the camel-servlet HTTP endpoint is published depends on:
-When using the Servlet component in a Camel/Spring application, it's
-often required to load the Spring ApplicationContext _after_ the Servlet
-component has started. This can be accomplished by using Spring's
-`ContextLoaderServlet` instead of `ContextLoaderListener`. In that case
-you'll need to start `ContextLoaderServlet` after
-https://github.com/apache/camel/blob/main/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java[CamelHttpTransportServlet]
-like this:
+* The Servlet application context path
+* The configured Servlet mapping URL patterns
+* The camel-servlet endpoint URI context path
-[source,xml]
--------------------------------------------------------------------------
-<web-app>
- <servlet>
- <servlet-name>CamelServlet</servlet-name>
- <servlet-class>
- org.apache.camel.component.servlet.CamelHttpTransportServlet
- </servlet-class>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet>
- <servlet-name>SpringApplicationContext</servlet-name>
- <servlet-class>
- org.springframework.web.context.ContextLoaderServlet
- </servlet-class>
- <load-on-startup>2</load-on-startup>
- </servlet>
-<web-app>
--------------------------------------------------------------------------
+For example, if the application context path is `/camel` and `CamelHttpTransportServlet` is configured with a URL mapping of `/services/*`.
+Then a Camel route like `from("servlet:hello")` would be published to a path like http://localhost:8080/camel/services/hello.
-=== Sample when using OSGi
+== Servlet asynchronous support
-You can publish the
-https://github.com/apache/camel/blob/main/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java[CamelHttpTransportServlet]
-as an OSGi service with Blueprint like this:
+To enable Camel to benefit from Servlet asynchronous support, you must enable the `async` boolean init parameter by setting it to `true`.
-[source,xml]
--------------------------------------------------------------------------
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="
- http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
-
- <bean id="camelServlet" class="org.apache.camel.component.servlet.CamelHttpTransportServlet" />
-
- <!--
- Enlist it in OSGi service registry.
- This will cause two things:
- 1) As the pax web whiteboard extender is running the CamelServlet will
- be registered with the OSGi HTTP Service
- 2) It will trigger the HttpRegistry in other bundles so the servlet is
- made known there too
- -->
- <service ref="camelServlet">
- <interfaces>
- <value>javax.servlet.Servlet</value>
- <value>org.apache.camel.http.common.CamelServlet</value>
- </interfaces>
- <service-properties>
- <entry key="alias" value="/camel/services" />
- <entry key="matchOnUriPrefix" value="true" />
- <entry key="servlet-name" value="CamelServlet" />
- </service-properties>
- </service>
-
-</blueprint>
--------------------------------------------------------------------------
+By default, the servlet thread pool is used for exchange processing. However, to use a custom thread pool, you can configure an init parameter named `executorRef` with the String value set to the name of a bean bound to the Camel registry of type `Executor`.
+If no bean was found in the Camel registry, the Servlet component will attempt to fall back on an executor policy or default executor service.
-Then use this service in your Camel route like this:
+If you want to force exchange processing to wait in another container background thread, you can set the `forceAwait` boolean init parameter to `true`.
-[source,xml]
--------------------------------------------------------------------------
-<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
- xmlns:ext="http://aries.apache.org/blueprint/xmlns/blueprint-ext/v1.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="
- http://www.osgi.org/xmlns/blueprint/v1.0.0 https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+On the Camel Quarkus runtime, these init parameters can be set via configuration properties. Refer to the Camel Quarkus Servlet extension documentation for more information.
- <reference id="servletref" ext:proxy-method="classes" interface="org.apache.camel.http.common.CamelServlet">
- <reference-listener ref="httpRegistry" bind-method="register" unbind-method="unregister" />
- </reference>
+On other runtimes you can configure these parameters in `web.xml` as follows.
- <bean id="httpRegistry" class="org.apache.camel.component.servlet.DefaultHttpRegistry" />
+[source,xml]
+-----------------------------------------------------------------------------------------------
+<web-app>
+ <servlet>
+ <servlet-name>CamelServlet</servlet-name>
+ <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
+ <init-param>
+ <param-name>async</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>executorRef</param-name>
+ <param-value>my-custom-thread-pool</param-value>
+ </init-param>
+ </servlet>
- <bean id="servlet" class="org.apache.camel.component.servlet.ServletComponent">
- <property name="httpRegistry" ref="httpRegistry" />
- </bean>
+ <servlet-mapping>
+ <servlet-name>CamelServlet</servlet-name>
+ <url-pattern>/services/*</url-pattern>
+ </servlet-mapping>
+</web-app>
+-----------------------------------------------------------------------------------------------
- <bean id="servletProcessor" class="org.apache.camel.example.servlet.ServletProcessor" />
+== Camel JARs on an application server boot classpath
- <camelContext xmlns="http://camel.apache.org/schema/blueprint">
- <route>
- <!-- Notice how we can use the servlet scheme which is that reference above -->
- <from uri="servlet://hello" />
- <process ref="servletProcessor" />
- </route>
- </camelContext>
+If deploying into an application server / servlet container and you choose to have Camel JARs such as `camel-core`, `camel-servlet`, etc on the boot classpath.
+Then the servlet mapping list will be shared between multiple deployed Camel application in the app server.
-</blueprint>
--------------------------------------------------------------------------
+WARNING: Having Camel JARs on the boot classpath of the application server is not best practice.
-You can use an `Activator` to publish
-the
-https://github.com/apache/camel/blob/main/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java[CamelHttpTransportServlet]
-on the OSGi platform:
+In this scenario, you *must* define a custom and unique servlet name in each of your Camel applications. For example, in `web.xml`:
-[source,java]
--------------------------------------------------------------------------
-import java.util.Dictionary;
-import java.util.Hashtable;
-
-import org.apache.camel.component.servlet.CamelHttpTransportServlet;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.osgi.context.BundleContextAware;
-
-public final class ServletActivator implements BundleActivator, BundleContextAware {
- private static final Logger LOG = LoggerFactory.getLogger(ServletActivator.class);
- private static boolean registerService;
-
- /**
- * HttpService reference.
- */
- private ServiceReference<?> httpServiceRef;
-
- /**
- * Called when the OSGi framework starts our bundle
- */
- public void start(BundleContext bc) throws Exception {
- registerServlet(bc);
- }
+[source,xml]
+---------------------------------------------------------------------------------------------
+<web-app>
+ <servlet>
+ <servlet-name>MyServlet</servlet-name>
+ <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
- /**
- * Called when the OSGi framework stops our bundle
- */
- public void stop(BundleContext bc) throws Exception {
- if (httpServiceRef != null) {
- bc.ungetService(httpServiceRef);
- httpServiceRef = null;
- }
- }
+ <servlet-mapping>
+ <servlet-name>MyServlet</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+</web-app>
+---------------------------------------------------------------------------------------------
- protected void registerServlet(BundleContext bundleContext) throws Exception {
- httpServiceRef = bundleContext.getServiceReference(HttpService.class.getName());
-
- if (httpServiceRef != null && !registerService) {
- LOG.info("Register the servlet service");
- final HttpService httpService = (HttpService)bundleContext.getService(httpServiceRef);
- if (httpService != null) {
- // create a default context to share between registrations
- final HttpContext httpContext = httpService.createDefaultHttpContext();
- // register the hello world servlet
- final Dictionary<String, String> initParams = new Hashtable<String, String>();
- initParams.put("matchOnUriPrefix", "false");
- initParams.put("servlet-name", "CamelServlet");
- httpService.registerServlet("/camel/services", // alias
- new CamelHttpTransportServlet(), // register servlet
- initParams, // init params
- httpContext // http context
- );
- registerService = true;
- }
- }
- }
+In your Camel servlet endpoints, include the servlet name:
- public void setBundleContext(BundleContext bc) {
- try {
- registerServlet(bc);
- } catch (Exception e) {
- LOG.error("Cannot register the servlet, the reason is {}", e);
- }
- }
+[source,java]
+---------------------------------------------------
+from("servlet://foo?servletName=MyServlet")
+---------------------------------------------------
-}
--------------------------------------------------------------------------
+Camel detects duplicate Servlet names and will fail to
+start the application. You can control and ignore such duplicates by
+setting the servlet init parameter `ignoreDuplicateServletName` to `true` as
+follows:
+[source,xml]
+-----------------------------------------------------------------------------------------------
+ <servlet>
+ <servlet-name>CamelServlet</servlet-name>
+ <display-name>Camel Http Transport Servlet</display-name>
+ <servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
+ <init-param>
+ <param-name>ignoreDuplicateServletName</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </servlet>
+-----------------------------------------------------------------------------------------------
+But it is *strongly advised* to use unique `servlet-name` for each Camel
+application to avoid this duplication clash, as well any unforeseen
+side effects.
include::spring-boot:partial$starter.adoc[]