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