]> git.argeo.org Git - lgpl/argeo-commons.git/blob - jcr/CmsJcrUtils.java
Prepare next development cycle
[lgpl/argeo-commons.git] / jcr / CmsJcrUtils.java
1 package org.argeo.cms.jcr;
2
3 import java.security.PrivilegedAction;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import javax.jcr.NoSuchWorkspaceException;
8 import javax.jcr.Node;
9 import javax.jcr.Property;
10 import javax.jcr.Repository;
11 import javax.jcr.RepositoryException;
12 import javax.jcr.RepositoryFactory;
13 import javax.jcr.Session;
14 import javax.naming.InvalidNameException;
15 import javax.naming.ldap.LdapName;
16 import javax.security.auth.AuthPermission;
17 import javax.security.auth.Subject;
18 import javax.security.auth.login.LoginContext;
19 import javax.security.auth.login.LoginException;
20
21 import org.argeo.api.cms.CmsAuth;
22 import org.argeo.api.cms.CmsConstants;
23
24 /** Utilities related to Argeo model in JCR */
25 public class CmsJcrUtils {
26 /**
27 * Wraps the call to the repository factory based on parameter
28 * {@link CmsConstants#CN} in order to simplify it and protect against future
29 * API changes.
30 */
31 public static Repository getRepositoryByAlias(RepositoryFactory repositoryFactory, String alias) {
32 try {
33 Map<String, String> parameters = new HashMap<String, String>();
34 parameters.put(CmsConstants.CN, alias);
35 return repositoryFactory.getRepository(parameters);
36 } catch (RepositoryException e) {
37 throw new RuntimeException("Unexpected exception when trying to retrieve repository with alias " + alias,
38 e);
39 }
40 }
41
42 /**
43 * Wraps the call to the repository factory based on parameter
44 * {@link CmsConstants#LABELED_URI} in order to simplify it and protect against
45 * future API changes.
46 */
47 public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri) {
48 return getRepositoryByUri(repositoryFactory, uri, null);
49 }
50
51 /**
52 * Wraps the call to the repository factory based on parameter
53 * {@link CmsConstants#LABELED_URI} in order to simplify it and protect against
54 * future API changes.
55 */
56 public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri, String alias) {
57 try {
58 Map<String, String> parameters = new HashMap<String, String>();
59 parameters.put(CmsConstants.LABELED_URI, uri);
60 if (alias != null)
61 parameters.put(CmsConstants.CN, alias);
62 return repositoryFactory.getRepository(parameters);
63 } catch (RepositoryException e) {
64 throw new RuntimeException("Unexpected exception when trying to retrieve repository with uri " + uri, e);
65 }
66 }
67
68 /**
69 * Returns the home node of the user or null if none was found.
70 *
71 * @param session the session to use in order to perform the search, this can
72 * be a session with a different user ID than the one searched,
73 * typically when a system or admin session is used.
74 * @param username the username of the user
75 */
76 public static Node getUserHome(Session session, String username) {
77 // try {
78 // QueryObjectModelFactory qomf = session.getWorkspace().getQueryManager().getQOMFactory();
79 // Selector sel = qomf.selector(NodeTypes.NODE_USER_HOME, "sel");
80 // DynamicOperand dop = qomf.propertyValue(sel.getSelectorName(), NodeNames.LDAP_UID);
81 // StaticOperand sop = qomf.literal(session.getValueFactory().createValue(username));
82 // Constraint constraint = qomf.comparison(dop, QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, sop);
83 // Query query = qomf.createQuery(sel, constraint, null, null);
84 // return querySingleNode(query);
85 // } catch (RepositoryException e) {
86 // throw new RuntimeException("Cannot find home for user " + username, e);
87 // }
88
89 try {
90 checkUserWorkspace(session, username);
91 String homePath = getHomePath(username);
92 if (session.itemExists(homePath))
93 return session.getNode(homePath);
94 // legacy
95 homePath = "/home/" + username;
96 if (session.itemExists(homePath))
97 return session.getNode(homePath);
98 return null;
99 } catch (RepositoryException e) {
100 throw new RuntimeException("Cannot find home for user " + username, e);
101 }
102 }
103
104 private static String getHomePath(String username) {
105 LdapName dn;
106 try {
107 dn = new LdapName(username);
108 } catch (InvalidNameException e) {
109 throw new IllegalArgumentException("Invalid name " + username, e);
110 }
111 String userId = dn.getRdn(dn.size() - 1).getValue().toString();
112 return '/' + userId;
113 }
114
115 private static void checkUserWorkspace(Session session, String username) {
116 String workspaceName = session.getWorkspace().getName();
117 if (!CmsConstants.HOME_WORKSPACE.equals(workspaceName))
118 throw new IllegalArgumentException(workspaceName + " is not the home workspace for user " + username);
119 }
120
121 /**
122 * Returns the home node of the user or null if none was found.
123 *
124 * @param session the session to use in order to perform the search, this can
125 * be a session with a different user ID than the one searched,
126 * typically when a system or admin session is used.
127 * @param groupname the name of the group
128 */
129 public static Node getGroupHome(Session session, String groupname) {
130 // try {
131 // QueryObjectModelFactory qomf = session.getWorkspace().getQueryManager().getQOMFactory();
132 // Selector sel = qomf.selector(NodeTypes.NODE_GROUP_HOME, "sel");
133 // DynamicOperand dop = qomf.propertyValue(sel.getSelectorName(), NodeNames.LDAP_CN);
134 // StaticOperand sop = qomf.literal(session.getValueFactory().createValue(cn));
135 // Constraint constraint = qomf.comparison(dop, QueryObjectModelFactory.JCR_OPERATOR_EQUAL_TO, sop);
136 // Query query = qomf.createQuery(sel, constraint, null, null);
137 // return querySingleNode(query);
138 // } catch (RepositoryException e) {
139 // throw new RuntimeException("Cannot find home for group " + cn, e);
140 // }
141
142 try {
143 checkGroupWorkspace(session, groupname);
144 String homePath = getGroupPath(groupname);
145 if (session.itemExists(homePath))
146 return session.getNode(homePath);
147 // legacy
148 homePath = "/groups/" + groupname;
149 if (session.itemExists(homePath))
150 return session.getNode(homePath);
151 return null;
152 } catch (RepositoryException e) {
153 throw new RuntimeException("Cannot find home for group " + groupname, e);
154 }
155
156 }
157
158 private static String getGroupPath(String groupname) {
159 String cn;
160 try {
161 LdapName dn = new LdapName(groupname);
162 cn = dn.getRdn(dn.size() - 1).getValue().toString();
163 } catch (InvalidNameException e) {
164 cn = groupname;
165 }
166 return '/' + cn;
167 }
168
169 private static void checkGroupWorkspace(Session session, String groupname) {
170 String workspaceName = session.getWorkspace().getName();
171 if (!CmsConstants.SRV_WORKSPACE.equals(workspaceName))
172 throw new IllegalArgumentException(workspaceName + " is not the group workspace for group " + groupname);
173 }
174
175 /**
176 * Queries one single node.
177 *
178 * @return one single node or null if none was found
179 * @throws ArgeoJcrException if more than one node was found
180 */
181 // private static Node querySingleNode(Query query) {
182 // NodeIterator nodeIterator;
183 // try {
184 // QueryResult queryResult = query.execute();
185 // nodeIterator = queryResult.getNodes();
186 // } catch (RepositoryException e) {
187 // throw new RuntimeException("Cannot execute query " + query, e);
188 // }
189 // Node node;
190 // if (nodeIterator.hasNext())
191 // node = nodeIterator.nextNode();
192 // else
193 // return null;
194 //
195 // if (nodeIterator.hasNext())
196 // throw new RuntimeException("Query returned more than one node.");
197 // return node;
198 // }
199
200 /** Returns the home node of the session user or null if none was found. */
201 public static Node getUserHome(Session session) {
202 String userID = session.getUserID();
203 return getUserHome(session, userID);
204 }
205
206 /** Whether this node is the home of the user of the underlying session. */
207 public static boolean isUserHome(Node node) {
208 try {
209 String userID = node.getSession().getUserID();
210 return node.hasProperty(Property.JCR_ID) && node.getProperty(Property.JCR_ID).getString().equals(userID);
211 } catch (RepositoryException e) {
212 throw new IllegalStateException(e);
213 }
214 }
215
216 /**
217 * Translate the path to this node into a path containing the name of the
218 * repository and the name of the workspace.
219 */
220 public static String getDataPath(String cn, Node node) {
221 assert node != null;
222 StringBuilder buf = new StringBuilder(CmsConstants.PATH_DATA);
223 try {
224 return buf.append('/').append(cn).append('/').append(node.getSession().getWorkspace().getName())
225 .append(node.getPath()).toString();
226 } catch (RepositoryException e) {
227 throw new IllegalStateException("Cannot get data path for " + node + " in repository " + cn, e);
228 }
229 }
230
231 /**
232 * Translate the path to this node into a path containing the name of the
233 * repository and the name of the workspace.
234 */
235 public static String getDataPath(Node node) {
236 return getDataPath(CmsConstants.NODE, node);
237 }
238
239 /**
240 * Open a JCR session with full read/write rights on the data, as
241 * {@link CmsConstants#ROLE_USER_ADMIN}, using the
242 * {@link CmsAuth#LOGIN_CONTEXT_DATA_ADMIN} login context. For security
243 * hardened deployement, use {@link AuthPermission} on this login context.
244 */
245 public static Session openDataAdminSession(Repository repository, String workspaceName) {
246 ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
247 LoginContext loginContext;
248 try {
249 loginContext = new LoginContext(CmsAuth.LOGIN_CONTEXT_DATA_ADMIN);
250 loginContext.login();
251 } catch (LoginException e1) {
252 throw new RuntimeException("Could not login as data admin", e1);
253 } finally {
254 Thread.currentThread().setContextClassLoader(currentCl);
255 }
256 return Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Session>() {
257
258 @Override
259 public Session run() {
260 try {
261 return repository.login(workspaceName);
262 } catch (NoSuchWorkspaceException e) {
263 throw new IllegalArgumentException("No workspace " + workspaceName + " available", e);
264 } catch (RepositoryException e) {
265 throw new RuntimeException("Cannot open data admin session", e);
266 }
267 }
268
269 });
270 }
271
272 /** Singleton. */
273 private CmsJcrUtils() {
274 }
275
276 }