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.util.PortalUtil;
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   *
69   */
70  public class WikiNodeLocalServiceImpl extends WikiNodeLocalServiceBaseImpl {
71  
72      public WikiNode addNode(
73              long userId, long plid, String name, String description,
74              boolean addCommunityPermissions, boolean addGuestPermissions)
75          throws PortalException, SystemException {
76  
77          return addNode(
78              null, userId, plid, name, description,
79              Boolean.valueOf(addCommunityPermissions),
80              Boolean.valueOf(addGuestPermissions), null, null);
81      }
82  
83      public WikiNode addNode(
84              String uuid, long userId, long plid, String name,
85              String description, boolean addCommunityPermissions,
86              boolean addGuestPermissions)
87          throws PortalException, SystemException {
88  
89          return addNode(
90              uuid, userId, plid, name, description,
91              Boolean.valueOf(addCommunityPermissions),
92              Boolean.valueOf(addGuestPermissions), null, null);
93      }
94  
95      public WikiNode addNode(
96              long userId, long plid, String name, String description,
97              String[] communityPermissions, String[] guestPermissions)
98          throws PortalException, SystemException {
99  
100         return addNode(
101             null, userId, plid, name, description, null, null,
102             communityPermissions, guestPermissions);
103     }
104 
105     public WikiNode addNode(
106             String uuid, long userId, long plid, String name,
107             String description, Boolean addCommunityPermissions,
108             Boolean addGuestPermissions, String[] communityPermissions,
109             String[] guestPermissions)
110         throws PortalException, SystemException {
111 
112         // Node
113 
114         User user = userPersistence.findByPrimaryKey(userId);
115         long groupId = PortalUtil.getScopeGroupId(plid);
116         Date now = new Date();
117 
118         validate(groupId, name);
119 
120         long nodeId = counterLocalService.increment();
121 
122         WikiNode node = wikiNodePersistence.create(nodeId);
123 
124         node.setUuid(uuid);
125         node.setGroupId(groupId);
126         node.setCompanyId(user.getCompanyId());
127         node.setUserId(user.getUserId());
128         node.setUserName(user.getFullName());
129         node.setCreateDate(now);
130         node.setModifiedDate(now);
131         node.setName(name);
132         node.setDescription(description);
133 
134         wikiNodePersistence.update(node, false);
135 
136         // Resources
137 
138         if ((addCommunityPermissions != null) &&
139             (addGuestPermissions != null)) {
140 
141             addNodeResources(
142                 node, addCommunityPermissions.booleanValue(),
143                 addGuestPermissions.booleanValue());
144         }
145         else {
146             addNodeResources(node, communityPermissions, guestPermissions);
147         }
148 
149         return node;
150     }
151 
152     public void addNodeResources(
153             long nodeId, boolean addCommunityPermissions,
154             boolean addGuestPermissions)
155         throws PortalException, SystemException {
156 
157         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
158 
159         addNodeResources(node, addCommunityPermissions, addGuestPermissions);
160     }
161 
162     public void addNodeResources(
163             WikiNode node, boolean addCommunityPermissions,
164             boolean addGuestPermissions)
165         throws PortalException, SystemException {
166 
167         resourceLocalService.addResources(
168             node.getCompanyId(), node.getGroupId(), node.getUserId(),
169             WikiNode.class.getName(), node.getNodeId(), false,
170             addCommunityPermissions, addGuestPermissions);
171     }
172 
173     public void addNodeResources(
174             long nodeId, String[] communityPermissions,
175             String[] guestPermissions)
176         throws PortalException, SystemException {
177 
178         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
179 
180         addNodeResources(node, communityPermissions, guestPermissions);
181     }
182 
183     public void addNodeResources(
184             WikiNode node, String[] communityPermissions,
185             String[] guestPermissions)
186         throws PortalException, SystemException {
187 
188         resourceLocalService.addModelResources(
189             node.getCompanyId(), node.getGroupId(), node.getUserId(),
190             WikiNode.class.getName(), node.getNodeId(), communityPermissions,
191             guestPermissions);
192     }
193 
194     public void deleteNode(long nodeId)
195         throws PortalException, SystemException {
196 
197         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
198 
199         deleteNode(node);
200     }
201 
202     public void deleteNode(WikiNode node)
203         throws PortalException, SystemException {
204 
205         // Indexer
206 
207         try {
208             Indexer.deletePages(node.getCompanyId(), node.getNodeId());
209         }
210         catch (SearchException se) {
211             _log.error("Deleting index " + node.getNodeId(), se);
212         }
213 
214         // Subscriptions
215 
216         subscriptionLocalService.deleteSubscriptions(
217             node.getCompanyId(), WikiNode.class.getName(), node.getNodeId());
218 
219         // Pages
220 
221         wikiPageLocalService.deletePages(node.getNodeId());
222 
223         // Resources
224 
225         resourceLocalService.deleteResource(
226             node.getCompanyId(), WikiNode.class.getName(),
227             ResourceConstants.SCOPE_INDIVIDUAL, node.getNodeId());
228 
229         // Node
230 
231         wikiNodePersistence.remove(node);
232     }
233 
234     public void deleteNodes(long groupId)
235         throws PortalException, SystemException {
236 
237         Iterator<WikiNode> itr = wikiNodePersistence.findByGroupId(
238             groupId).iterator();
239 
240         while (itr.hasNext()) {
241             WikiNode node = itr.next();
242 
243             deleteNode(node);
244         }
245     }
246 
247     public WikiNode getNode(long nodeId)
248         throws PortalException, SystemException {
249 
250         return wikiNodePersistence.findByPrimaryKey(nodeId);
251     }
252 
253     public WikiNode getNode(long groupId, String nodeName)
254         throws PortalException, SystemException {
255 
256         return wikiNodePersistence.findByG_N(groupId, nodeName);
257     }
258 
259     public List<WikiNode> getNodes(long groupId) throws SystemException {
260         return wikiNodePersistence.findByGroupId(groupId);
261     }
262 
263     public List<WikiNode> getNodes(long groupId, int start, int end)
264         throws SystemException {
265 
266         return wikiNodePersistence.findByGroupId(groupId, start, end);
267     }
268 
269     public int getNodesCount(long groupId) throws SystemException {
270         return wikiNodePersistence.countByGroupId(groupId);
271     }
272 
273     public void importPages(
274             long userId, long nodeId, String importer, File[] files,
275             Map<String, String[]> options)
276         throws PortalException, SystemException {
277 
278         WikiNode node = getNode(nodeId);
279 
280         getWikiImporter(importer).importPages(userId, node, files, options);
281     }
282 
283     public void reIndex(String[] ids) throws SystemException {
284         if (SearchEngineUtil.isIndexReadOnly()) {
285             return;
286         }
287 
288         long companyId = GetterUtil.getLong(ids[0]);
289 
290         try {
291             reIndexNodes(companyId);
292         }
293         catch (SystemException se) {
294             throw se;
295         }
296         catch (Exception e) {
297             throw new SystemException(e);
298         }
299     }
300 
301     public Hits search(
302             long companyId, long groupId, long[] nodeIds, String keywords,
303             int start, int end)
304         throws SystemException {
305 
306         try {
307             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
308 
309             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
310 
311             if (groupId > 0) {
312                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
313             }
314 
315             if ((nodeIds != null) && (nodeIds.length > 0)) {
316                 BooleanQuery nodeIdsQuery = BooleanQueryFactoryUtil.create();
317 
318                 for (long nodeId : nodeIds) {
319                     TermQuery termQuery = TermQueryFactoryUtil.create(
320                         Field.ENTRY_CLASS_PK, nodeId);
321 
322                     nodeIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
323                 }
324 
325                 contextQuery.add(nodeIdsQuery, BooleanClauseOccur.MUST);
326             }
327 
328             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
329 
330             if (Validator.isNotNull(keywords)) {
331                 searchQuery.addTerm(Field.TITLE, keywords);
332                 searchQuery.addTerm(Field.CONTENT, keywords);
333                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords, true);
334             }
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(companyId, fullQuery, start, end);
345         }
346         catch (Exception e) {
347             throw new SystemException(e);
348         }
349     }
350 
351     public void subscribeNode(long userId, long nodeId)
352         throws PortalException, SystemException {
353 
354         subscriptionLocalService.addSubscription(
355             userId, WikiNode.class.getName(), nodeId);
356     }
357 
358     public void unsubscribeNode(long userId, long nodeId)
359         throws PortalException, SystemException {
360 
361         subscriptionLocalService.deleteSubscription(
362             userId, WikiNode.class.getName(), nodeId);
363     }
364 
365     public WikiNode updateNode(long nodeId, String name, String description)
366         throws PortalException, SystemException {
367 
368         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
369 
370         validate(nodeId, node.getGroupId(), name);
371 
372         node.setModifiedDate(new Date());
373         node.setName(name);
374         node.setDescription(description);
375 
376         wikiNodePersistence.update(node, false);
377 
378         return node;
379     }
380 
381     protected WikiImporter getWikiImporter(String importer)
382         throws SystemException {
383 
384         WikiImporter wikiImporter = _wikiImporters.get(importer);
385 
386         if (wikiImporter == null) {
387             String importerClass = PropsUtil.get(
388                 PropsKeys.WIKI_IMPORTERS_CLASS, new Filter(importer));
389 
390             if (importerClass != null) {
391                 wikiImporter = (WikiImporter)InstancePool.get(importerClass);
392 
393                 _wikiImporters.put(importer, wikiImporter);
394             }
395 
396             if (importer == null) {
397                 throw new SystemException(
398                     "Unable to instantiate wiki importer class " +
399                         importerClass);
400             }
401         }
402 
403         return wikiImporter;
404     }
405 
406     protected void reIndexNodes(long companyId) throws SystemException {
407         int nodeCount = wikiNodePersistence.countByCompanyId(companyId);
408 
409         int nodePages = nodeCount / Indexer.DEFAULT_INTERVAL;
410 
411         for (int i = 0; i <= nodePages; i++) {
412             int nodeStart = (i * Indexer.DEFAULT_INTERVAL);
413             int nodeEnd = nodeStart + Indexer.DEFAULT_INTERVAL;
414 
415             reIndexNodes(companyId, nodeStart, nodeEnd);
416         }
417     }
418 
419     protected void reIndexNodes(long companyId, int nodeStart, int nodeEnd)
420         throws SystemException {
421 
422         List<WikiNode> nodes = wikiNodePersistence.findByCompanyId(
423             companyId, nodeStart, nodeEnd);
424 
425         for (WikiNode node : nodes) {
426             long nodeId = node.getNodeId();
427 
428             int pageCount = wikiPagePersistence.countByN_H(nodeId, true);
429 
430             int pagePages = pageCount / Indexer.DEFAULT_INTERVAL;
431 
432             for (int i = 0; i <= pagePages; i++) {
433                 int pageStart = (i * Indexer.DEFAULT_INTERVAL);
434                 int pageEnd = pageStart + Indexer.DEFAULT_INTERVAL;
435 
436                 reIndexPages(nodeId, pageStart, pageEnd);
437             }
438         }
439     }
440 
441     protected void reIndexPages(long nodeId, int pageStart, int pageEnd)
442         throws SystemException {
443 
444         List<WikiPage> pages = wikiPagePersistence.findByN_H(
445             nodeId, true, pageStart, pageEnd);
446 
447         for (WikiPage page : pages) {
448             wikiPageLocalService.reIndex(page);
449         }
450     }
451 
452     protected void validate(long groupId, String name)
453         throws PortalException, SystemException {
454 
455         validate(0, groupId, name);
456     }
457 
458     protected void validate(long nodeId, long groupId, String name)
459         throws PortalException, SystemException {
460 
461         if (name.equalsIgnoreCase("tag")) {
462             throw new NodeNameException(name + " is reserved");
463         }
464 
465         if (!Validator.isName(name)) {
466             throw new NodeNameException();
467         }
468 
469         WikiNode node = wikiNodePersistence.fetchByG_N(groupId, name);
470 
471         if ((node != null) && (node.getNodeId() != nodeId)) {
472             throw new DuplicateNodeNameException();
473         }
474     }
475 
476     private static Log _log =
477         LogFactoryUtil.getLog(WikiNodeLocalServiceImpl.class);
478 
479     private Map<String, WikiImporter> _wikiImporters =
480         new HashMap<String, WikiImporter>();
481 
482 }