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