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