1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.services.cms.queries.impl;
18
19 import org.exoplatform.commons.utils.ISO8601;
20 import org.exoplatform.container.xml.InitParams;
21 import org.exoplatform.container.xml.PortalContainerInfo;
22 import org.exoplatform.services.cache.CacheService;
23 import org.exoplatform.services.cache.ExoCache;
24 import org.exoplatform.services.cms.BasePath;
25 import org.exoplatform.services.cms.impl.DMSConfiguration;
26 import org.exoplatform.services.cms.impl.DMSRepositoryConfiguration;
27 import org.exoplatform.services.cms.queries.QueryService;
28 import org.exoplatform.services.jcr.RepositoryService;
29 import org.exoplatform.services.jcr.access.PermissionType;
30 import org.exoplatform.services.jcr.core.ExtendedNode;
31 import org.exoplatform.services.jcr.core.ManageableRepository;
32 import org.exoplatform.services.jcr.ext.common.SessionProvider;
33 import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
34 import org.exoplatform.services.log.ExoLogger;
35 import org.exoplatform.services.log.Log;
36 import org.exoplatform.services.organization.MembershipHandler;
37 import org.exoplatform.services.organization.OrganizationService;
38 import org.exoplatform.services.security.ConversationState;
39 import org.exoplatform.services.security.IdentityConstants;
40 import org.exoplatform.services.security.Identity;
41 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
42 import org.exoplatform.web.application.RequestContext;
43 import org.picocontainer.Startable;
44
45 import javax.jcr.*;
46 import javax.jcr.query.Query;
47 import javax.jcr.query.QueryManager;
48 import javax.jcr.query.QueryResult;
49
50 import java.util.*;
51
52 public class QueryServiceImpl implements QueryService, Startable{
53 private static final String[] perms = {PermissionType.READ, PermissionType.ADD_NODE,
54 PermissionType.SET_PROPERTY, PermissionType.REMOVE };
55 private String relativePath_;
56 private List<QueryPlugin> queryPlugins_ = new ArrayList<QueryPlugin> ();
57 private RepositoryService repositoryService_;
58 private ExoCache<String, QueryResult> cache_;
59 private PortalContainerInfo containerInfo_;
60 private OrganizationService organizationService_;
61 private String baseUserPath_;
62 private String baseQueriesPath_;
63 private String group_;
64 private DMSConfiguration dmsConfiguration_;
65 private Set<String> configuredQueries_;
66
67 private NodeHierarchyCreator nodeHierarchyCreator_;
68
69 private static final Log LOG = ExoLogger.getLogger(QueryServiceImpl.class.getName());
70
71
72
73
74
75
76
77
78
79
80
81
82 public QueryServiceImpl(RepositoryService repositoryService, NodeHierarchyCreator nodeHierarchyCreator,
83 InitParams params, PortalContainerInfo containerInfo, CacheService cacheService,
84 OrganizationService organizationService, DMSConfiguration dmsConfiguration) throws Exception {
85 relativePath_ = params.getValueParam("relativePath").getValue();
86 group_ = params.getValueParam("group").getValue();
87 repositoryService_ = repositoryService;
88 containerInfo_ = containerInfo;
89 cache_ = cacheService.getCacheInstance(CACHE_NAME);
90 organizationService_ = organizationService;
91 nodeHierarchyCreator_ = nodeHierarchyCreator;
92 baseUserPath_ = nodeHierarchyCreator.getJcrPath(BasePath.CMS_USERS_PATH);
93 baseQueriesPath_ = nodeHierarchyCreator.getJcrPath(BasePath.QUERIES_PATH);
94 dmsConfiguration_ = dmsConfiguration;
95 }
96
97
98
99
100
101
102 public void start() {
103 configuredQueries_ = new HashSet<String>();
104 for(QueryPlugin queryPlugin : queryPlugins_){
105 try{
106 queryPlugin.init(baseQueriesPath_);
107 configuredQueries_.addAll(queryPlugin.getAllConfiguredQueries());
108 }catch (Exception e) {
109 if (LOG.isErrorEnabled()) {
110 LOG.error("Can not start query plugin '" + queryPlugin.getName() + "'", e);
111 }
112 }
113 }
114 }
115
116
117
118
119 public void stop() {
120 }
121
122
123
124
125 public void init() throws Exception {
126 configuredQueries_ = new HashSet<String>();
127 for(QueryPlugin queryPlugin : queryPlugins_){
128 try{
129 queryPlugin.init(baseQueriesPath_);
130 configuredQueries_.addAll(queryPlugin.getAllConfiguredQueries());
131 }catch (Exception e) {
132 if (LOG.isErrorEnabled()) {
133 LOG.error("Can not init query plugin '" + queryPlugin.getName() + "'", e);
134 }
135 }
136 }
137 }
138
139
140
141
142
143
144 public void setQueryPlugin(QueryPlugin queryPlugin) {
145 queryPlugins_.add(queryPlugin);
146 }
147
148
149
150
151 public String getRelativePath() { return relativePath_; }
152
153
154
155
156 public List<Query> getQueries(String userName, SessionProvider provider) throws Exception {
157 List<Query> queries = new ArrayList<Query>();
158 if (userName == null) return queries;
159 Session session = getSession(provider, true);
160 QueryManager manager = session.getWorkspace().getQueryManager();
161 Node usersHome;
162 try {
163 usersHome = (Node)session.getItem(baseUserPath_);
164 } catch (PathNotFoundException e) {
165 usersHome = (Node)getSession(provider, false).getItem(baseUserPath_);
166 }
167 Node userHome = null;
168 try {
169 userHome = nodeHierarchyCreator_.getUserNode(provider, userName);
170 } catch(Exception e) {
171 if (LOG.isWarnEnabled()) {
172 LOG.warn(e.getMessage());
173 }
174 }
175 if (userHome == null) {
176 if(usersHome.hasNode(userName)) {
177 userHome = usersHome.getNode(userName);
178 } else{
179 userHome = usersHome.addNode(userName);
180 if(userHome.canAddMixin("exo:privilegeable")){
181 userHome.addMixin("exo:privilegeable");
182
183 }
184 ((ExtendedNode)userHome).setPermissions(getPermissions(userName));
185 Node query = null;
186 if(userHome.hasNode(relativePath_)) {
187 query = userHome.getNode(relativePath_);
188 } else {
189 query = getNodeByRelativePath(userHome, relativePath_);
190 }
191 if (query.canAddMixin("exo:privilegeable")){
192 query.addMixin("exo:privilegeable");
193 }
194 ((ExtendedNode)query).setPermissions(getPermissions(userName));
195 usersHome.save();
196 }
197 }
198 Node queriesHome = null;
199 if(userHome.hasNode(relativePath_)) {
200 queriesHome = userHome.getNode(relativePath_);
201 } else {
202 queriesHome = getNodeByRelativePath(userHome, relativePath_);
203 }
204 NodeIterator iter = queriesHome.getNodes();
205 while (iter.hasNext()) {
206 Node node = iter.nextNode();
207 if(node.isNodeType("nt:query")) queries.add(manager.getQuery(node));
208 }
209 return queries;
210 }
211
212
213
214
215
216
217
218
219 private Node getNodeByRelativePath(Node userHome, String relativePath) throws Exception {
220 String[] paths = relativePath.split("/");
221 StringBuffer relPath = null;
222 Node queriesHome = null;
223 for (String path : paths) {
224 if (relPath == null)
225 relPath = new StringBuffer(path);
226 else
227 relPath.append("/").append(path);
228 if (!userHome.hasNode(relPath.toString()))
229 queriesHome = userHome.addNode(relPath.toString());
230 }
231 return queriesHome;
232 }
233
234
235
236
237
238
239 private Map<String,String[]> getPermissions(String owner) {
240 Map<String, String[]> permissions = new HashMap<String, String[]>();
241 permissions.put(owner, perms);
242 permissions.put(group_, perms);
243 return permissions;
244 }
245
246
247
248
249 public void addQuery(String queryName, String statement, String language, String userName) throws Exception {
250 if (userName == null)
251 return;
252 Session session = getSession();
253 QueryManager manager = session.getWorkspace().getQueryManager();
254 Query query = manager.createQuery(statement, language);
255 SessionProvider sessionProvider = WCMCoreUtils.getSystemSessionProvider();
256 Node userNode = nodeHierarchyCreator_.getUserNode(sessionProvider, userName);
257 if (!userNode.hasNode(getRelativePath())) {
258 getNodeByRelativePath(userNode, relativePath_);
259 session.save();
260 }
261 String absPath = userNode.getPath() + "/" + relativePath_ + "/" + queryName;
262 query.storeAsNode(absPath);
263 session.save();
264 }
265
266
267
268
269 public void removeQuery(String queryPath, String userName) throws Exception {
270 if (userName == null)
271 return;
272 Session session = getSession();
273
274 Node queryNode = null;
275 try {
276 queryNode = (Node) session.getItem(queryPath);
277 } catch (PathNotFoundException pe) {
278 queryNode = (Node) getSession(WCMCoreUtils.getSystemSessionProvider(), true).getItem(queryPath);
279 }
280 Node queriesHome = queryNode.getParent();
281 queryNode.remove();
282 queriesHome.save();
283 removeFromCache(queryPath);
284 }
285
286
287
288
289 public void addSharedQuery(String queryName,
290 String statement,
291 String language,
292 String[] permissions,
293 boolean cachedResult) throws Exception {
294 addSharedQuery(queryName,
295 statement,
296 language,
297 permissions,
298 cachedResult,
299 WCMCoreUtils.getUserSessionProvider());
300 }
301
302 public void addSharedQuery(String queryName,
303 String statement,
304 String language,
305 String[] permissions,
306 boolean cachedResult,
307 SessionProvider provider) throws Exception {
308 Session session = getSession(provider, true);
309 ValueFactory vt = session.getValueFactory();
310 String queryPath;
311 List<Value> perm = new ArrayList<Value>();
312 for (String permission : permissions) {
313 Value vl = vt.createValue(permission);
314 perm.add(vl);
315 }
316 Value[] vls = perm.toArray(new Value[] {});
317
318 String queriesPath = baseQueriesPath_;
319 Node queryHome = (Node)session.getItem(baseQueriesPath_);
320 QueryManager queryManager = session.getWorkspace().getQueryManager();
321 queryManager.createQuery(statement, language);
322 if (queryHome.hasNode(queryName)) {
323 Node query = queryHome.getNode(queryName);
324 query.setProperty("jcr:language", language);
325 query.setProperty("jcr:statement", statement);
326 query.setProperty("exo:accessPermissions", vls);
327 query.setProperty("exo:cachedResult", cachedResult);
328 query.save();
329 session.save();
330 queryPath = query.getPath();
331 } else {
332 QueryManager manager = session.getWorkspace().getQueryManager();
333 Query query = manager.createQuery(statement, language);
334 Node newQuery = query.storeAsNode(baseQueriesPath_ + "/" + queryName);
335 newQuery.addMixin("mix:sharedQuery");
336 newQuery.setProperty("exo:accessPermissions", vls);
337 newQuery.setProperty("exo:cachedResult", cachedResult);
338 session.getItem(queriesPath).save();
339 queryPath = queriesPath;
340 }
341 removeFromCache(queryPath);
342 }
343
344
345
346
347 public Node getSharedQuery(String queryName, SessionProvider provider) throws Exception {
348 Session session = getSession(provider, true);
349 try {
350 Node sharedQueryNode = (Node) session.getItem(baseQueriesPath_ + "/" + queryName);
351 return sharedQueryNode;
352 } catch (PathNotFoundException e) {
353 return null;
354 }
355 }
356
357
358
359
360 public List<Node> getSharedQueries(SessionProvider provider) throws Exception {
361 Session session = getSession(provider, true);
362 List<Node> queries = new ArrayList<Node>();
363 Node sharedQueryHome = (Node) session.getItem(baseQueriesPath_);
364 NodeIterator iter = sharedQueryHome.getNodes();
365 while (iter.hasNext()) {
366 Node node = iter.nextNode();
367 if(node.isNodeType("nt:query")) {
368 queries.add(node);
369 }
370 }
371 return queries;
372 }
373
374
375
376
377 public List<Node> getSharedQueries(String userId, SessionProvider provider) throws Exception {
378 List<Node> sharedQueries = new ArrayList<Node>();
379 for(Node query : getSharedQueries(provider)) {
380 if (canUseQuery(userId, query)) {
381 sharedQueries.add(query);
382 }
383 }
384 return sharedQueries;
385 }
386
387
388
389
390 public List<Node> getSharedQueries(String queryType,
391 String userId,
392 SessionProvider provider) throws Exception {
393 List<Node> resultList = new ArrayList<Node>();
394 String language = null;
395 for (Node queryNode: getSharedQueries(provider)) {
396 language = queryNode.getProperty("jcr:language").getString();
397 if (!queryType.equalsIgnoreCase(language)) continue;
398 if (canUseQuery(userId,queryNode)) {
399 resultList.add(queryNode);
400 }
401 }
402 return resultList;
403 }
404
405
406
407
408 public Query getQueryByPath(String queryPath, String userName, SessionProvider provider) throws Exception {
409 List<Query> queries = getQueries(userName, provider);
410 for (Query query : queries) {
411 if (query.getStoredQueryPath().equals(queryPath)) return query;
412 }
413 return null;
414 }
415
416
417
418
419 public void removeSharedQuery(String queryName, SessionProvider provider) throws Exception {
420 Session session = getSession(provider, true);
421 session.getItem(baseQueriesPath_ + "/" + queryName).remove();
422 session.save();
423 }
424
425
426
427
428 public QueryResult execute(String queryPath,
429 String workspace,
430 SessionProvider provider,
431 String userId) throws Exception {
432 Session session = getSession(provider, true);
433 Session querySession = getSession(workspace, provider);
434 Node queryNode = null;
435 try {
436 queryNode = (Node) session.getItem(queryPath);
437 } catch (PathNotFoundException e) {
438 if (LOG.isWarnEnabled()) {
439 LOG.warn("Can not find node by path " + queryPath + " in dms-system workspace");
440 }
441 queryNode = (Node) querySession.getItem(queryPath);
442 }
443 if (queryNode != null && queryNode.hasProperty("exo:cachedResult")
444 && queryNode.getProperty("exo:cachedResult").getBoolean()) {
445 String portalName = containerInfo_.getContainerName();
446 String key = portalName + queryPath;
447 QueryResult result = cache_.get(key);
448 if (result != null) return result;
449 result = execute(querySession, queryNode, userId);
450 cache_.put(key, result);
451 return result;
452 }
453 QueryResult queryResult = execute(querySession, queryNode, userId);
454 return queryResult;
455 }
456
457
458
459
460
461
462
463
464
465 private QueryResult execute(Session session, Node queryNode, String userId) throws Exception {
466 return createQuery(session, queryNode, userId).execute();
467 }
468
469
470
471
472
473
474
475
476
477
478
479
480 private String computeStatement(String statement, String userId) {
481
482
483 String ret = statement;
484
485
486 ret = ret.replace("${UserId}$",userId);
487
488
489 String currentDate = ISO8601.format(new GregorianCalendar());
490 ret = ret.replace("${Date}$",currentDate);
491
492 return ret;
493 }
494
495
496
497
498
499
500 private void removeFromCache(String queryPath) throws Exception {
501 String portalName = containerInfo_.getContainerName();
502 String key = portalName + queryPath;
503 QueryResult result = cache_.get(key);
504 if (result != null) cache_.remove(key);
505 }
506
507
508
509
510
511
512 private Session getSession() throws Exception {
513 ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
514 SessionProvider sessionProvider = WCMCoreUtils.getSystemSessionProvider();
515 return sessionProvider.getSession(manageableRepository.getConfiguration().getDefaultWorkspaceName(),
516 manageableRepository);
517
518 }
519
520
521
522
523
524
525
526
527 private Session getSession(SessionProvider provider, boolean flag) throws Exception {
528 ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
529 if (!flag) {
530 String workspace = manageableRepository.getConfiguration().getDefaultWorkspaceName();
531 return provider.getSession(workspace, manageableRepository);
532 }
533 DMSRepositoryConfiguration dmsRepoConfig = dmsConfiguration_.getConfig();
534 return provider.getSession(dmsRepoConfig.getSystemWorkspace(), manageableRepository);
535 }
536
537
538
539
540
541
542
543
544 private Session getSession(String workspace, SessionProvider provider) throws Exception {
545 ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
546 return provider.getSession(workspace,manageableRepository);
547 }
548
549
550
551
552
553
554
555
556 private boolean canUseQuery(String userId, Node queryNode) throws Exception{
557 Value[] values = queryNode.getProperty("exo:accessPermissions").getValues();
558 for(Value value : values) {
559 String accessPermission = value.getString();
560 if (hasMembership(userId,accessPermission)) {
561 return true;
562 }
563 }
564 return false;
565 }
566
567
568
569
570
571
572
573 private boolean hasMembership(String userId, String roleExpression) {
574 if (userId == null || userId.length() == 0) {
575 return false;
576 }
577 if(roleExpression.equals("*") || roleExpression.equals(IdentityConstants.ANY))
578 return true;
579 ConversationState conversationState = ConversationState.getCurrent();
580 Identity identity = conversationState.getIdentity();
581 String membershipType = roleExpression.substring(0, roleExpression.indexOf(":"));
582 String groupName = roleExpression.substring(roleExpression.indexOf(":") + 1);
583 try {
584 MembershipHandler membershipHandler = organizationService_.getMembershipHandler();
585 if ("*".equals(membershipType)) {
586
587 if (userId.equals(ConversationState.getCurrent().getIdentity().getUserId())) {
588 return identity.isMemberOf(groupName);
589 } else {
590 return !membershipHandler.findMembershipsByUserAndGroup( userId,groupName).isEmpty();
591 }
592 }
593 if (userId.equals(ConversationState.getCurrent().getIdentity().getUserId())) {
594 return identity.isMemberOf(groupName, membershipType);
595 } else {
596
597 return membershipHandler.findMembershipByUserGroupAndType(userId,groupName,membershipType) != null;
598 }
599 }
600 catch(Exception e) {
601 return false;
602 }
603 }
604
605
606
607
608 public Query getQuery(String queryPath, String workspace, SessionProvider provider, String userId) throws Exception {
609 Session session = getSession(provider, true);
610 Session querySession = getSession(workspace, provider);
611 Node queryNode = null;
612 try {
613 queryNode = (Node) session.getItem(queryPath);
614 } catch (PathNotFoundException e) {
615 if (LOG.isWarnEnabled()) {
616 LOG.warn("Can not find node by path " + queryPath + " in dms-system workspace");
617 }
618 queryNode = (Node) querySession.getItem(queryPath);
619 }
620 return createQuery(querySession, queryNode, userId);
621 }
622
623
624
625
626
627
628
629
630
631 private Query createQuery(Session session, Node queryNode, String userId) throws Exception {
632 String statement = this.computeStatement(queryNode.getProperty("jcr:statement").getString(), userId);
633 String language = queryNode.getProperty("jcr:language").getString();
634 Query query = session.getWorkspace().getQueryManager().createQuery(statement,language);
635 return query;
636 }
637
638 @Override
639 public Set<String> getAllConfiguredQueries() {
640 return configuredQueries_;
641 }
642
643 }