1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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.PropsKeys;
42  import com.liferay.portal.kernel.util.Validator;
43  import com.liferay.portal.model.Group;
44  import com.liferay.portal.model.ResourceConstants;
45  import com.liferay.portal.model.User;
46  import com.liferay.portal.service.ServiceContext;
47  import com.liferay.portal.util.PropsUtil;
48  import com.liferay.portlet.wiki.DuplicateNodeNameException;
49  import com.liferay.portlet.wiki.NodeNameException;
50  import com.liferay.portlet.wiki.importers.WikiImporter;
51  import com.liferay.portlet.wiki.model.WikiNode;
52  import com.liferay.portlet.wiki.model.WikiPage;
53  import com.liferay.portlet.wiki.service.base.WikiNodeLocalServiceBaseImpl;
54  import com.liferay.portlet.wiki.util.Indexer;
55  
56  import java.io.File;
57  
58  import java.util.Date;
59  import java.util.HashMap;
60  import java.util.Iterator;
61  import java.util.List;
62  import java.util.Map;
63  
64  /**
65   * <a href="WikiNodeLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
66   *
67   * @author Brian Wing Shun Chan
68   * @author Charles May
69   * @author Raymond Augé
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         try {
109             wikiNodePersistence.update(node, false);
110         }
111         catch (SystemException se) {
112             if (_log.isWarnEnabled()) {
113                 _log.warn(
114                     "Add failed, fetch {groupId=" + groupId + ", name=" +
115                         name + "}");
116             }
117 
118             node = wikiNodePersistence.fetchByG_N(groupId, name, false);
119 
120             if (node == null) {
121                 throw se;
122             }
123 
124             return node;
125         }
126 
127         // Resources
128 
129         if (serviceContext.getAddCommunityPermissions() ||
130             serviceContext.getAddGuestPermissions()) {
131 
132             addNodeResources(
133                 node, serviceContext.getAddCommunityPermissions(),
134                 serviceContext.getAddGuestPermissions());
135         }
136         else {
137             addNodeResources(
138                 node, serviceContext.getCommunityPermissions(),
139                 serviceContext.getGuestPermissions());
140         }
141 
142         return node;
143     }
144 
145     public void addNodeResources(
146             long nodeId, boolean addCommunityPermissions,
147             boolean addGuestPermissions)
148         throws PortalException, SystemException {
149 
150         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
151 
152         addNodeResources(node, addCommunityPermissions, addGuestPermissions);
153     }
154 
155     public void addNodeResources(
156             WikiNode node, boolean addCommunityPermissions,
157             boolean addGuestPermissions)
158         throws PortalException, SystemException {
159 
160         resourceLocalService.addResources(
161             node.getCompanyId(), node.getGroupId(), node.getUserId(),
162             WikiNode.class.getName(), node.getNodeId(), false,
163             addCommunityPermissions, addGuestPermissions);
164     }
165 
166     public void addNodeResources(
167             long nodeId, String[] communityPermissions,
168             String[] guestPermissions)
169         throws PortalException, SystemException {
170 
171         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
172 
173         addNodeResources(node, communityPermissions, guestPermissions);
174     }
175 
176     public void addNodeResources(
177             WikiNode node, String[] communityPermissions,
178             String[] guestPermissions)
179         throws PortalException, SystemException {
180 
181         resourceLocalService.addModelResources(
182             node.getCompanyId(), node.getGroupId(), node.getUserId(),
183             WikiNode.class.getName(), node.getNodeId(), communityPermissions,
184             guestPermissions);
185     }
186 
187     public void deleteNode(long nodeId)
188         throws PortalException, SystemException {
189 
190         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
191 
192         deleteNode(node);
193     }
194 
195     public void deleteNode(WikiNode node)
196         throws PortalException, SystemException {
197 
198         // Indexer
199 
200         try {
201             Indexer.deletePages(node.getCompanyId(), node.getNodeId());
202         }
203         catch (SearchException se) {
204             _log.error("Deleting index " + node.getNodeId(), se);
205         }
206 
207         // Subscriptions
208 
209         subscriptionLocalService.deleteSubscriptions(
210             node.getCompanyId(), WikiNode.class.getName(), node.getNodeId());
211 
212         // Pages
213 
214         wikiPageLocalService.deletePages(node.getNodeId());
215 
216         // Resources
217 
218         resourceLocalService.deleteResource(
219             node.getCompanyId(), WikiNode.class.getName(),
220             ResourceConstants.SCOPE_INDIVIDUAL, node.getNodeId());
221 
222         // Node
223 
224         wikiNodePersistence.remove(node);
225     }
226 
227     public void deleteNodes(long groupId)
228         throws PortalException, SystemException {
229 
230         Iterator<WikiNode> itr = wikiNodePersistence.findByGroupId(
231             groupId).iterator();
232 
233         while (itr.hasNext()) {
234             WikiNode node = itr.next();
235 
236             deleteNode(node);
237         }
238     }
239 
240     public WikiNode getNode(long nodeId)
241         throws PortalException, SystemException {
242 
243         return wikiNodePersistence.findByPrimaryKey(nodeId);
244     }
245 
246     public WikiNode getNode(long groupId, String nodeName)
247         throws PortalException, SystemException {
248 
249         return wikiNodePersistence.findByG_N(groupId, nodeName);
250     }
251 
252     public List<WikiNode> getNodes(long groupId) throws SystemException {
253         return wikiNodePersistence.findByGroupId(groupId);
254     }
255 
256     public List<WikiNode> getNodes(long groupId, int start, int end)
257         throws SystemException {
258 
259         return wikiNodePersistence.findByGroupId(groupId, start, end);
260     }
261 
262     public int getNodesCount(long groupId) throws SystemException {
263         return wikiNodePersistence.countByGroupId(groupId);
264     }
265 
266     public void importPages(
267             long userId, long nodeId, String importer, File[] files,
268             Map<String, String[]> options)
269         throws PortalException, SystemException {
270 
271         WikiNode node = getNode(nodeId);
272 
273         getWikiImporter(importer).importPages(userId, node, files, options);
274     }
275 
276     public void reIndex(String[] ids) throws SystemException {
277         if (SearchEngineUtil.isIndexReadOnly()) {
278             return;
279         }
280 
281         long companyId = GetterUtil.getLong(ids[0]);
282 
283         try {
284             reIndexNodes(companyId);
285         }
286         catch (SystemException se) {
287             throw se;
288         }
289         catch (Exception e) {
290             throw new SystemException(e);
291         }
292     }
293 
294     public Hits search(
295             long companyId, long groupId, long userId, long[] nodeIds,
296             String keywords, int start, int end)
297         throws SystemException {
298 
299         try {
300             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
301 
302             contextQuery.addRequiredTerm(Field.PORTLET_ID, Indexer.PORTLET_ID);
303 
304             if (groupId > 0) {
305                 Group group = groupLocalService.getGroup(groupId);
306 
307                 if (group.isLayout()) {
308                     contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
309 
310                     groupId = group.getParentGroupId();
311                 }
312 
313                 contextQuery.addRequiredTerm(Field.GROUP_ID, groupId);
314             }
315 
316             if ((nodeIds != null) && (nodeIds.length > 0)) {
317                 BooleanQuery nodeIdsQuery = BooleanQueryFactoryUtil.create();
318 
319                 for (long nodeId : nodeIds) {
320                     if (userId > 0) {
321                         try {
322                             wikiNodeService.getNode(nodeId);
323                         }
324                         catch (Exception e) {
325                             continue;
326                         }
327                     }
328 
329                     TermQuery termQuery = TermQueryFactoryUtil.create(
330                         "nodeId", nodeId);
331 
332                     nodeIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
333                 }
334 
335                 contextQuery.add(nodeIdsQuery, BooleanClauseOccur.MUST);
336             }
337 
338             BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
339 
340             if (Validator.isNotNull(keywords)) {
341                 searchQuery.addTerm(Field.TITLE, keywords);
342                 searchQuery.addTerm(Field.CONTENT, keywords);
343                 searchQuery.addTerm(Field.TAGS_ENTRIES, keywords, true);
344             }
345 
346             BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
347 
348             fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
349 
350             if (searchQuery.clauses().size() > 0) {
351                 fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
352             }
353 
354             return SearchEngineUtil.search(
355                 companyId, groupId, userId, WikiPage.class.getName(), fullQuery,
356                 start, end);
357         }
358         catch (Exception e) {
359             throw new SystemException(e);
360         }
361     }
362 
363     public void subscribeNode(long userId, long nodeId)
364         throws PortalException, SystemException {
365 
366         subscriptionLocalService.addSubscription(
367             userId, WikiNode.class.getName(), nodeId);
368     }
369 
370     public void unsubscribeNode(long userId, long nodeId)
371         throws PortalException, SystemException {
372 
373         subscriptionLocalService.deleteSubscription(
374             userId, WikiNode.class.getName(), nodeId);
375     }
376 
377     public WikiNode updateNode(long nodeId, String name, String description)
378         throws PortalException, SystemException {
379 
380         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
381 
382         validate(nodeId, node.getGroupId(), name);
383 
384         node.setModifiedDate(new Date());
385         node.setName(name);
386         node.setDescription(description);
387 
388         wikiNodePersistence.update(node, false);
389 
390         return node;
391     }
392 
393     protected WikiImporter getWikiImporter(String importer)
394         throws SystemException {
395 
396         WikiImporter wikiImporter = _wikiImporters.get(importer);
397 
398         if (wikiImporter == null) {
399             String importerClass = PropsUtil.get(
400                 PropsKeys.WIKI_IMPORTERS_CLASS, new Filter(importer));
401 
402             if (importerClass != null) {
403                 wikiImporter = (WikiImporter)InstancePool.get(importerClass);
404 
405                 _wikiImporters.put(importer, wikiImporter);
406             }
407 
408             if (importer == null) {
409                 throw new SystemException(
410                     "Unable to instantiate wiki importer class " +
411                         importerClass);
412             }
413         }
414 
415         return wikiImporter;
416     }
417 
418     protected void reIndexNodes(long companyId) throws SystemException {
419         int nodeCount = wikiNodePersistence.countByCompanyId(companyId);
420 
421         int nodePages = nodeCount / Indexer.DEFAULT_INTERVAL;
422 
423         for (int i = 0; i <= nodePages; i++) {
424             int nodeStart = (i * Indexer.DEFAULT_INTERVAL);
425             int nodeEnd = nodeStart + Indexer.DEFAULT_INTERVAL;
426 
427             reIndexNodes(companyId, nodeStart, nodeEnd);
428         }
429     }
430 
431     protected void reIndexNodes(long companyId, int nodeStart, int nodeEnd)
432         throws SystemException {
433 
434         List<WikiNode> nodes = wikiNodePersistence.findByCompanyId(
435             companyId, nodeStart, nodeEnd);
436 
437         for (WikiNode node : nodes) {
438             long nodeId = node.getNodeId();
439 
440             int pageCount = wikiPagePersistence.countByN_H(nodeId, true);
441 
442             int pagePages = pageCount / Indexer.DEFAULT_INTERVAL;
443 
444             for (int i = 0; i <= pagePages; i++) {
445                 int pageStart = (i * Indexer.DEFAULT_INTERVAL);
446                 int pageEnd = pageStart + Indexer.DEFAULT_INTERVAL;
447 
448                 reIndexPages(nodeId, pageStart, pageEnd);
449             }
450         }
451     }
452 
453     protected void reIndexPages(long nodeId, int pageStart, int pageEnd)
454         throws SystemException {
455 
456         List<WikiPage> pages = wikiPagePersistence.findByN_H(
457             nodeId, true, pageStart, pageEnd);
458 
459         for (WikiPage page : pages) {
460             wikiPageLocalService.reIndex(page);
461         }
462     }
463 
464     protected void validate(long groupId, String name)
465         throws PortalException, SystemException {
466 
467         validate(0, groupId, name);
468     }
469 
470     protected void validate(long nodeId, long groupId, String name)
471         throws PortalException, SystemException {
472 
473         if (name.equalsIgnoreCase("tag")) {
474             throw new NodeNameException(name + " is reserved");
475         }
476 
477         if (!Validator.isName(name)) {
478             throw new NodeNameException();
479         }
480 
481         WikiNode node = wikiNodePersistence.fetchByG_N(groupId, name);
482 
483         if ((node != null) && (node.getNodeId() != nodeId)) {
484             throw new DuplicateNodeNameException();
485         }
486     }
487 
488     private static Log _log =
489         LogFactoryUtil.getLog(WikiNodeLocalServiceImpl.class);
490 
491     private Map<String, WikiImporter> _wikiImporters =
492         new HashMap<String, WikiImporter>();
493 
494 }