1   /**
2    * Copyright (c) 2000-2008 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.search.Document;
29  import com.liferay.portal.kernel.search.Field;
30  import com.liferay.portal.kernel.search.Hits;
31  import com.liferay.portal.kernel.search.SearchEngineUtil;
32  import com.liferay.portal.kernel.search.SearchException;
33  import com.liferay.portal.kernel.util.GetterUtil;
34  import com.liferay.portal.kernel.util.InstancePool;
35  import com.liferay.portal.kernel.util.Validator;
36  import com.liferay.portal.model.ResourceConstants;
37  import com.liferay.portal.model.User;
38  import com.liferay.portal.search.lucene.LuceneUtil;
39  import com.liferay.portal.util.PortalUtil;
40  import com.liferay.portal.util.PropsKeys;
41  import com.liferay.portal.util.PropsUtil;
42  import com.liferay.portlet.wiki.DuplicateNodeNameException;
43  import com.liferay.portlet.wiki.NodeNameException;
44  import com.liferay.portlet.wiki.importers.WikiImporter;
45  import com.liferay.portlet.wiki.model.WikiNode;
46  import com.liferay.portlet.wiki.model.WikiPage;
47  import com.liferay.portlet.wiki.service.base.WikiNodeLocalServiceBaseImpl;
48  import com.liferay.portlet.wiki.util.Indexer;
49  
50  import java.io.File;
51  
52  import java.util.Date;
53  import java.util.HashMap;
54  import java.util.Iterator;
55  import java.util.List;
56  import java.util.Map;
57  
58  import org.apache.commons.logging.Log;
59  import org.apache.commons.logging.LogFactory;
60  import org.apache.lucene.index.Term;
61  import org.apache.lucene.search.BooleanClause;
62  import org.apache.lucene.search.BooleanQuery;
63  import org.apache.lucene.search.TermQuery;
64  
65  /**
66   * <a href="WikiNodeLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
67   *
68   * @author Brian Wing Shun Chan
69   * @author Charles May
70   *
71   */
72  public class WikiNodeLocalServiceImpl extends WikiNodeLocalServiceBaseImpl {
73  
74      public WikiNode addNode(
75              long userId, long plid, String name, String description,
76              boolean addCommunityPermissions, boolean addGuestPermissions)
77          throws PortalException, SystemException {
78  
79          return addNode(
80              null, userId, plid, name, description,
81              Boolean.valueOf(addCommunityPermissions),
82              Boolean.valueOf(addGuestPermissions), null, null);
83      }
84  
85      public WikiNode addNode(
86              String uuid, long userId, long plid, String name,
87              String description, boolean addCommunityPermissions,
88              boolean addGuestPermissions)
89          throws PortalException, SystemException {
90  
91          return addNode(
92              uuid, userId, plid, name, description,
93              Boolean.valueOf(addCommunityPermissions),
94              Boolean.valueOf(addGuestPermissions), null, null);
95      }
96  
97      public WikiNode addNode(
98              long userId, long plid, String name, String description,
99              String[] communityPermissions, String[] guestPermissions)
100         throws PortalException, SystemException {
101 
102         return addNode(
103             null, userId, plid, name, description, null, null,
104             communityPermissions, guestPermissions);
105     }
106 
107     public WikiNode addNode(
108             String uuid, long userId, long plid, String name,
109             String description, Boolean addCommunityPermissions,
110             Boolean addGuestPermissions, String[] communityPermissions,
111             String[] guestPermissions)
112         throws PortalException, SystemException {
113 
114         // Node
115 
116         User user = userPersistence.findByPrimaryKey(userId);
117         long groupId = PortalUtil.getPortletGroupId(plid);
118         Date now = new Date();
119 
120         validate(groupId, name);
121 
122         long nodeId = counterLocalService.increment();
123 
124         WikiNode node = wikiNodePersistence.create(nodeId);
125 
126         node.setUuid(uuid);
127         node.setGroupId(groupId);
128         node.setCompanyId(user.getCompanyId());
129         node.setUserId(user.getUserId());
130         node.setUserName(user.getFullName());
131         node.setCreateDate(now);
132         node.setModifiedDate(now);
133         node.setName(name);
134         node.setDescription(description);
135 
136         wikiNodePersistence.update(node, false);
137 
138         // Resources
139 
140         if ((addCommunityPermissions != null) &&
141             (addGuestPermissions != null)) {
142 
143             addNodeResources(
144                 node, addCommunityPermissions.booleanValue(),
145                 addGuestPermissions.booleanValue());
146         }
147         else {
148             addNodeResources(node, communityPermissions, guestPermissions);
149         }
150 
151         return node;
152     }
153 
154     public void addNodeResources(
155             long nodeId, boolean addCommunityPermissions,
156             boolean addGuestPermissions)
157         throws PortalException, SystemException {
158 
159         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
160 
161         addNodeResources(node, addCommunityPermissions, addGuestPermissions);
162     }
163 
164     public void addNodeResources(
165             WikiNode node, boolean addCommunityPermissions,
166             boolean addGuestPermissions)
167         throws PortalException, SystemException {
168 
169         resourceLocalService.addResources(
170             node.getCompanyId(), node.getGroupId(), node.getUserId(),
171             WikiNode.class.getName(), node.getNodeId(), false,
172             addCommunityPermissions, addGuestPermissions);
173     }
174 
175     public void addNodeResources(
176             long nodeId, String[] communityPermissions,
177             String[] guestPermissions)
178         throws PortalException, SystemException {
179 
180         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
181 
182         addNodeResources(node, communityPermissions, guestPermissions);
183     }
184 
185     public void addNodeResources(
186             WikiNode node, String[] communityPermissions,
187             String[] guestPermissions)
188         throws PortalException, SystemException {
189 
190         resourceLocalService.addModelResources(
191             node.getCompanyId(), node.getGroupId(), node.getUserId(),
192             WikiNode.class.getName(), node.getNodeId(), communityPermissions,
193             guestPermissions);
194     }
195 
196     public void deleteNode(long nodeId)
197         throws PortalException, SystemException {
198 
199         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
200 
201         deleteNode(node);
202     }
203 
204     public void deleteNode(WikiNode node)
205         throws PortalException, SystemException {
206 
207         // Lucene
208 
209         try {
210             Indexer.deletePages(node.getCompanyId(), node.getNodeId());
211         }
212         catch (SearchException se) {
213             _log.error("Deleting index " + node.getNodeId(), se);
214         }
215 
216         // Subscriptions
217 
218         subscriptionLocalService.deleteSubscriptions(
219             node.getCompanyId(), WikiNode.class.getName(), node.getNodeId());
220 
221         // Pages
222 
223         wikiPageLocalService.deletePages(node.getNodeId());
224 
225         // Resources
226 
227         resourceLocalService.deleteResource(
228             node.getCompanyId(), WikiNode.class.getName(),
229             ResourceConstants.SCOPE_INDIVIDUAL, node.getNodeId());
230 
231         // Node
232 
233         wikiNodePersistence.remove(node.getNodeId());
234     }
235 
236     public void deleteNodes(long groupId)
237         throws PortalException, SystemException {
238 
239         Iterator<WikiNode> itr = wikiNodePersistence.findByGroupId(
240             groupId).iterator();
241 
242         while (itr.hasNext()) {
243             WikiNode node = itr.next();
244 
245             deleteNode(node);
246         }
247     }
248 
249     public WikiNode getNode(long nodeId)
250         throws PortalException, SystemException {
251 
252         return wikiNodePersistence.findByPrimaryKey(nodeId);
253     }
254 
255     public WikiNode getNode(long groupId, String nodeName)
256         throws PortalException, SystemException {
257 
258         return wikiNodePersistence.findByG_N(groupId, nodeName);
259     }
260 
261     public List<WikiNode> getNodes(long groupId) throws SystemException {
262         return wikiNodePersistence.findByGroupId(groupId);
263     }
264 
265     public List<WikiNode> getNodes(long groupId, int start, int end)
266         throws SystemException {
267 
268         return wikiNodePersistence.findByGroupId(groupId, start, end);
269     }
270 
271     public int getNodesCount(long groupId) throws SystemException {
272         return wikiNodePersistence.countByGroupId(groupId);
273     }
274 
275     public void importPages(
276             long userId, long nodeId, String importer, File[] files,
277             Map<String, String[]> options)
278         throws PortalException, SystemException {
279 
280         WikiNode node = getNode(nodeId);
281 
282         getWikiImporter(importer).importPages(userId, node, files, options);
283     }
284 
285     public void reIndex(String[] ids) throws SystemException {
286         if (SearchEngineUtil.isIndexReadOnly()) {
287             return;
288         }
289 
290         long companyId = GetterUtil.getLong(ids[0]);
291 
292         try {
293             Iterator<WikiNode> nodesItr = wikiNodePersistence.findByCompanyId(
294                 companyId).iterator();
295 
296             while (nodesItr.hasNext()) {
297                 WikiNode node = nodesItr.next();
298 
299                 long nodeId = node.getNodeId();
300 
301                 Iterator<WikiPage> pagesItr = wikiPagePersistence.findByNodeId(
302                     nodeId).iterator();
303 
304                 while (pagesItr.hasNext()) {
305                     WikiPage page = pagesItr.next();
306 
307                     long groupId = node.getGroupId();
308                     String title = page.getTitle();
309                     String content = page.getContent();
310 
311                     String[] tagsEntries = tagsEntryLocalService.getEntryNames(
312                         WikiPage.class.getName(), page.getResourcePrimKey());
313 
314                     try {
315                         Document doc = Indexer.getPageDocument(
316                             companyId, groupId, nodeId, title, content,
317                             tagsEntries);
318 
319                         SearchEngineUtil.addDocument(companyId, doc);
320                     }
321                     catch (Exception e1) {
322                         _log.error("Reindexing " + page.getPrimaryKey(), e1);
323                     }
324                 }
325             }
326         }
327         catch (SystemException se) {
328             throw se;
329         }
330         catch (Exception e2) {
331             throw new SystemException(e2);
332         }
333     }
334 
335     public Hits search(
336             long companyId, long groupId, long[] nodeIds, String keywords,
337             int start, int end)
338         throws SystemException {
339 
340         try {
341             BooleanQuery contextQuery = new BooleanQuery();
342 
343             LuceneUtil.addRequiredTerm(
344                 contextQuery, Field.PORTLET_ID, Indexer.PORTLET_ID);
345 
346             if (groupId > 0) {
347                 LuceneUtil.addRequiredTerm(
348                     contextQuery, Field.GROUP_ID, groupId);
349             }
350 
351             if ((nodeIds != null) && (nodeIds.length > 0)) {
352                 BooleanQuery nodeIdsQuery = new BooleanQuery();
353 
354                 for (long nodeId : nodeIds) {
355                     Term term = new Term(
356                         Field.ENTRY_CLASS_PK, String.valueOf(nodeId));
357                     TermQuery termQuery = new TermQuery(term);
358 
359                     nodeIdsQuery.add(termQuery, BooleanClause.Occur.SHOULD);
360                 }
361 
362                 contextQuery.add(nodeIdsQuery, BooleanClause.Occur.MUST);
363             }
364 
365             BooleanQuery searchQuery = new BooleanQuery();
366 
367             if (Validator.isNotNull(keywords)) {
368                 LuceneUtil.addTerm(searchQuery, Field.TITLE, keywords);
369                 LuceneUtil.addTerm(searchQuery, Field.CONTENT, keywords);
370                 LuceneUtil.addTerm(searchQuery, Field.TAGS_ENTRIES, keywords);
371             }
372 
373             BooleanQuery fullQuery = new BooleanQuery();
374 
375             fullQuery.add(contextQuery, BooleanClause.Occur.MUST);
376 
377             if (searchQuery.clauses().size() > 0) {
378                 fullQuery.add(searchQuery, BooleanClause.Occur.MUST);
379             }
380 
381             return SearchEngineUtil.search(
382                 companyId, fullQuery.toString(), start, end);
383         }
384         catch (Exception e) {
385             throw new SystemException(e);
386         }
387     }
388 
389     public void subscribeNode(long userId, long nodeId)
390         throws PortalException, SystemException {
391 
392         subscriptionLocalService.addSubscription(
393             userId, WikiNode.class.getName(), nodeId);
394     }
395 
396     public void unsubscribeNode(long userId, long nodeId)
397         throws PortalException, SystemException {
398 
399         subscriptionLocalService.deleteSubscription(
400             userId, WikiNode.class.getName(), nodeId);
401     }
402 
403     public WikiNode updateNode(long nodeId, String name, String description)
404         throws PortalException, SystemException {
405 
406         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
407 
408         validate(nodeId, node.getGroupId(), name);
409 
410         node.setModifiedDate(new Date());
411         node.setName(name);
412         node.setDescription(description);
413 
414         wikiNodePersistence.update(node, false);
415 
416         return node;
417     }
418 
419     protected WikiImporter getWikiImporter(String importer)
420         throws SystemException {
421 
422         WikiImporter wikiImporter = _wikiImporters.get(importer);
423 
424         if (wikiImporter == null) {
425             String importerClass = PropsUtil.get(
426                 PropsKeys.WIKI_IMPORTERS_CLASS, new Filter(importer));
427 
428             if (importerClass != null) {
429                 wikiImporter = (WikiImporter)InstancePool.get(importerClass);
430 
431                 _wikiImporters.put(importer, wikiImporter);
432             }
433 
434             if (importer == null) {
435                 throw new SystemException(
436                     "Unable to instantiate wiki importer class " +
437                         importerClass);
438             }
439         }
440 
441         return wikiImporter;
442     }
443 
444     protected void validate(long groupId, String name)
445         throws PortalException, SystemException {
446 
447         validate(0, groupId, name);
448     }
449 
450     protected void validate(long nodeId, long groupId, String name)
451         throws PortalException, SystemException {
452 
453         if (!Validator.isName(name)) {
454             throw new NodeNameException();
455         }
456 
457         WikiNode node = wikiNodePersistence.fetchByG_N(groupId, name);
458 
459         if ((node != null) && (node.getNodeId() != nodeId)) {
460             throw new DuplicateNodeNameException();
461         }
462     }
463 
464     private static Log _log = LogFactory.getLog(WikiNodeLocalServiceImpl.class);
465 
466     private Map<String, WikiImporter> _wikiImporters =
467         new HashMap<String, WikiImporter>();
468 
469 }