1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portlet.wiki.service.impl;
16  
17  import com.liferay.portal.PortalException;
18  import com.liferay.portal.SystemException;
19  import com.liferay.portal.kernel.configuration.Filter;
20  import com.liferay.portal.kernel.log.Log;
21  import com.liferay.portal.kernel.log.LogFactoryUtil;
22  import com.liferay.portal.kernel.search.BooleanClauseOccur;
23  import com.liferay.portal.kernel.search.BooleanQuery;
24  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
25  import com.liferay.portal.kernel.search.Field;
26  import com.liferay.portal.kernel.search.Hits;
27  import com.liferay.portal.kernel.search.SearchEngineUtil;
28  import com.liferay.portal.kernel.search.SearchException;
29  import com.liferay.portal.kernel.search.TermQuery;
30  import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.InstancePool;
33  import com.liferay.portal.kernel.util.PropsKeys;
34  import com.liferay.portal.kernel.util.Validator;
35  import com.liferay.portal.model.Group;
36  import com.liferay.portal.model.ResourceConstants;
37  import com.liferay.portal.model.User;
38  import com.liferay.portal.service.ServiceContext;
39  import com.liferay.portal.util.PropsUtil;
40  import com.liferay.portlet.wiki.DuplicateNodeNameException;
41  import com.liferay.portlet.wiki.NodeNameException;
42  import com.liferay.portlet.wiki.importers.WikiImporter;
43  import com.liferay.portlet.wiki.model.WikiNode;
44  import com.liferay.portlet.wiki.model.WikiPage;
45  import com.liferay.portlet.wiki.service.base.WikiNodeLocalServiceBaseImpl;
46  import com.liferay.portlet.wiki.util.Indexer;
47  
48  import java.io.File;
49  
50  import java.util.Date;
51  import java.util.HashMap;
52  import java.util.Iterator;
53  import java.util.List;
54  import java.util.Map;
55  
56  /**
57   * <a href="WikiNodeLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
58   *
59   * @author Brian Wing Shun Chan
60   * @author Charles May
61   * @author Raymond Augé
62   */
63  public class WikiNodeLocalServiceImpl extends WikiNodeLocalServiceBaseImpl {
64  
65      public WikiNode addNode(
66              long userId, String name, String description,
67              ServiceContext serviceContext)
68          throws PortalException, SystemException {
69  
70          return addNode(null, userId, name, description, serviceContext);
71      }
72  
73      public WikiNode addNode(
74              String uuid, long userId, String name, String description,
75              ServiceContext serviceContext)
76          throws PortalException, SystemException {
77  
78          // Node
79  
80          User user = userPersistence.findByPrimaryKey(userId);
81          long groupId = serviceContext.getScopeGroupId();
82          Date now = new Date();
83  
84          validate(groupId, name);
85  
86          long nodeId = counterLocalService.increment();
87  
88          WikiNode node = wikiNodePersistence.create(nodeId);
89  
90          node.setUuid(uuid);
91          node.setGroupId(groupId);
92          node.setCompanyId(user.getCompanyId());
93          node.setUserId(user.getUserId());
94          node.setUserName(user.getFullName());
95          node.setCreateDate(serviceContext.getCreateDate(now));
96          node.setModifiedDate(serviceContext.getModifiedDate(now));
97          node.setName(name);
98          node.setDescription(description);
99  
100         try {
101             wikiNodePersistence.update(node, false);
102         }
103         catch (SystemException se) {
104             if (_log.isWarnEnabled()) {
105                 _log.warn(
106                     "Add failed, fetch {groupId=" + groupId + ", name=" +
107                         name + "}");
108             }
109 
110             node = wikiNodePersistence.fetchByG_N(groupId, name, false);
111 
112             if (node == null) {
113                 throw se;
114             }
115 
116             return node;
117         }
118 
119         // Resources
120 
121         if (serviceContext.getAddCommunityPermissions() ||
122             serviceContext.getAddGuestPermissions()) {
123 
124             addNodeResources(
125                 node, serviceContext.getAddCommunityPermissions(),
126                 serviceContext.getAddGuestPermissions());
127         }
128         else {
129             addNodeResources(
130                 node, serviceContext.getCommunityPermissions(),
131                 serviceContext.getGuestPermissions());
132         }
133 
134         return node;
135     }
136 
137     public void addNodeResources(
138             long nodeId, boolean addCommunityPermissions,
139             boolean addGuestPermissions)
140         throws PortalException, SystemException {
141 
142         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
143 
144         addNodeResources(node, addCommunityPermissions, addGuestPermissions);
145     }
146 
147     public void addNodeResources(
148             WikiNode node, boolean addCommunityPermissions,
149             boolean addGuestPermissions)
150         throws PortalException, SystemException {
151 
152         resourceLocalService.addResources(
153             node.getCompanyId(), node.getGroupId(), node.getUserId(),
154             WikiNode.class.getName(), node.getNodeId(), false,
155             addCommunityPermissions, addGuestPermissions);
156     }
157 
158     public void addNodeResources(
159             long nodeId, String[] communityPermissions,
160             String[] guestPermissions)
161         throws PortalException, SystemException {
162 
163         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
164 
165         addNodeResources(node, communityPermissions, guestPermissions);
166     }
167 
168     public void addNodeResources(
169             WikiNode node, String[] communityPermissions,
170             String[] guestPermissions)
171         throws PortalException, SystemException {
172 
173         resourceLocalService.addModelResources(
174             node.getCompanyId(), node.getGroupId(), node.getUserId(),
175             WikiNode.class.getName(), node.getNodeId(), communityPermissions,
176             guestPermissions);
177     }
178 
179     public void deleteNode(long nodeId)
180         throws PortalException, SystemException {
181 
182         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
183 
184         deleteNode(node);
185     }
186 
187     public void deleteNode(WikiNode node)
188         throws PortalException, SystemException {
189 
190         // Indexer
191 
192         try {
193             Indexer.deletePages(node.getCompanyId(), node.getNodeId());
194         }
195         catch (SearchException se) {
196             _log.error("Deleting index " + node.getNodeId(), se);
197         }
198 
199         // Subscriptions
200 
201         subscriptionLocalService.deleteSubscriptions(
202             node.getCompanyId(), WikiNode.class.getName(), node.getNodeId());
203 
204         // Pages
205 
206         wikiPageLocalService.deletePages(node.getNodeId());
207 
208         // Resources
209 
210         resourceLocalService.deleteResource(
211             node.getCompanyId(), WikiNode.class.getName(),
212             ResourceConstants.SCOPE_INDIVIDUAL, node.getNodeId());
213 
214         // Node
215 
216         wikiNodePersistence.remove(node);
217     }
218 
219     public void deleteNodes(long groupId)
220         throws PortalException, SystemException {
221 
222         Iterator<WikiNode> itr = wikiNodePersistence.findByGroupId(
223             groupId).iterator();
224 
225         while (itr.hasNext()) {
226             WikiNode node = itr.next();
227 
228             deleteNode(node);
229         }
230     }
231 
232     public WikiNode getNode(long nodeId)
233         throws PortalException, SystemException {
234 
235         return wikiNodePersistence.findByPrimaryKey(nodeId);
236     }
237 
238     public WikiNode getNode(long groupId, String nodeName)
239         throws PortalException, SystemException {
240 
241         return wikiNodePersistence.findByG_N(groupId, nodeName);
242     }
243 
244     public List<WikiNode> getNodes(long groupId) throws SystemException {
245         return wikiNodePersistence.findByGroupId(groupId);
246     }
247 
248     public List<WikiNode> getNodes(long groupId, int start, int end)
249         throws SystemException {
250 
251         return wikiNodePersistence.findByGroupId(groupId, start, end);
252     }
253 
254     public int getNodesCount(long groupId) throws SystemException {
255         return wikiNodePersistence.countByGroupId(groupId);
256     }
257 
258     public void importPages(
259             long userId, long nodeId, String importer, File[] files,
260             Map<String, String[]> options)
261         throws PortalException, SystemException {
262 
263         WikiNode node = getNode(nodeId);
264 
265         getWikiImporter(importer).importPages(userId, node, files, options);
266     }
267 
268     public void reIndex(String[] ids) throws SystemException {
269         if (SearchEngineUtil.isIndexReadOnly()) {
270             return;
271         }
272 
273         long companyId = GetterUtil.getLong(ids[0]);
274 
275         try {
276             reIndexNodes(companyId);
277         }
278         catch (SystemException se) {
279             throw se;
280         }
281         catch (Exception e) {
282             throw new SystemException(e);
283         }
284     }
285 
286     public Hits search(
287             long companyId, long groupId, long userId, long[] nodeIds,
288             String keywords, int start, int end)
289         throws SystemException {
290 
291         try {
292             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
293 
294             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
295 
296             if (groupId > 0) {
297                 Group group = groupLocalService.getGroup(groupId);
298 
299                 if (group.isLayout()) {
300                     contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
301 
302                     groupId = group.getParentGroupId();
303                 }
304 
305                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
306             }
307 
308             if ((nodeIds != null) && (nodeIds.length > 0)) {
309                 BooleanQuery nodeIdsQuery = BooleanQueryFactoryUtil.create();
310 
311                 for (long nodeId : nodeIds) {
312                     if (userId > 0) {
313                         try {
314                             wikiNodeService.getNode(nodeId);
315                         }
316                         catch (Exception e) {
317                             continue;
318                         }
319                     }
320 
321                     TermQuery termQuery = TermQueryFactoryUtil.create(
322                         "nodeId", nodeId);
323 
324                     nodeIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
325                 }
326 
327                 contextQuery.add(nodeIdsQuery, BooleanClauseOccur.MUST);
328             }
329 
330             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
331 
332             searchQuery.addTerms(_KEYWORDS_FIELDS, keywords);
333 
334             searchQuery.addExactTerm(Field.TAGS_ENTRIES, keywords);
335 
336             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
337 
338             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
339 
340             if (searchQuery.clauses().size() > 0) {
341                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
342             }
343 
344             return SearchEngineUtil.search(
345                 companyId, groupId, userId, WikiPage.class.getName(), fullQuery,
346                 start, end);
347         }
348         catch (Exception e) {
349             throw new SystemException(e);
350         }
351     }
352 
353     public void subscribeNode(long userId, long nodeId)
354         throws PortalException, SystemException {
355 
356         subscriptionLocalService.addSubscription(
357             userId, WikiNode.class.getName(), nodeId);
358     }
359 
360     public void unsubscribeNode(long userId, long nodeId)
361         throws PortalException, SystemException {
362 
363         subscriptionLocalService.deleteSubscription(
364             userId, WikiNode.class.getName(), nodeId);
365     }
366 
367     /**
368      * @deprecated
369      */
370     public WikiNode updateNode(
371             long nodeId, String name, String description)
372         throws PortalException, SystemException {
373 
374         return updateNode(nodeId, name, description, new ServiceContext());
375     }
376 
377     public WikiNode updateNode(
378             long nodeId, String name, String description,
379             ServiceContext serviceContext)
380         throws PortalException, SystemException {
381 
382         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
383 
384         validate(nodeId, node.getGroupId(), name);
385 
386         node.setModifiedDate(serviceContext.getModifiedDate(null));
387         node.setName(name);
388         node.setDescription(description);
389 
390         wikiNodePersistence.update(node, false);
391 
392         return node;
393     }
394 
395     protected WikiImporter getWikiImporter(String importer)
396         throws SystemException {
397 
398         WikiImporter wikiImporter = _wikiImporters.get(importer);
399 
400         if (wikiImporter == null) {
401             String importerClass = PropsUtil.get(
402                 PropsKeys.WIKI_IMPORTERS_CLASS, new Filter(importer));
403 
404             if (importerClass != null) {
405                 wikiImporter = (WikiImporter)InstancePool.get(importerClass);
406 
407                 _wikiImporters.put(importer, wikiImporter);
408             }
409 
410             if (importer == null) {
411                 throw new SystemException(
412                     "Unable to instantiate wiki importer class " +
413                         importerClass);
414             }
415         }
416 
417         return wikiImporter;
418     }
419 
420     protected void reIndexNodes(long companyId) throws SystemException {
421         int nodeCount = wikiNodePersistence.countByCompanyId(companyId);
422 
423         int nodePages = nodeCount / Indexer.DEFAULT_INTERVAL;
424 
425         for (int i = 0; i <= nodePages; i++) {
426             int nodeStart = (i * Indexer.DEFAULT_INTERVAL);
427             int nodeEnd = nodeStart + Indexer.DEFAULT_INTERVAL;
428 
429             reIndexNodes(companyId, nodeStart, nodeEnd);
430         }
431     }
432 
433     protected void reIndexNodes(long companyId, int nodeStart, int nodeEnd)
434         throws SystemException {
435 
436         List<WikiNode> nodes = wikiNodePersistence.findByCompanyId(
437             companyId, nodeStart, nodeEnd);
438 
439         for (WikiNode node : nodes) {
440             long nodeId = node.getNodeId();
441 
442             int pageCount = wikiPagePersistence.countByN_H(nodeId, true);
443 
444             int pagePages = pageCount / Indexer.DEFAULT_INTERVAL;
445 
446             for (int i = 0; i <= pagePages; i++) {
447                 int pageStart = (i * Indexer.DEFAULT_INTERVAL);
448                 int pageEnd = pageStart + Indexer.DEFAULT_INTERVAL;
449 
450                 reIndexPages(nodeId, pageStart, pageEnd);
451             }
452         }
453     }
454 
455     protected void reIndexPages(long nodeId, int pageStart, int pageEnd)
456         throws SystemException {
457 
458         List<WikiPage> pages = wikiPagePersistence.findByN_H(
459             nodeId, true, pageStart, pageEnd);
460 
461         for (WikiPage page : pages) {
462             wikiPageLocalService.reIndex(page);
463         }
464     }
465 
466     protected void validate(long groupId, String name)
467         throws PortalException, SystemException {
468 
469         validate(0, groupId, name);
470     }
471 
472     protected void validate(long nodeId, long groupId, String name)
473         throws PortalException, SystemException {
474 
475         if (name.equalsIgnoreCase("tag")) {
476             throw new NodeNameException(name + " is reserved");
477         }
478 
479         if (!Validator.isName(name)) {
480             throw new NodeNameException();
481         }
482 
483         WikiNode node = wikiNodePersistence.fetchByG_N(groupId, name);
484 
485         if ((node != null) && (node.getNodeId() != nodeId)) {
486             throw new DuplicateNodeNameException();
487         }
488     }
489 
490     private static final String[] _KEYWORDS_FIELDS = {
491         Field.CONTENT, Field.TITLE
492     };
493 
494     private static Log _log = LogFactoryUtil.getLog(
495         WikiNodeLocalServiceImpl.class);
496 
497     private Map<String, WikiImporter> _wikiImporters =
498         new HashMap<String, WikiImporter>();
499 
500 }