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