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