]> git.argeo.org Git - gpl/argeo-jcr.git/blob - JcrSessionAdapter.java
0fc46b8c9cc734f344ecc2233922a006734d20a5
[gpl/argeo-jcr.git] / JcrSessionAdapter.java
1 package org.argeo.cms.jcr.acr;
2
3 import java.security.PrivilegedAction;
4 import java.util.Collections;
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.Set;
8 import java.util.TreeSet;
9
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;
17
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;
23
24 /** Manages JCR {@link Session} in an ACR context. */
25 class JcrSessionAdapter {
26 private Repository repository;
27 private Subject subject;
28
29 private ProvidedSession contentSession;
30
31 private Map<Thread, Map<String, Session>> threadSessions = Collections.synchronizedMap(new HashMap<>());
32
33 private boolean closed = false;
34
35 private Thread lastRetrievingThread = null;
36
37 // private Thread writeThread;
38 private Map<String, Session> writeSessions = new HashMap<>();
39 /**
40 * Path of versionable nodes which have been modified during an edition cycle.
41 */
42 private Map<String, Set<String>> checkedInModified = new HashMap<>();
43 private Map<String, Set<String>> checkedOutModified = new HashMap<>();
44
45 public JcrSessionAdapter(Repository repository, ProvidedSession contentSession, Subject subject) {
46 this.repository = repository;
47 this.contentSession = contentSession;
48 this.subject = subject;
49 }
50
51 public synchronized void close() {
52 for (Map<String, Session> sessions : threadSessions.values()) {
53 for (Session session : sessions.values()) {
54 JcrUtils.logoutQuietly(session);
55 }
56 sessions.clear();
57 }
58 threadSessions.clear();
59 closed = true;
60 }
61
62 public synchronized Session getSession(String workspace) {
63 if (closed)
64 throw new IllegalStateException("JCR session adapter is closed.");
65
66 Thread currentThread = Thread.currentThread();
67 if (lastRetrievingThread == null)
68 lastRetrievingThread = currentThread;
69
70 Map<String, Session> threadSession = threadSessions.get(currentThread);
71 if (threadSession == null) {
72 threadSession = new HashMap<>();
73 threadSessions.put(currentThread, threadSession);
74 }
75
76 Session session = threadSession.get(workspace);
77 if (session == null) {
78 session = login(workspace);
79 threadSession.put(workspace, session);
80 }
81
82 if (lastRetrievingThread != currentThread) {
83 try {
84 session.refresh(true);
85 } catch (RepositoryException e) {
86 throw new JcrException("Cannot refresh JCR session " + session, e);
87 }
88 }
89 lastRetrievingThread = currentThread;
90 return session;
91 }
92
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);
98 } else {
99 // if ((writeThread != Thread.currentThread()) && session.hasPendingChanges()) {
100 // throw new IllegalStateException("Session " + contentSession + " is currently being written to");
101 // }
102 // writeThread = Thread.currentThread();
103 }
104 return session;
105 }
106
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);
116 } else {
117 if (!checkedInModified.containsKey(workspace))
118 checkedInModified.put(workspace, new TreeSet<>());
119 checkedInModified.get(workspace).add(jcrPath);
120 versionManager.checkout(jcrPath);
121 }
122 }
123 return node;
124 }
125
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);
133 }
134 }
135 return node;
136 }
137
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);
142 }
143
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
152 }
153 session.save();
154 VersionManager versionManager = session.getWorkspace().getVersionManager();
155 if (checkedOutModified.containsKey(workspace))
156 for (String jcrPath : checkedOutModified.get(workspace)) {
157 versionManager.checkpoint(jcrPath);
158 }
159 if (checkedInModified.containsKey(workspace))
160 for (String jcrPath : checkedInModified.get(workspace)) {
161 versionManager.checkin(jcrPath);
162 }
163 Jcr.logout(session);
164 }
165
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();
173 }
174
175 protected Session login(String workspace) {
176 return Subject.doAs(subject, (PrivilegedAction<Session>) () -> {
177 try {
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);
184 return sess;
185 } catch (RepositoryException e) {
186 throw new IllegalStateException("Cannot log in to " + workspace, e);
187 }
188 });
189 }
190
191 }