4.9. Sessions

Having opened a CapConnection, all actions are executed on behalf of the single user whose credentials where provided when logging in. In some contexts, it is desirable to use different users for different tasks while maintaining a shared cache. To this end, the Unified API allows you to use multiple sessions per connection.

Every session is represented by an instance of CapSession. The session that is created while the connection is opened is also known as the connection session. Additional sessions can be opened by the connection's login methods. Having obtained a session, this session can replace the default connection session by calling the method setSession(CapSession) on the connection. Alternatively, you can call activate() on the session. Afterwards, all accesses in the same thread are performed on behalf of the new session.

CapSession session = connection.login(user, password);
try {
  session.activate();
  ...
} finally {
  session.close();
}

      

Example 4.1. Open a session


The previous code fragment shows how a second session is created from an existing connection. Notice that the call to activate was necessary, because the login call does not automatically set the session. Only between activate and close you can see the newly created user as the user of the current session. In fact, in other threads the original session still applies. After closing the session, the connection session is again active.

The call to activate() returns the previously set session. The above code assumes that the previous session is not worth remembering. After closing a session, the thread's session automatically returns to the connection session. Another example at the end of these sections shows how the old session can be reestablished.

In other cases you might want to save the original session and reestablish it after the work of the second session is complete, without closing the second session. That way you can save the time that is required for opening the session. Of course, a session that is held open consumes a concurrent license all the time.

All accesses to the repositories are subject to the limitations of the requested session. During reads and writes, the rights check is based on the identity of the session's user. Write rights may happen to be reduced, but it is also possible that additional rights are gained by switching to another user. However, the read rights available to any session are at most the read rights of the connection session. This is required in order to ensure efficient caching and to avoid accidental information leaks. Due to this restriction, it is recommended that the connection session's user should be allowed to read all repositories in their entirety, if additional sessions are expected to be created.

When attaching a listener using the Unified API, the current session is recorded. Before events are delivered to the listener, that session is reestablished as the current session. This way, listeners inherit the privileges of the code that attaches them.

Note that it is always possible to reset the current session to the connection session. Therefore, setting the current session is not sufficient for enforcing access restrictions when a CapConnection object is passed to untrusted code. Multiple sessions show their greatest potential in trusted applications which receive help in restricting user views while maintaining a shared cache.

Certain privileged connections have the ability to create new sessions for arbitrary users without providing a password. In particular this is true for the workflow service. In this case, logging in another session might be as simple as:

User user = ...;
CapSession session = connection.login(user);
...

Example 4.2. Log in another session


Note that it is not possible for ordinary user code to create a privileged connection. Instead, a privileged connection is returned by framework methods like WfServer.getConnection(). The default connection in a Content Application Engine is also privileged.

In the case of a privileged connection, you may also use a com.coremedia.cap.common.pool.CapSessionPool to obtain sessions temporarily. This class keeps a pool of sessions, which can greatly speed up your application if you change sessions often. Note that you still have to activate a session after it has been retrieved from the pool.

CapSessionPool pool = new CapSessionPoolImpl();
pool.setConnection(connection);
...
CapSession session = pool.acquireSession(user);
CapSession oldSession = session.activate();
try {
  ...
} finally {
  pool.releaseSession(session);
  oldSession.activate();
}

Example 4.3. Using a session pool


See CapSessionPool for further configuration options.

Write Buffering

When writing properties of a CapObject, these writes are initially buffered per thread and not sent to a server. Afterwards, the accumulated changes are sent to the server during a flush() call on the CapConnection object.

Buffering the changes per thread and not per session simplifies concurrent programming using the Unified API and reduces lock contention when a session is reused across threads.

The write buffers are also flushed when a call is made that cannot be handled locally by the Unified API. Currently, all calls except setters and getters will flush the write buffers, but this may change in future versions.

It is a good practice to flush the write buffers before any user interaction is resumed, before long delays are expected, and before returning from public methods that may be called from arbitrary code.