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.BooleanClauseOccur;
29  import com.liferay.portal.kernel.search.BooleanQuery;
30  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
31  import com.liferay.portal.kernel.search.Document;
32  import com.liferay.portal.kernel.search.Field;
33  import com.liferay.portal.kernel.search.Hits;
34  import com.liferay.portal.kernel.search.SearchEngineUtil;
35  import com.liferay.portal.kernel.search.SearchException;
36  import com.liferay.portal.kernel.search.TermQuery;
37  import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
38  import com.liferay.portal.kernel.util.GetterUtil;
39  import com.liferay.portal.kernel.util.InstancePool;
40  import com.liferay.portal.kernel.util.Validator;
41  import com.liferay.portal.model.ResourceConstants;
42  import com.liferay.portal.model.User;
43  import com.liferay.portal.util.PortalUtil;
44  import com.liferay.portal.util.PropsKeys;
45  import com.liferay.portal.util.PropsUtil;
46  import com.liferay.portlet.wiki.DuplicateNodeNameException;
47  import com.liferay.portlet.wiki.NodeNameException;
48  import com.liferay.portlet.wiki.importers.WikiImporter;
49  import com.liferay.portlet.wiki.model.WikiNode;
50  import com.liferay.portlet.wiki.model.WikiPage;
51  import com.liferay.portlet.wiki.service.base.WikiNodeLocalServiceBaseImpl;
52  import com.liferay.portlet.wiki.util.Indexer;
53  
54  import java.io.File;
55  
56  import java.util.Date;
57  import java.util.HashMap;
58  import java.util.Iterator;
59  import java.util.List;
60  import java.util.Map;
61  
62  import org.apache.commons.logging.Log;
63  import org.apache.commons.logging.LogFactory;
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 = BooleanQueryFactoryUtil.create();
342 
343             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
344 
345             if (groupId > 0) {
346                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
347             }
348 
349             if ((nodeIds != null) && (nodeIds.length > 0)) {
350                 BooleanQuery nodeIdsQuery = BooleanQueryFactoryUtil.create();
351 
352                 for (long nodeId : nodeIds) {
353                     TermQuery termQuery = TermQueryFactoryUtil.create(
354                         Field.ENTRY_CLASS_PK, nodeId);
355 
356                     nodeIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
357                 }
358 
359                 contextQuery.add(nodeIdsQuery, BooleanClauseOccur.MUST);
360             }
361 
362             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
363 
364             if (Validator.isNotNull(keywords)) {
365                 searchQuery.addTerm(Field.TITLE, keywords);
366                 searchQuery.addTerm(Field.CONTENT, keywords);
367                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords);
368             }
369 
370             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
371 
372             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
373 
374             if (searchQuery.clauses().size() > 0) {
375                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
376             }
377 
378             return SearchEngineUtil.search(companyId, fullQuery, start, end);
379         }
380         catch (Exception e) {
381             throw new SystemException(e);
382         }
383     }
384 
385     public void subscribeNode(long userId, long nodeId)
386         throws PortalException, SystemException {
387 
388         subscriptionLocalService.addSubscription(
389             userId, WikiNode.class.getName(), nodeId);
390     }
391 
392     public void unsubscribeNode(long userId, long nodeId)
393         throws PortalException, SystemException {
394 
395         subscriptionLocalService.deleteSubscription(
396             userId, WikiNode.class.getName(), nodeId);
397     }
398 
399     public WikiNode updateNode(long nodeId, String name, String description)
400         throws PortalException, SystemException {
401 
402         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
403 
404         validate(nodeId, node.getGroupId(), name);
405 
406         node.setModifiedDate(new Date());
407         node.setName(name);
408         node.setDescription(description);
409 
410         wikiNodePersistence.update(node, false);
411 
412         return node;
413     }
414 
415     protected WikiImporter getWikiImporter(String importer)
416         throws SystemException {
417 
418         WikiImporter wikiImporter = _wikiImporters.get(importer);
419 
420         if (wikiImporter == null) {
421             String importerClass = PropsUtil.get(
422                 PropsKeys.WIKI_IMPORTERS_CLASS, new Filter(importer));
423 
424             if (importerClass != null) {
425                 wikiImporter = (WikiImporter)InstancePool.get(importerClass);
426 
427                 _wikiImporters.put(importer, wikiImporter);
428             }
429 
430             if (importer == null) {
431                 throw new SystemException(
432                     "Unable to instantiate wiki importer class " +
433                         importerClass);
434             }
435         }
436 
437         return wikiImporter;
438     }
439 
440     protected void validate(long groupId, String name)
441         throws PortalException, SystemException {
442 
443         validate(0, groupId, name);
444     }
445 
446     protected void validate(long nodeId, long groupId, String name)
447         throws PortalException, SystemException {
448 
449         if (name.equalsIgnoreCase("tag")) {
450             throw new NodeNameException(name + " is reserved");
451         }
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 }