Putting Cayenne Files in Web Application CLASSPATH

When deploying an application in a web container it is possible to follow the procedure for the standalone applications, i.e. put all XML files in the application CLASSPATH (e.g. in "mywebapp/WEB-INF/classes/", but DON'T put it in container shared locations!). Session DataContext can be obtained via ServletUtil:

HttpSession session = ...;
DataContext context = ServletUtil.getSessionContext(session);

However you may consider a deployment procedure described below, as it provides more flexibility and a number of additional useful features.

Cayenne Servlet Filter

Adding the following filter to the web.xml would automate Cayenne setup in the web application:

<filter>
    <filter-name>CayenneFilter</filter-name>
    <filter-class>org.apache.cayenne.conf.WebApplicationContextFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CayenneFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

The filter will ensure that for each matching request a ObjectContext (which is actually a DataContext instance) is bound to the request thread. Context itself is session-scoped. So you can retrieve it anywhere in the application, even if you don't have a reference to the web environment:

ObjectContext context = BaseContext.getThreadObjectContext();

Filter can match a specific URL as shown above, or a specific servlet:

<servlet>
   <servlet-name>MyServlet</servlet-name>
   <servlet-class>org.example.MyServlet</servlet-class>
   <load-on-startup>0</load-on-startup>
</servlet>
		
<filter>
    <filter-name>CayenneFilter</filter-name>
    <filter-class>org.apache.cayenne.conf.WebApplicationContextFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CayenneFilter</filter-name>
    <servlet-name>MyServlet</servlet-name>
</filter-mapping>

Additionally the filter supports putting files in myapp/WEB-INF/ directory instead of the CLASSPATH, so a .war file may look like this:

index.jsp
WEB-INF/cayenne.xml
WEB-INF/xyz.map.xml
WEB-INF/lib/...

Actually, Cayenne files can be stored in any subdirectory of myapp/WEB-INF/. To specify a subdirectory, you'll need to add <context-param> named cayenne.configuration.path to your application descriptor:

<context-param>
    <param-name>cayenne.configuration.path</param-name>
    <param-value>/WEB-INF/config/cayenne-files</param-value>
</context-param>

ObjectContext Scope

ServletUtil and WebApplicationContextFilter would both provide an ObjectContext shared between the requests in the same user session (session-scoped context). This is the default behavior. However, depending on the application needs, you may choose to use application-scoped context (usually for read-only parts of the application, and combined with caching), or per-request context (to avoid race conditions on long-running operations). In those cases you won't be able to use ServletUtil and WebApplicationContextFilter, but you can easily write your own correctly scoped replacements, or set it up via an IoC container, such as Spring.