1 package org
.argeo
.cms
.jcr
.acr
;
3 import java
.security
.PrivilegedAction
;
4 import java
.util
.Collections
;
5 import java
.util
.HashMap
;
8 import java
.util
.TreeSet
;
10 import javax
.jcr
.Node
;
11 import javax
.jcr
.Repository
;
12 import javax
.jcr
.RepositoryException
;
13 import javax
.jcr
.Session
;
14 import javax
.jcr
.nodetype
.NodeType
;
15 import javax
.jcr
.version
.VersionManager
;
16 import javax
.security
.auth
.Subject
;
18 import org
.apache
.jackrabbit
.core
.SessionImpl
;
19 import org
.argeo
.api
.acr
.spi
.ProvidedSession
;
20 import org
.argeo
.jcr
.Jcr
;
21 import org
.argeo
.jcr
.JcrException
;
22 import org
.argeo
.jcr
.JcrUtils
;
24 /** Manages JCR {@link Session} in an ACR context. */
25 class JcrSessionAdapter
{
26 private Repository repository
;
27 private Subject subject
;
29 private ProvidedSession contentSession
;
31 private Map
<Thread
, Map
<String
, Session
>> threadSessions
= Collections
.synchronizedMap(new HashMap
<>());
33 private boolean closed
= false;
35 private Thread lastRetrievingThread
= null;
37 // private Thread writeThread;
38 private Map
<String
, Session
> writeSessions
= new HashMap
<>();
40 * Path of versionable nodes which have been modified during an edition cycle.
42 private Map
<String
, Set
<String
>> checkedInModified
= new HashMap
<>();
43 private Map
<String
, Set
<String
>> checkedOutModified
= new HashMap
<>();
45 public JcrSessionAdapter(Repository repository
, ProvidedSession contentSession
, Subject subject
) {
46 this.repository
= repository
;
47 this.contentSession
= contentSession
;
48 this.subject
= subject
;
51 public synchronized void close() {
52 for (Map
<String
, Session
> sessions
: threadSessions
.values()) {
53 for (Session session
: sessions
.values()) {
54 JcrUtils
.logoutQuietly(session
);
58 threadSessions
.clear();
62 public synchronized Session
getSession(String workspace
) {
64 throw new IllegalStateException("JCR session adapter is closed.");
66 Thread currentThread
= Thread
.currentThread();
67 if (lastRetrievingThread
== null)
68 lastRetrievingThread
= currentThread
;
70 Map
<String
, Session
> threadSession
= threadSessions
.get(currentThread
);
71 if (threadSession
== null) {
72 threadSession
= new HashMap
<>();
73 threadSessions
.put(currentThread
, threadSession
);
76 Session session
= threadSession
.get(workspace
);
77 if (session
== null) {
78 session
= login(workspace
);
79 threadSession
.put(workspace
, session
);
82 if (lastRetrievingThread
!= currentThread
) {
84 session
.refresh(true);
85 } catch (RepositoryException e
) {
86 throw new JcrException("Cannot refresh JCR session " + session
, e
);
89 lastRetrievingThread
= currentThread
;
93 protected synchronized Session
getWriteSession(String workspace
) throws RepositoryException
{
94 Session session
= writeSessions
.get(workspace
);
95 if (session
== null) {
96 session
= login(workspace
);
97 writeSessions
.put(workspace
, session
);
99 // if ((writeThread != Thread.currentThread()) && session.hasPendingChanges()) {
100 // throw new IllegalStateException("Session " + contentSession + " is currently being written to");
102 // writeThread = Thread.currentThread();
107 public synchronized Node
openForEdit(String workspace
, String jcrPath
) throws RepositoryException
{
108 Session session
= getWriteSession(workspace
);
109 Node node
= session
.getNode(jcrPath
);
110 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
112 Node versionedAncestor
= findVersionedAncestor(node
);
113 boolean checkedOut
= versionManager
.isCheckedOut(jcrPath
);
115 if (versionedAncestor
!= null) {
117 if (!checkedOutModified
.containsKey(workspace
))
118 checkedOutModified
.put(workspace
, new TreeSet
<>());
119 checkedOutModified
.get(workspace
).add(versionedAncestor
.getPath());
121 if (!checkedInModified
.containsKey(workspace
))
122 checkedInModified
.put(workspace
, new TreeSet
<>());
123 checkedInModified
.get(workspace
).add(versionedAncestor
.getPath());
124 versionManager
.checkout(versionedAncestor
.getPath());
130 private Node
findVersionedAncestor(Node node
) throws RepositoryException
{
131 if (node
.isNodeType(NodeType
.MIX_SIMPLE_VERSIONABLE
))
133 Node parent
= node
.getParent();
136 return findVersionedAncestor(parent
);
139 public synchronized Node
freeze(String workspace
, String jcrPath
) throws RepositoryException
{
140 Session session
= getWriteSession(workspace
);
141 Node node
= session
.getNode(jcrPath
);
142 if (node
.isNodeType(NodeType
.MIX_SIMPLE_VERSIONABLE
)) {
143 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
144 if (versionManager
.isCheckedOut(jcrPath
)) {
145 versionManager
.checkin(jcrPath
);
151 public synchronized boolean isOpenForEdit(String workspace
, String jcrPath
) throws RepositoryException
{
152 Session session
= getWriteSession(workspace
);
153 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
154 return versionManager
.isCheckedOut(jcrPath
);
157 public synchronized void persist() throws RepositoryException
{
158 for (String workspace
: writeSessions
.keySet()) {
159 Session session
= writeSessions
.get(workspace
);
160 if (session
== null) {
161 // assert writeThread == null;
162 assert !checkedOutModified
.containsKey(workspace
);
163 assert !checkedInModified
.containsKey(workspace
);
164 return; // nothing to do
167 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
168 if (checkedOutModified
.containsKey(workspace
))
169 for (String jcrPath
: checkedOutModified
.get(workspace
)) {
170 versionManager
.checkpoint(jcrPath
);
172 if (checkedInModified
.containsKey(workspace
))
173 for (String jcrPath
: checkedInModified
.get(workspace
)) {
174 versionManager
.checkin(jcrPath
);
179 for (Map
<String
, Session
> m
: threadSessions
.values())
180 for (Session session
: m
.values())
181 session
.refresh(true);
182 // writeThread = null;
183 writeSessions
.clear();
184 checkedOutModified
.clear();
185 checkedInModified
.clear();
188 protected Session
login(String workspace
) {
189 return Subject
.doAs(subject
, (PrivilegedAction
<Session
>) () -> {
191 // String username = CurrentUser.getUsername(subject);
192 // SimpleCredentials credentials = new SimpleCredentials(username, new char[0]);
193 // credentials.setAttribute(ProvidedSession.class.getName(), contentSession);
194 Session sess
= repository
.login(workspace
);
195 // Jackrabbit specific:
196 ((SessionImpl
) sess
).setAttribute(ProvidedSession
.class.getName(), contentSession
);
198 } catch (RepositoryException e
) {
199 throw new IllegalStateException("Cannot log in to " + workspace
, e
);