]> git.argeo.org Git - gpl/argeo-jcr.git/blob - org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrSessionAdapter.java
Adapt to changes in Argeo TP
[gpl/argeo-jcr.git] / org.argeo.cms.jcr / src / org / argeo / cms / jcr / acr / 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 VersionManager versionManager = session.getWorkspace().getVersionManager();
111
112 Node versionedAncestor = findVersionedAncestor(node);
113 boolean checkedOut = versionManager.isCheckedOut(jcrPath);
114
115 if (versionedAncestor != null) {
116 if (checkedOut) {
117 if (!checkedOutModified.containsKey(workspace))
118 checkedOutModified.put(workspace, new TreeSet<>());
119 checkedOutModified.get(workspace).add(versionedAncestor.getPath());
120 } else {
121 if (!checkedInModified.containsKey(workspace))
122 checkedInModified.put(workspace, new TreeSet<>());
123 checkedInModified.get(workspace).add(versionedAncestor.getPath());
124 versionManager.checkout(versionedAncestor.getPath());
125 }
126 }
127 return node;
128 }
129
130 private Node findVersionedAncestor(Node node) throws RepositoryException {
131 if (node.isNodeType(NodeType.MIX_SIMPLE_VERSIONABLE))
132 return node;
133 Node parent = node.getParent();
134 if (parent == null)
135 return null;
136 return findVersionedAncestor(parent);
137 }
138
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);
146 }
147 }
148 return node;
149 }
150
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);
155 }
156
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
165 }
166 session.save();
167 VersionManager versionManager = session.getWorkspace().getVersionManager();
168 if (checkedOutModified.containsKey(workspace))
169 for (String jcrPath : checkedOutModified.get(workspace)) {
170 versionManager.checkpoint(jcrPath);
171 }
172 if (checkedInModified.containsKey(workspace))
173 for (String jcrPath : checkedInModified.get(workspace)) {
174 versionManager.checkin(jcrPath);
175 }
176 Jcr.logout(session);
177 }
178
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();
186 }
187
188 protected Session login(String workspace) {
189 return Subject.doAs(subject, (PrivilegedAction<Session>) () -> {
190 try {
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);
197 return sess;
198 } catch (RepositoryException e) {
199 throw new IllegalStateException("Cannot log in to " + workspace, e);
200 }
201 });
202 }
203
204 }