1 package org
.argeo
.cms
.jcr
.internal
.servlet
;
3 import java
.io
.Serializable
;
4 import java
.security
.PrivilegedActionException
;
5 import java
.security
.PrivilegedExceptionAction
;
6 import java
.util
.HashMap
;
7 import java
.util
.HashSet
;
8 import java
.util
.LinkedHashMap
;
12 import javax
.jcr
.Repository
;
13 import javax
.jcr
.RepositoryException
;
14 import javax
.jcr
.Session
;
15 import javax
.security
.auth
.Subject
;
16 import javax
.servlet
.ServletException
;
17 import javax
.servlet
.http
.HttpServletRequest
;
19 import org
.apache
.jackrabbit
.server
.SessionProvider
;
20 import org
.argeo
.api
.cms
.CmsConstants
;
21 import org
.argeo
.api
.cms
.CmsLog
;
22 import org
.argeo
.api
.cms
.CmsSession
;
23 import org
.argeo
.cms
.auth
.RemoteAuthUtils
;
24 import org
.argeo
.cms
.servlet
.ServletHttpRequest
;
25 import org
.argeo
.jcr
.JcrUtils
;
28 * Implements an open session in view patter: a new JCR session is created for
31 public class CmsSessionProvider
implements SessionProvider
, Serializable
{
32 private static final long serialVersionUID
= -1358136599534938466L;
34 private final static CmsLog log
= CmsLog
.getLog(CmsSessionProvider
.class);
36 private final String alias
;
38 private LinkedHashMap
<Session
, CmsDataSession
> cmsSessions
= new LinkedHashMap
<>();
40 public CmsSessionProvider(String alias
) {
44 public Session
getSession(HttpServletRequest request
, Repository rep
, String workspace
)
45 throws javax
.jcr
.LoginException
, ServletException
, RepositoryException
{
47 // a client is scanning parent URLs.
48 // if (workspace == null)
51 CmsSession cmsSession
= RemoteAuthUtils
.getCmsSession(new ServletHttpRequest(request
));
52 // CmsSessionImpl cmsSession = WebCmsSessionImpl.getCmsSession(request);
53 if (log
.isTraceEnabled()) {
54 log
.trace("Get JCR session from " + cmsSession
);
56 if (cmsSession
== null)
57 throw new IllegalStateException("Cannot find a session for request " + request
.getRequestURI());
58 CmsDataSession cmsDataSession
= new CmsDataSession(cmsSession
);
59 Session session
= cmsDataSession
.getDataSession(alias
, workspace
, rep
);
60 cmsSessions
.put(session
, cmsDataSession
);
64 public void releaseSession(Session session
) {
65 // JcrUtils.logoutQuietly(session);
66 if (cmsSessions
.containsKey(session
)) {
67 CmsDataSession cmsDataSession
= cmsSessions
.get(session
);
68 cmsDataSession
.releaseDataSession(alias
, session
);
70 log
.warn("JCR session " + session
+ " not found in CMS session list. Logging it out...");
71 JcrUtils
.logoutQuietly(session
);
75 static class CmsDataSession
{
76 private CmsSession cmsSession
;
78 private Map
<String
, Session
> dataSessions
= new HashMap
<>();
79 private Set
<String
> dataSessionsInUse
= new HashSet
<>();
80 private Set
<Session
> additionalDataSessions
= new HashSet
<>();
82 private CmsDataSession(CmsSession cmsSession
) {
83 this.cmsSession
= cmsSession
;
84 cmsSession
.addOnCloseCallback((sess
) -> close());
87 public Session
newDataSession(String cn
, String workspace
, Repository repository
) {
89 return login(repository
, workspace
);
92 public synchronized Session
getDataSession(String cn
, String workspace
, Repository repository
) {
94 // FIXME make it more robust
95 if (workspace
== null)
96 workspace
= CmsConstants
.SYS_WORKSPACE
;
97 String path
= cn
+ '/' + workspace
;
98 if (dataSessionsInUse
.contains(path
)) {
101 if (dataSessionsInUse
.contains(path
)) {
102 Session session
= login(repository
, workspace
);
103 additionalDataSessions
.add(session
);
104 if (log
.isTraceEnabled())
105 log
.trace("Additional data session " + path
+ " for " + cmsSession
.getUserDn());
108 } catch (InterruptedException e
) {
113 Session session
= null;
114 if (dataSessions
.containsKey(path
)) {
115 session
= dataSessions
.get(path
);
117 session
= login(repository
, workspace
);
118 dataSessions
.put(path
, session
);
119 if (log
.isTraceEnabled())
120 log
.trace("New data session " + path
+ " for " + cmsSession
.getUserDn());
122 dataSessionsInUse
.add(path
);
126 private Session
login(Repository repository
, String workspace
) {
128 return Subject
.doAs(cmsSession
.getSubject(), new PrivilegedExceptionAction
<Session
>() {
130 public Session
run() throws Exception
{
131 return repository
.login(workspace
);
134 } catch (PrivilegedActionException e
) {
135 throw new IllegalStateException("Cannot log in " + cmsSession
.getUserDn() + " to JCR", e
);
139 public synchronized void releaseDataSession(String cn
, Session session
) {
140 if (additionalDataSessions
.contains(session
)) {
141 JcrUtils
.logoutQuietly(session
);
142 additionalDataSessions
.remove(session
);
143 if (log
.isTraceEnabled())
144 log
.trace("Remove additional data session " + session
);
147 String path
= cn
+ '/' + session
.getWorkspace().getName();
148 if (!dataSessionsInUse
.contains(path
))
149 log
.warn("Data session " + path
+ " was not in use for " + cmsSession
.getUserDn());
150 dataSessionsInUse
.remove(path
);
151 Session registeredSession
= dataSessions
.get(path
);
152 if (session
!= registeredSession
)
153 log
.warn("Data session " + path
+ " not consistent for " + cmsSession
.getUserDn());
154 if (log
.isTraceEnabled())
155 log
.trace("Released data session " + session
+ " for " + path
);
159 private void checkValid() {
160 if (!cmsSession
.isValid())
161 throw new IllegalStateException(
162 "CMS session " + cmsSession
.getUuid() + " is not valid since " + cmsSession
.getEnd());
165 protected void close() {
166 synchronized (this) {
167 // TODO check data session in use ?
168 for (String path
: dataSessions
.keySet())
169 JcrUtils
.logoutQuietly(dataSessions
.get(path
));
170 for (Session session
: additionalDataSessions
)
171 JcrUtils
.logoutQuietly(session
);