| [[HTTPSession-HTTPSession]] |
| HTTP-Session Handling |
| ~~~~~~~~~~~~~~~~~~~~~ |
| |
| Several Camel components can use HTTP as the underlying transport protocol. |
| In general HTTP calls are stateless in nature, however some servers allow |
| to maintain state via cookies. Cookies are often used to maintain a server |
| session (e.g. via a session cookie called "JSESSIONID" with servers implementing |
| the JEE Servlet specification). |
| |
| [[HTTPSession-SessionScope]] |
| Session Scope |
| ^^^^^^^^^^^^^ |
| |
| If a Camel route intends to implement some kind of HTTP session handling |
| the scope of this session should be considered. |
| |
| Independently of the session scope the implementation must honor the domain of |
| the handled cookies. |
| |
| [[HTTPSession-ContextScope]] |
| Route/Context Scope |
| +++++++++++++++++++ |
| |
| It might be desirable to have a single session for a route or a |
| CamelContext. This essentially means that all calls to |
| a server issued from a route or CamelContext share a single HTTP session. |
| |
| [[HTTPSession-EndpointScope]] |
| Endpoint Scope |
| ++++++++++++++ |
| |
| It is also possible to have a session on an |
| Endpoint entity. This would mean that all invocations of |
| an HTTP call issued by a single Endpoint share a session, whereas different |
| Endpoints never share sessions, even if the call is sent to the same server. |
| |
| Some components like camel-http, and camel-http4 support endpoint scoped sessions |
| even prior to version 2.19. |
| |
| [[HTTPSession-ExchangeScope]] |
| Exchange Scope |
| ++++++++++++++ |
| |
| The third option to define a session scope is on |
| Exchange level. This is particularly useful for scenarios |
| where the server session is really maintaining state. |
| |
| In this case the route could e.g. first do a login call, then some update calls |
| and finally a logout call. If the session handling would be defined on route or |
| CamelContext scopes this would seem to run, however under load parallel invocations |
| of the route would share a *single* session, which could cause issues. If the session |
| is defined on exchange scope, each invocation of the route will get a separate session |
| and the server can maintain a separate state for the different parallel invocations. |
| |
| [[HTTPSession-Usage]] |
| Usage |
| ^^^^^ |
| |
| If you are a Camel user, you see that several Camel components support the cookieHandler |
| parameter on endpoint level. All you need to do is to instantiate a cookie handler |
| appropriate for your use case and reference it in the cookieHandler parameter for |
| all endpoints that are supposed to participate in the HTTP session. |
| |
| There are two pre-implemented cookie handlers: |
| `org.apache.camel.http.common.cookie.InstanceCookieHandler` and |
| `org.apache.camel.http.common.cookie.ExchangeCookieHandler`. |
| |
| The InstanceCookieHandler stores cookies in an instance of itself. You can compare that |
| to a Browser instance that is shared between all the endpoints that use it (and will |
| be used for all invocations of these endpoints). If you want to maintain separate sessions |
| for different endpoints or groups of endpoints you may have multiple instances of the |
| InstanceCookieHandler. |
| |
| The ExchangeCookieHandler stores the session in the exchange. With the browser analogy |
| this means that each Exchange will get its own browser instance (so sessions are separated). |
| As the ExchangeCookieHandler does not store any state it is generally not useful to have |
| multiple ExchangeCookieHandler instances (as they would access the same data, anyway). |
| |
| Example |
| +++++++ |
| |
| The following three routes will each do two invocations of an echo REST service. In the first |
| route (without a cookie handler) each invocation will get a new session. For the second route |
| all invocations will share a session. For the third route the first and the second invocation |
| within the route share a session, but different (even parallel) invocations of the route will |
| not share a session. |
| |
| [source,xml] |
| ----------------------------------------------------------- |
| <cxf:rsClient id="rsClientProxy" address="http://127.0.0.1:8080/CxfRsProducerSessionTest/" |
| serviceClass="org.apache.camel.component.cxf.jaxrs.testbean.EchoService" |
| loggingFeatureEnabled="true" /> |
| |
| <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> |
| <route> |
| <from uri="direct://proxy"/> |
| <to uri="cxfrs://bean://rsClientProxy"/> |
| <convertBodyTo type="java.lang.String"/> |
| <to uri="cxfrs://bean://rsClientProxy"/> |
| </route> |
| <route> |
| <from uri="direct://proxyinstance"/> |
| <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#instanceCookieHandler"/> |
| <convertBodyTo type="java.lang.String"/> |
| <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#instanceCookieHandler"/> |
| </route> |
| <route> |
| <from uri="direct://proxyexchange"/> |
| <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#exchangeCookieHandler"/> |
| <convertBodyTo type="java.lang.String"/> |
| <to uri="cxfrs://bean://rsClientProxy?cookieHandler=#exchangeCookieHandler"/> |
| </route> |
| </camelContext> |
| |
| <bean id="instanceCookieHandler" class="org.apache.camel.http.common.cookie.InstanceCookieHandler"/> |
| <bean id="exchangeCookieHandler" class="org.apache.camel.http.common.cookie.ExchangeCookieHandler"/> |
| ----------------------------------------------------------- |
| |
| Both CookieHandler implementations support setting a CookiePolicy to control the policy for storing |
| cookies. Default is CookiePolicy.ACCEPT_ORIGINAL_SERVER. |
| |
| Note: Some EIPs like multicast or splitter create multiple exchanges from a single one. If |
| no `org.apache.camel.http.common.cookie.ExchangeCookieHandler` is used before this, each multicast |
| or splitter branch will have its own cookie store. This will not be the case if the first invocation |
| of one of the endpoints using the cookie handler is before the multicast, because in this case the |
| cookie store will be attached to the original exchange, and the exchanges created by the multicast |
| will copy the reference to this cookie store (so there is effectively a shared cookie store across branches. |
| As a workaround, you can call a cookieHandler.getCookieStore() e.g. by setting this to some dummy header. |
| |
| [[HTTPSession-ComponentDevelopers]] |
| Component Developers |
| ^^^^^^^^^^^^^^^^^^^^ |
| |
| If you want to develop a HTTP based component that is supposed to participate in a session |
| you have to add the following parts to your code: |
| |
| . Include a build reference to camel-http-common (if it is not already there) |
| . Add a cookieHandler parameter to the endpoint class (together with getter and setter) |
| . Before your code does the HTTP call, if a cookie handler is set on the endpoint |
| perform a `cookieHandler.loadCookies(exchange, uri)` call. It will return a |
| `Map<String, List<String>>` containing the headers that need to be sent to the server. |
| The details how you need to send these headers to the server depend on the underlying HTTP |
| API you are using. |
| . After your code does receive the HTTP response if a cookie handler is set on the endpoint |
| perform a `cookieHandler.storeCookies(exchange, uri, m)` call. `m` is a |
| `Map<String, List<String>>` containing the HTTP headers returned from the server. |
| |
| Note: some APIs provide more direct support for cookie handling. In this case it might be easier |
| to get the underlying `java.net.CookieStore` with a `cookeManager.getCookieStore(exchange)` call |
| and handle the cookies using the cookie interface provided by the underlying library. |