View Javadoc
1   /*
2    * Copyright (C) 2003-2010 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.wiki.service.wysiwyg;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.exoplatform.commons.utils.PageList;
21  import org.exoplatform.container.ExoContainerContext;
22  import org.exoplatform.container.PortalContainer;
23  import org.exoplatform.services.log.ExoLogger;
24  import org.exoplatform.services.log.Log;
25  import org.exoplatform.wiki.WikiException;
26  import org.exoplatform.wiki.mow.api.Page;
27  import org.exoplatform.wiki.mow.api.Wiki;
28  import org.exoplatform.wiki.mow.api.WikiType;
29  import org.exoplatform.wiki.resolver.TitleResolver;
30  import org.exoplatform.wiki.service.*;
31  import org.exoplatform.wiki.service.search.SearchResult;
32  import org.exoplatform.wiki.service.search.WikiSearchData;
33  import org.exoplatform.wiki.utils.Utils;
34  import org.xwiki.component.annotation.Component;
35  import org.xwiki.context.Execution;
36  import org.xwiki.gwt.wysiwyg.client.wiki.*;
37  import org.xwiki.gwt.wysiwyg.client.wiki.WikiService;
38  import org.xwiki.model.reference.DocumentReference;
39  
40  import javax.inject.Inject;
41  import java.util.ArrayList;
42  import java.util.Collection;
43  import java.util.List;
44  
45  @Component
46  public class DefaultWikiService implements WikiService {
47    /**
48     * Default Wiki logger to report errors correctly.
49     */
50    private static Log                     log                      = ExoLogger.getLogger("wiki:GWTWikiService");
51  
52    /** Execution context handler, needed for accessing the WikiContext. */
53    @Inject
54    private Execution                      execution;
55  
56    /**
57     * The service used to create links.
58     */
59    @Inject
60    private LinkService                    linkService;
61  
62    /**
63     * The object used to convert between client and server entity reference.
64     */
65    private final EntityReferenceConverter entityReferenceConverter = new EntityReferenceConverter();
66  
67    private WikiContext getWikiContext() {
68      return (WikiContext) execution.getContext().getProperty(WikiContext.WIKICONTEXT);
69    }
70  
71    /**
72     * {@inheritDoc}
73     *
74     * @see WikiService#isMultiWiki()
75     */
76    @Override
77    public Boolean isMultiWiki() {
78      return false;
79    }
80  
81    /**
82     * {@inheritDoc}
83     *
84     * @see WikiService#getVirtualWikiNames()
85     */
86    @Override
87    public List<String> getVirtualWikiNames() {
88      List<String> virtualWikiNamesList = new ArrayList<String>();
89      return virtualWikiNamesList;
90    }
91  
92    /**
93     * {@inheritDoc}
94     *
95     * @see WikiService#getSpaceNames(String)
96     */
97    @Override
98    public List<String> getSpaceNames(String wikiType) {
99      List<String> spaceNames = new ArrayList<>();
100     org.exoplatform.wiki.service.WikiService wikiService = ExoContainerContext.getCurrentContainer()
101             .getComponentInstanceOfType(org.exoplatform.wiki.service.WikiService.class);
102     try {
103       Collection<Wiki> wikis = wikiService.getWikisByType(wikiType);
104       for (Wiki wiki : wikis) {
105         spaceNames.add(wiki.getOwner());
106       }
107     } catch(WikiException e) {
108       log.error("Cannot get space names - Cause : " + e.getMessage(), e);
109     }
110     return spaceNames;
111   }
112 
113   /**
114    * {@inheritDoc}
115    *
116    * @see WikiService#getPageNames(String, String)
117    */
118   @Override
119   public List<String> getPageNames(String wikiName, String spaceName) {
120     org.exoplatform.wiki.service.WikiService wservice = (org.exoplatform.wiki.service.WikiService) PortalContainer.getComponent(org.exoplatform.wiki.service.WikiService.class);
121     try {
122       WikiContext wikiContext = getWikiContext();
123       WikiSearchData data = new WikiSearchData("", null, wikiContext.getType(), wikiContext.getOwner());
124       PageList<SearchResult> results = wservice.search(data);
125       List<String> pagesNames = new ArrayList<String>();
126       if(results != null) {
127         List<DocumentReference> documentReferences = prepareDocumentReferenceList(results);
128         List<WikiPage> wikiPages = getWikiPages(documentReferences);
129         for (WikiPage page : wikiPages) {
130           String pageName = page.getTitle();
131           if (!pagesNames.contains(pageName)) {
132             pagesNames.add(pageName);
133           }
134         }
135       }
136       return pagesNames;
137     } catch (Exception e) {
138       log.error("Exception happened when list pages name", e);
139       throw new RuntimeException("Failed to list Wiki pages name.", e);
140     }
141   }
142 
143   /**
144    * {@inheritDoc}
145    *
146    * @see WikiService#getRecentlyModifiedPages(String, int, int)
147    */
148   public List<WikiPage> getRecentlyModifiedPages(String wikiName, int start, int count) {
149     WikiContext wikiContext = getWikiContext();
150     org.exoplatform.wiki.service.WikiService wservice =
151         (org.exoplatform.wiki.service.WikiService) PortalContainer.getComponent(org.exoplatform.wiki.service.WikiService.class);
152 
153     // Create search condition by current user and recently
154     WikiSearchData data = new WikiSearchData(StringUtils.EMPTY, "*", wikiContext.getType(), wikiContext.getOwner());
155     // TODO add a property in the search data to get only recent pages
156     //data.addPropertyConstraint(String.format(" AND (  ( exo:lastModifier='%s' ) )",
157     //                           ConversationState.getCurrent().getIdentity().getUserId()));
158     data.setSort("exo:lastModifiedDate");
159     data.setOrder("DESC");
160     data.setLimit(count);
161 
162     // Call wiki service to execute search
163     try {
164       PageList<SearchResult> results = wservice.search(data);
165       List<DocumentReference> documentReferences = prepareDocumentReferenceList(results);
166       return getWikiPages(documentReferences);
167     } catch (Exception e) {
168       log.error("Exception happened when searching pages", e);
169       throw new RuntimeException("Failed to search Wiki pages.", e);
170     }
171   }
172 
173   /**
174    * {@inheritDoc}
175    *
176    * @see WikiService#getMatchingPages(String, String, int, int)
177    */
178   public List<WikiPage> getMatchingPages(String wikiName, String keyword, int start, int count) {
179     String quote = "'";
180     String doubleQuote = "''";
181     String escapedKeyword = keyword.replaceAll(quote, doubleQuote).toLowerCase();
182     org.exoplatform.wiki.service.WikiService wservice = (org.exoplatform.wiki.service.WikiService) PortalContainer.getComponent(org.exoplatform.wiki.service.WikiService.class);
183 
184     try {
185       WikiContext wikiContext = getWikiContext();
186       WikiSearchData data = new WikiSearchData(escapedKeyword, escapedKeyword, wikiContext.getType(), wikiContext.getOwner());
187       PageList<SearchResult> results = wservice.search(data);
188       List<DocumentReference> documentReferences = prepareDocumentReferenceList(results);
189       return getWikiPages(documentReferences);
190     } catch (Exception e) {
191       log.error("Exception happened when searching pages", e);
192       throw new RuntimeException("Failed to search Wiki pages.", e);
193     }
194   }
195 
196   /**
197    * Helper function to create a list of {@link WikiPage}s from a list of
198    * document references.
199    *
200    * @param documentReferences a list of document references
201    * @return the list of {@link WikiPage}s corresponding to the given document
202    *         references
203    * @throws Exception if anything goes wrong while creating the list of
204    *           {@link WikiPage}s
205    */
206   private List<WikiPage> getWikiPages(List<DocumentReference> documentReferences) throws Exception {
207     org.exoplatform.wiki.service.WikiService wservice = (org.exoplatform.wiki.service.WikiService) PortalContainer.getComponent(org.exoplatform.wiki.service.WikiService.class);
208     List<WikiPage> wikiPages = new ArrayList<>();
209     for (DocumentReference documentReference : documentReferences) {
210       WikiPage wikiPage = new WikiPage();
211       wikiPage.setReference(entityReferenceConverter.convert(documentReference).getEntityReference());
212       String pageId = documentReference.getName();
213       String wikiOwner = documentReference.getParent().getName();
214       String wikiType = documentReference.getParent().getParent().getName();
215       Page page = wservice.getPageByRootPermission(wikiType, wikiOwner, pageId);
216       wikiPage.setTitle(page.getTitle());
217       wikiPage.setUrl(pageId);
218       wikiPages.add(wikiPage);
219     }
220     return wikiPages;
221   }
222 
223   /**
224    * {@inheritDoc}
225    *
226    * @see WikiService#getEntityConfig(org.xwiki.gwt.wysiwyg.client.wiki.EntityReference,
227    *      ResourceReference)
228    */
229   public EntityConfig getEntityConfig(org.xwiki.gwt.wysiwyg.client.wiki.EntityReference origin, ResourceReference destination) {
230     return linkService.getEntityConfig(origin, destination);
231   }
232 
233   /**
234    * {@inheritDoc}
235    *
236    * @see WikiService#getAttachment(AttachmentReference)
237    */
238   @Override
239   public Attachment getAttachment(AttachmentReference attachmentReference) {
240     // Clean attachment filename to be synchronized with all attachment operations.
241     String cleanedFileName = attachmentReference.getFileName();
242     cleanedFileName = Utils.escapeIllegalCharacterInName(cleanedFileName);
243     attachmentReference.setFileName(cleanedFileName);
244     WikiPageReference pageReference = attachmentReference.getWikiPageReference();
245     org.exoplatform.wiki.service.WikiService wservice = (org.exoplatform.wiki.service.WikiService) PortalContainer.getComponent(org.exoplatform.wiki.service.WikiService.class);
246     Page page;
247     try {
248       cleanedFileName = TitleResolver.getId(cleanedFileName, false);
249       page = wservice.getExsitedOrNewDraftPageById(pageReference.getWikiName(), pageReference.getSpaceName(), pageReference.getPageName());
250       if (page == null) {
251         return null;
252       }
253 
254       org.exoplatform.wiki.mow.api.Attachment attachment = wservice.getAttachmentOfPageByName(cleanedFileName, page);
255       if (attachment == null) {
256         log.warn(String.format("Failed to get attachment: %s not found.", cleanedFileName));
257         return null;
258       }
259 
260       Attachment attach = new Attachment();
261       attach.setReference(attachmentReference.getEntityReference());
262       attach.setUrl(attachment.getDownloadURL());
263       return attach;
264     } catch (Exception e) {
265       log.error("Failed to get attachment: there was a problem with getting the document on the server.", e);
266       return null;
267     }
268   }
269 
270   /**
271    * {@inheritDoc}
272    *
273    * @see WikiService#getImageAttachments(WikiPageReference)
274    */
275   public List<Attachment> getImageAttachments(WikiPageReference reference) {
276     List<Attachment> imageAttachments = new ArrayList<Attachment>();
277     List<Attachment> allAttachments = getAttachments(reference);
278     for (Attachment attachment : allAttachments) {
279       if (attachment.getMimeType().startsWith("image/")) {
280         imageAttachments.add(attachment);
281       }
282     }
283     return imageAttachments;
284   }
285 
286   /**
287    * {@inheritDoc}
288    *
289    * @see WikiService#getAttachments(WikiPageReference)
290    */
291   @Override
292   public List<Attachment> getAttachments(WikiPageReference documentReference) {
293     try {
294       String wikiName = documentReference.getWikiName();
295       String spaceName = documentReference.getSpaceName();
296       String pageName = documentReference.getPageName();
297       if (log.isTraceEnabled()) {
298         log.trace("Getting attachments of page : " + wikiName + "." + spaceName + "." + pageName);
299       }
300       List<Attachment> attachments = new ArrayList<Attachment>();
301       org.exoplatform.wiki.service.WikiService wservice = (org.exoplatform.wiki.service.WikiService) PortalContainer.getComponent(org.exoplatform.wiki.service.WikiService.class);
302       Page page = wservice.getExsitedOrNewDraftPageById(wikiName, spaceName, TitleResolver.getId(pageName, false));
303       List<org.exoplatform.wiki.mow.api.Attachment> attachs = wservice.getAttachmentsOfPage(page);
304       for (org.exoplatform.wiki.mow.api.Attachment attach : attachs) {
305         AttachmentReference attachmentReference = new AttachmentReference(attach.getName(), documentReference);
306         EntityReference entityReference = attachmentReference.getEntityReference();
307         entityReference.setType(org.xwiki.gwt.wysiwyg.client.wiki.EntityReference.EntityType.ATTACHMENT);
308         Attachment currentAttach = new Attachment();
309         currentAttach.setUrl(attach.getDownloadURL());
310         currentAttach.setReference(entityReference);
311         currentAttach.setMimeType(attach.getMimeType());
312         attachments.add(currentAttach);
313       }
314       return attachments;
315     } catch (Exception e) {
316       throw new RuntimeException("Failed to retrieve the list of attachments.", e);
317     }
318   }
319 
320   /**
321    * {@inheritDoc}
322    *
323    * @see WikiService#getUploadURL(org.xwiki.gwt.wysiwyg.client.wiki.WikiPageReference)
324    */
325   @Override
326   public String getUploadURL(WikiPageReference documentReference) {
327     StringBuilder sb = new StringBuilder();
328     sb.append("/").append(PortalContainer.getCurrentPortalContainerName()).append("/");
329     sb.append(PortalContainer.getCurrentRestContextName()).append("/wiki/upload/");
330     sb.append(documentReference.getWikiName()).append("/").append(documentReference.getSpaceName());
331     sb.append("/").append(documentReference.getPageName()).append("/");
332     return sb.toString();
333   }
334 
335   /**
336    * {@inheritDoc}
337    *
338    * @see WikiService#parseLinkReference(String,
339    *      org.xwiki.gwt.wysiwyg.client.wiki.EntityReference)
340    */
341   public ResourceReference parseLinkReference(String linkReference, org.xwiki.gwt.wysiwyg.client.wiki.EntityReference baseReference) {
342     return linkService.parseLinkReference(linkReference, baseReference);
343   }
344 
345   /**
346    * Helper function to prepare a list of {@link WikiPage} (with full name,
347    * title, etc) from a list of search results.
348    *
349    * @param results the list of the search results
350    * @return the list of {@link WikiPage}s corresponding to the passed names
351    * @throws Exception if anything goes wrong retrieving the documents
352    */
353   private List<DocumentReference> prepareDocumentReferenceList(PageList<SearchResult> results) throws Exception {
354     List<DocumentReference> documentReferences = new ArrayList<DocumentReference>();
355     for (SearchResult result : results.getAll()) {
356       String nodeName = result.getPageName();
357       if (nodeName != null && nodeName.length() > 0 && nodeName.startsWith("/")) {
358         nodeName = nodeName.substring(1);
359       }
360       WikiContext wikiContext = getWikiContext();
361       log.info("Prepair DocumentReference : " + wikiContext.getType() + "@" + wikiContext.getOwner() + "@" + nodeName);
362       documentReferences.add(new DocumentReference(wikiContext.getType(), wikiContext.getOwner(), nodeName));
363     }
364     return documentReferences;
365   }
366 }