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 if (node
.isNodeType(NodeType
.MIX_SIMPLE_VERSIONABLE
)) {
111 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
112 if (versionManager
.isCheckedOut(jcrPath
)) {
113 if (!checkedOutModified
.containsKey(workspace
))
114 checkedOutModified
.put(workspace
, new TreeSet
<>());
115 checkedOutModified
.get(workspace
).add(jcrPath
);
117 if (!checkedInModified
.containsKey(workspace
))
118 checkedInModified
.put(workspace
, new TreeSet
<>());
119 checkedInModified
.get(workspace
).add(jcrPath
);
120 versionManager
.checkout(jcrPath
);
126 public synchronized Node
freeze(String workspace
, String jcrPath
) throws RepositoryException
{
127 Session session
= getWriteSession(workspace
);
128 Node node
= session
.getNode(jcrPath
);
129 if (node
.isNodeType(NodeType
.MIX_SIMPLE_VERSIONABLE
)) {
130 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
131 if (versionManager
.isCheckedOut(jcrPath
)) {
132 versionManager
.checkin(jcrPath
);
138 public synchronized boolean isOpenForEdit(String workspace
, String jcrPath
) throws RepositoryException
{
139 Session session
= getWriteSession(workspace
);
140 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
141 return versionManager
.isCheckedOut(jcrPath
);
144 public synchronized void persist() throws RepositoryException
{
145 for (String workspace
: writeSessions
.keySet()) {
146 Session session
= writeSessions
.get(workspace
);
147 if (session
== null) {
148 // assert writeThread == null;
149 assert !checkedOutModified
.containsKey(workspace
);
150 assert !checkedInModified
.containsKey(workspace
);
151 return; // nothing to do
154 VersionManager versionManager
= session
.getWorkspace().getVersionManager();
155 if (checkedOutModified
.containsKey(workspace
))
156 for (String jcrPath
: checkedOutModified
.get(workspace
)) {
157 versionManager
.checkpoint(jcrPath
);
159 if (checkedInModified
.containsKey(workspace
))
160 for (String jcrPath
: checkedInModified
.get(workspace
)) {
161 versionManager
.checkin(jcrPath
);
166 for (Map
<String
, Session
> m
: threadSessions
.values())
167 for (Session session
: m
.values())
168 session
.refresh(true);
169 // writeThread = null;
170 writeSessions
.clear();
171 checkedOutModified
.clear();
172 checkedInModified
.clear();
175 protected Session
login(String workspace
) {
176 return Subject
.doAs(subject
, (PrivilegedAction
<Session
>) () -> {
178 // String username = CurrentUser.getUsername(subject);
179 // SimpleCredentials credentials = new SimpleCredentials(username, new char[0]);
180 // credentials.setAttribute(ProvidedSession.class.getName(), contentSession);
181 Session sess
= repository
.login(workspace
);
182 // Jackrabbit specific:
183 ((SessionImpl
) sess
).setAttribute(ProvidedSession
.class.getName(), contentSession
);
185 } catch (RepositoryException e
) {
186 throw new IllegalStateException("Cannot log in to " + workspace
, e
);