View Javadoc
1   package org.exoplatform.wiki.service.impl;
2   
3   import org.apache.commons.collections.CollectionUtils;
4   import org.apache.commons.lang.StringUtils;
5   import org.chromattic.api.ChromatticSession;
6   import org.chromattic.common.IO;
7   import org.chromattic.core.api.ChromatticSessionImpl;
8   import org.chromattic.ext.ntdef.Resource;
9   import org.exoplatform.commons.utils.ObjectPageList;
10  import org.exoplatform.commons.utils.PageList;
11  import org.exoplatform.container.configuration.ConfigurationManager;
12  import org.exoplatform.container.xml.ValuesParam;
13  import org.exoplatform.portal.config.model.PortalConfig;
14  import org.exoplatform.services.jcr.access.AccessControlEntry;
15  import org.exoplatform.services.jcr.access.AccessControlList;
16  import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
17  import org.exoplatform.services.jcr.impl.core.query.QueryImpl;
18  import org.exoplatform.services.jcr.util.Text;
19  import org.exoplatform.services.log.ExoLogger;
20  import org.exoplatform.services.log.Log;
21  import org.exoplatform.services.security.Identity;
22  import org.exoplatform.services.security.IdentityConstants;
23  import org.exoplatform.wiki.WikiException;
24  import org.exoplatform.wiki.chromattic.ext.ntdef.NTVersion;
25  import org.exoplatform.wiki.chromattic.ext.ntdef.VersionableMixin;
26  import org.exoplatform.wiki.mow.api.*;
27  import org.exoplatform.wiki.mow.core.api.MOWService;
28  import org.exoplatform.wiki.mow.core.api.WikiStoreImpl;
29  import org.exoplatform.wiki.mow.core.api.wiki.*;
30  import org.exoplatform.wiki.resolver.TitleResolver;
31  import org.exoplatform.wiki.service.DataStorage;
32  import org.exoplatform.wiki.service.WikiPageParams;
33  import org.exoplatform.wiki.service.search.*;
34  import org.exoplatform.wiki.service.search.jcr.JCRTemplateSearchQueryBuilder;
35  import org.exoplatform.wiki.service.search.jcr.JCRWikiSearchQueryBuilder;
36  import org.exoplatform.wiki.utils.JCRUtils;
37  import org.exoplatform.wiki.utils.Utils;
38  import org.exoplatform.wiki.utils.VersionNameComparatorDesc;
39  import org.exoplatform.wiki.utils.WikiConstants;
40  
41  import javax.jcr.*;
42  import javax.jcr.query.Query;
43  import javax.jcr.query.QueryResult;
44  import javax.jcr.query.Row;
45  import javax.jcr.query.RowIterator;
46  import java.io.*;
47  import java.net.URLConnection;
48  import java.util.*;
49  
50  public class JCRDataStorage implements DataStorage {
51    private static final Log log = ExoLogger.getLogger(JCRDataStorage.class);
52  
53    private static final int MAX_EXCERPT_LENGTH = 430;
54  
55    private static final int CIRCULAR_RENAME_FLAG = 1000;
56  
57    private MOWService mowService;
58  
59    /**
60     * Constructor
61     * Inject NodeHierarchyCreator to be sure JCRDataStorage is loaded after NodeHierarchyCreator,
62     * so JCR wiki root folders are created before wiki data initialization
63     * @param mowService
64     * @param nodeHierarchyCreator
65     */
66    public JCRDataStorage(MOWService mowService, NodeHierarchyCreator nodeHierarchyCreator) {
67      this.mowService = mowService;
68    }
69  
70    @Override
71    public Wiki getWikiByTypeAndOwner(String wikiType, String wikiOwner) throws WikiException {
72      WikiImpl wikiImpl = fetchWikiImpl(wikiType, wikiOwner);
73      return convertWikiImplToWiki(wikiImpl);
74    }
75  
76    @Override
77    public List<Wiki> getWikisByType(String wikiType) throws WikiException {
78      boolean created = mowService.startSynchronization();
79  
80      List wikis = new ArrayList();
81  
82      try {
83        WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
84        if (wStore != null) {
85          WikiContainer<WikiImpl> wikiContainer = wStore.getWikiContainer(WikiType.valueOf(wikiType.toUpperCase()));
86          if (wikiContainer != null) {
87            Collection<WikiImpl> allWikis = wikiContainer.getAllWikis();
88  
89            if (allWikis != null) {
90              for (WikiImpl wikiImpl : allWikis) {
91                wikis.add(convertWikiImplToWiki(wikiImpl));
92              }
93            }
94          }
95        }
96      } finally {
97        mowService.stopSynchronization(created);
98      }
99  
100     return wikis;
101   }
102 
103   @Override
104   public Wiki createWiki(Wiki wiki) throws WikiException {
105     boolean created = mowService.startSynchronization();
106 
107     try {
108       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
109 
110       WikiContainer wikiContainer = wStore.getWikiContainer(WikiType.valueOf(wiki.getType().toUpperCase()));
111       WikiImpl wikiImpl = wikiContainer.addWiki(wiki);
112       // create wiki home page
113       wikiImpl.getWikiHome();
114 
115       mowService.persist();
116 
117       Wiki createdWiki = convertWikiImplToWiki(wikiImpl);
118       return createdWiki;
119     } finally {
120       mowService.stopSynchronization(created);
121     }
122   }
123 
124   /**
125    * Create a wiki page with the given pageId, under the node of the parentPage node.
126    * @param wiki
127    * @param parentPage
128    * @param page
129    * @return
130    * @throws WikiException
131    */
132   @Override
133   public Page createPage(Wiki wiki, Page parentPage, Page page) throws WikiException {
134     if (parentPage == null) {
135       throw new IllegalArgumentException("Parent page cannot be null when creating the new page " + wiki.getType() + ":" + wiki.getOwner() + ":" + page.getName());
136     }
137 
138     boolean created = mowService.startSynchronization();
139 
140     try {
141       WikiImpl wikiImpl = fetchWikiImpl(wiki.getType(), wiki.getOwner());
142       PageImpl parentPageImpl = fetchPageImpl(parentPage);
143       PageImpl pageImpl = wikiImpl.createWikiPage();
144       pageImpl.setName(page.getName());
145       parentPageImpl.addWikiPage(pageImpl);
146       pageImpl.setOwner(page.getOwner());
147       pageImpl.setPermission(JCRUtils.convertToPermissionMap(page.getPermissions()));
148       pageImpl.setTitle(page.getTitle());
149       String text = "";
150       if(page.getContent() != null) {
151         text = page.getContent();
152       }
153       Date now = GregorianCalendar.getInstance().getTime();
154       pageImpl.setCreatedDate(now);
155       pageImpl.setUpdatedDate(now);
156       pageImpl.setAuthor(page.getAuthor());
157       pageImpl.getContent().setText(text);
158       pageImpl.setSyntax(page.getSyntax());
159       pageImpl.setURL(page.getUrl());
160 
161       if(page.getActivityId() != null) {
162         pageImpl.setActivityId(page.getActivityId());
163       }
164 
165       try {
166         // create a first version
167         pageImpl.makeVersionable();
168         pageImpl.checkin();
169         pageImpl.checkout();
170       } catch (Exception e) {
171         log.error("Cannot create first version of page " + wiki.getType() + ":" + wiki.getOwner() + ":" + page.getName()
172                 + " - Cause : " + e.getMessage(), e);
173       }
174 
175       //update LinkRegistry
176       LinkRegistry linkRegistry = wikiImpl.getLinkRegistry();
177       String newEntryName = getLinkEntryName(wiki.getType(), wiki.getOwner(), page.getName());
178       String newEntryAlias = getLinkEntryAlias(wiki.getType(), wiki.getOwner(), page.getName());
179       LinkEntry newEntry = linkRegistry.getLinkEntries().get(newEntryName);
180       if (newEntry == null) {
181         newEntry = linkRegistry.createLinkEntry();
182         linkRegistry.getLinkEntries().put(newEntryName, newEntry);
183         newEntry.setAlias(newEntryAlias);
184         newEntry.setTitle(page.getTitle());
185       }
186       //This line must be outside if statement to break chaining list when add new page with name that was used in list.
187       newEntry.setNewLink(newEntry);
188 
189       mowService.persist();
190 
191       Page createdPage = convertPageImplToPage(pageImpl);
192       return createdPage;
193     } finally {
194       mowService.stopSynchronization(created);
195     }
196   }
197 
198   @Override
199   public Page getPageOfWikiByName(String wikiType, String wikiOwner, String pageName) throws WikiException {
200     PageImpl pageImpl = null;
201 
202     boolean created = mowService.startSynchronization();
203 
204     try {
205       WikiImpl wiki = fetchWikiImpl(wikiType, wikiOwner);
206 
207       if(wiki != null) {
208         if (WikiConstants.WIKI_HOME_NAME.equals(pageName) || pageName == null) {
209           pageImpl = wiki.getWikiHome();
210         } else {
211           Page page = new Page(pageName);
212           page.setWikiType(wikiType);
213           page.setWikiOwner(wikiOwner);
214           pageImpl = fetchPageImpl(page);
215           if (pageImpl == null && (pageImpl = wiki.getWikiHome()) != null) {
216             String wikiHomeId = TitleResolver.getId(pageImpl.getTitle(), true);
217             if (!wikiHomeId.equals(pageName)) {
218               pageImpl = null;
219             }
220           }
221         }
222       }
223 
224       Page page = null;
225       if(pageImpl != null) {
226         try {
227           pageImpl.migrateLegacyData();
228           pageImpl.migrateAttachmentPermission();
229         } catch(WikiException | RepositoryException e) {
230           log.error("Cannot migrate page " + wikiType + ":" + wikiOwner + ":"
231                   + pageName + " - Cause : " + e.getMessage(), e);
232         }
233         page = convertPageImplToPage(pageImpl);
234         page.setWikiId(wiki.getName());
235         page.setWikiType(wiki.getType());
236         page.setWikiOwner(wiki.getOwner());
237       }
238       return page;
239     } finally {
240       mowService.stopSynchronization(created);
241     }
242   }
243 
244   @Override
245   public Page getPageById(String id) throws WikiException {
246     boolean created = mowService.startSynchronization();
247 
248     ChromatticSession session = mowService.getSession();
249 
250     try {
251       Page page = convertPageImplToPage(session.findById(PageImpl.class, id));
252       return page;
253     } finally {
254       mowService.stopSynchronization(created);
255     }
256   }
257 
258   @Override
259   public DraftPage getDraftPageById(String id) throws WikiException {
260     boolean created = mowService.startSynchronization();
261 
262     ChromatticSession session = mowService.getSession();
263 
264     try {
265       DraftPage draftPage = convertDraftPageImplToDraftPage(session.findById(DraftPageImpl.class, id));
266       return draftPage;
267     } finally {
268       mowService.stopSynchronization(created);
269     }
270   }
271 
272   @Override
273   public Page getParentPageOf(Page page) throws WikiException {
274     boolean created = mowService.startSynchronization();
275 
276     try {
277       PageImpl pageImpl = fetchPageImpl(page);
278       PageImpl parentPageImpl = pageImpl.getParentPage();
279 
280       Page parentPage = convertPageImplToPage(parentPageImpl);
281       if(parentPage != null) {
282         parentPage.setWikiId(page.getWikiId());
283         parentPage.setWikiType(page.getWikiType());
284         parentPage.setWikiOwner(page.getWikiOwner());
285       }
286 
287       return parentPage;
288     } finally {
289       mowService.stopSynchronization(created);
290     }
291   }
292 
293   @Override
294   public List<Page> getChildrenPageOf(Page page) throws WikiException {
295     List<Page> childrenPages = new ArrayList<>();
296 
297     boolean created = mowService.startSynchronization();
298 
299     try {
300       PageImpl pageImpl = fetchPageImpl(page);
301       if(pageImpl == null) {
302         throw new WikiException("Page " + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName() + " does not exist, cannot get its children.");
303       }
304 
305       try {
306         Map<String, PageImpl> childrenPageImpls = pageImpl.getChildPages();
307         for (PageImpl childPageImpl : childrenPageImpls.values()) {
308           Page childPage = convertPageImplToPage(childPageImpl);
309           childPage.setWikiType(page.getWikiType());
310           childPage.setWikiOwner(page.getWikiOwner());
311           childrenPages.add(childPage);
312         }
313       } catch(Exception e) {
314         log.error("Cannot get children pages of page " + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName()
315                 + " - Cause : " + e.getMessage(), e);
316       }
317 
318       return childrenPages;
319     } finally {
320       mowService.stopSynchronization(created);
321     }
322   }
323 
324   @Override
325   public void createTemplatePage(Wiki wiki, Template template) throws WikiException {
326     boolean created = mowService.startSynchronization();
327 
328     try {
329       TemplateContainer templatesContainer = getTemplatesContainer(wiki.getType(), wiki.getOwner());
330 
331       TemplateImpl templatePage = templatesContainer.createTemplatePage();
332       templatePage = templatesContainer.addPage(template.getName(), templatePage);
333 
334       templatePage.setTitle(template.getTitle());
335       templatePage.setDescription(template.getDescription());
336       templatePage.getContent().setText(template.getContent());
337     } finally {
338       mowService.stopSynchronization(created);
339     }
340   }
341 
342   @Override
343   public void updateTemplatePage(Template template) throws WikiException {
344     boolean created = mowService.startSynchronization();
345 
346     try {
347       TemplateContainer templatesContainer = getTemplatesContainer(template.getWikiType(), template.getWikiOwner());
348       TemplateImpl templateImpl = templatesContainer.getTemplate(template.getName());
349 
350       templateImpl.setTitle(template.getTitle());
351       templateImpl.setDescription(template.getDescription());
352       templateImpl.getContent().setText(template.getContent());
353       templateImpl.setSyntax(template.getSyntax());
354 
355       mowService.persist();
356     } finally {
357       mowService.stopSynchronization(created);
358     }
359   }
360 
361   @Override
362   public void deleteTemplatePage(String wikiType, String wikiOwner, String templateName) throws WikiException {
363     boolean created = mowService.startSynchronization();
364 
365     try {
366       TemplateContainer templatesContainer = getTemplatesContainer(wikiType, wikiOwner);
367       TemplateImpl templateImpl = templatesContainer.getTemplate(templateName);
368       templateImpl.remove();
369       mowService.persist();
370     } finally {
371       mowService.stopSynchronization(created);
372     }
373   }
374 
375   @Override
376   public void deletePage(String wikiType, String wikiOwner, String pageId) throws WikiException {
377     boolean created = mowService.startSynchronization();
378 
379     try {
380       Page page = new Page(pageId);
381       page.setWikiType(wikiType);
382       page.setWikiOwner(wikiOwner);
383       PageImpl pageImpl = fetchPageImpl(page);
384       if(pageImpl == null) {
385         throw new WikiException("Page " + wikiType + ":" + wikiOwner + ":" + pageId + " does not exist, cannot delete it.");
386       }
387 
388       ChromatticSession session = mowService.getSession();
389       RemovedMixin mix = session.create(RemovedMixin.class);
390       session.setEmbedded(pageImpl, RemovedMixin.class, mix);
391       mix.setRemovedBy(Utils.getCurrentUser());
392       Calendar calendar = GregorianCalendar.getInstance();
393       calendar.setTimeInMillis(new Date().getTime());
394       mix.setRemovedDate(calendar.getTime());
395       mix.setParentPath(pageImpl.getParentPage().getPath());
396       WikiImpl wiki = fetchWikiImpl(wikiType, wikiOwner);
397       Trash trash = wiki.getTrash();
398       if (trash.isHasPage(pageImpl.getName())) {
399         PageImpl oldDeleted = trash.getPage(pageImpl.getName());
400         String removedDate = oldDeleted.getRemovedMixin().getRemovedDate().toGMTString();
401         String newName = pageImpl.getName() + "_" + removedDate.replaceAll(" ", "-").replaceAll(":", "-");
402         trash.addChild(newName, oldDeleted);
403       }
404       trash.addRemovedWikiPage(pageImpl);
405 
406       //update LinkRegistry
407       LinkRegistry linkRegistry = wiki.getLinkRegistry();
408       if (linkRegistry.getLinkEntries().get(getLinkEntryName(wikiType, wikiOwner, pageId)) != null) {
409         linkRegistry.getLinkEntries().get(getLinkEntryName(wikiType, wikiOwner, pageId)).setNewLink(null);
410       }
411 
412       session.save();
413     } finally {
414       mowService.stopSynchronization(created);
415     }
416   }
417 
418   @Override
419   public Template getTemplatePage(WikiPageParams params, String templateId) throws WikiException {
420     boolean created = mowService.startSynchronization();
421 
422     try {
423       TemplateContainer templatesContainer = getTemplatesContainer(params.getType(), params.getOwner());
424       Template template = convertTemplateImplToTemplate(templatesContainer.getTemplate(templateId));
425       if(template != null) {
426         template.setWikiType(params.getType());
427         template.setWikiOwner(params.getOwner());
428       }
429 
430       return template;
431     } finally {
432       mowService.stopSynchronization(created);
433     }
434   }
435 
436   @Override
437   public Map<String, Template> getTemplates(WikiPageParams params) throws WikiException {
438     boolean created = mowService.startSynchronization();
439 
440     try {
441       Map<String, Template> templates = new HashMap<>();
442       Map<String, TemplateImpl> templatesImpl = getTemplatesContainer(params.getType(), params.getOwner()).getTemplates();
443       for(String templateImplKey : templatesImpl.keySet()) {
444         Template template = convertTemplateImplToTemplate(templatesImpl.get(templateImplKey));
445         template.setWikiType(params.getType());
446         template.setWikiOwner(params.getOwner());
447         templates.put(templateImplKey, template);
448       }
449 
450       return templates;
451     } finally {
452       mowService.stopSynchronization(created);
453     }
454 
455   }
456 
457   private TemplateContainer getTemplatesContainer(String wikiType, String wikiOwner) throws WikiException {
458     boolean created = mowService.startSynchronization();
459 
460     try {
461       WikiImpl wiki = fetchWikiImpl(wikiType, wikiOwner);
462       TemplateContainer templateContainer = wiki.getPreferences().getTemplateContainer();
463 
464       return templateContainer;
465     } finally {
466       mowService.stopSynchronization(created);
467     }
468   }
469 
470   @Override
471   public void deleteDraftOfPage(Page page, String username) throws WikiException {
472     boolean created = mowService.startSynchronization();
473 
474     try {
475       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
476       UserWiki userWiki = (UserWiki) wStore.getWiki(WikiType.USER, username);
477       if(userWiki != null) {
478         PageImpl draftPagesContainer = userWiki.getDraftPagesContainer();
479         try {
480           Map<String, PageImpl> childPages = draftPagesContainer.getChildPages();
481           for (PageImpl childPage : childPages.values()) {
482             String targetPageId = ((DraftPageImpl) childPage).getTargetPage();
483             if (targetPageId != null && targetPageId.equals(page.getId())) {
484               childPage.remove();
485               return;
486             }
487           }
488         } catch(Exception e) {
489           log.error("Cannot get drafts of page " + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName()
490                   + " - Cause : " + e.getMessage(), e);
491         }
492       }
493 
494       if(log.isDebugEnabled()) {
495         log.debug("No draft page of page " + page.getWikiType() + ":" + page.getWikiOwner()
496                 + ":" + page.getName() + " for user " + username + ", so nothing to delete.");
497       }
498     } finally {
499       mowService.stopSynchronization(created);
500     }
501   }
502 
503   @Override
504   public void deleteDraftByName(String newDraftPageName, String username) throws WikiException {
505     if(newDraftPageName == null || StringUtils.isEmpty(newDraftPageName)) {
506       throw new IllegalArgumentException("Draft page name cannot be null or empty");
507     }
508     if(username == null || StringUtils.isEmpty(username)) {
509       throw new IllegalArgumentException("Username cannot be null or empty");
510     }
511 
512     boolean created = mowService.startSynchronization();
513 
514     WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
515     UserWiki userWiki = (UserWiki) wStore.getWiki(WikiType.USER, username);
516     if(userWiki == null) {
517       mowService.stopSynchronization(created);
518       throw new WikiException("Cannot delete draft page with name " + newDraftPageName + " of user " + username + " because no user wiki has been found.");
519     }
520 
521     PageImpl draftPagesContainer = userWiki.getDraftPagesContainer();
522     try {
523       Map<String, PageImpl> childPages = draftPagesContainer.getChildPages();
524       for (PageImpl childPage : childPages.values()) {
525         if (newDraftPageName.equals(childPage.getName())) {
526           childPage.remove();
527           return;
528         }
529       }
530     } catch(Exception e) {
531       throw new WikiException("Cannot delete draft page of with name " + newDraftPageName + " of user " + username, e);
532     } finally {
533       mowService.stopSynchronization(created);
534     }
535 
536     throw new WikiException("Cannot delete draft page with name " + newDraftPageName + " of user " + username + " because it does not exist.");
537   }
538 
539   @Override
540   public void renamePage(String wikiType, String wikiOwner, String pageName, String newName, String newTitle) throws WikiException {
541     boolean created = mowService.startSynchronization();
542 
543     try {
544       Page page = new Page(pageName);
545       page.setWikiType(wikiType);
546       page.setWikiOwner(wikiOwner);
547       PageImpl currentPage = fetchPageImpl(page);
548       PageImpl parentPage = currentPage.getParentPage();
549       RenamedMixin mix = currentPage.getRenamedMixin();
550       if (mix == null) {
551         mix = parentPage.getChromatticSession().create(RenamedMixin.class);
552         currentPage.setRenamedMixin(mix);
553         List<String> ids = new ArrayList<>();
554         ids.add(pageName);
555         mix.setOldPageIds(ids.toArray(new String[]{}));
556       }
557       List<String> ids = new ArrayList<>();
558       for (String id : mix.getOldPageIds()) {
559         ids.add(id);
560       }
561       mix.setOldPageIds(ids.toArray(new String[]{}));
562       currentPage.setName(newName);
563       mowService.persist();
564       currentPage.setTitle(newTitle);
565       mowService.persist();
566 
567       //update LinkRegistry
568       WikiImpl wiki = (WikiImpl) parentPage.getWiki();
569       LinkRegistry linkRegistry = wiki.getLinkRegistry();
570       String newEntryName = getLinkEntryName(wikiType, wikiOwner, newName);
571       String newEntryAlias = getLinkEntryAlias(wikiType, wikiOwner, newName);
572       LinkEntry newEntry = linkRegistry.getLinkEntries().get(newEntryName);
573       LinkEntry entry = linkRegistry.getLinkEntries().get(getLinkEntryName(wikiType, wikiOwner, pageName));
574       if (newEntry == null) {
575         newEntry = linkRegistry.createLinkEntry();
576         linkRegistry.getLinkEntries().put(newEntryName, newEntry);
577         newEntry.setAlias(newEntryAlias);
578         newEntry.setNewLink(newEntry);
579         newEntry.setTitle(newTitle);
580         if (entry != null) {
581           entry.setNewLink(newEntry);
582         }
583       } else if (entry == null) {
584         newEntry.setNewLink(newEntry);
585       } else {
586         processCircularRename(entry, newEntry);
587       }
588       parentPage.getChromatticSession().save();
589     } finally {
590       mowService.stopSynchronization(created);
591     }
592   }
593 
594   @Override
595   public void movePage(WikiPageParams currentLocationParams, WikiPageParams newLocationParams) throws WikiException {
596     boolean created = mowService.startSynchronization();
597 
598     try {
599       Page destPage = new Page(newLocationParams.getPageName());
600       destPage.setWikiType(newLocationParams.getType());
601       destPage.setWikiOwner(newLocationParams.getOwner());
602       PageImpl destPageImpl = fetchPageImpl(destPage);
603       if (destPageImpl == null || !destPageImpl.hasPermission(PermissionType.EDITPAGE)) {
604         throw new WikiException("Destination page " + newLocationParams.getType() + ":" +
605                 newLocationParams.getOwner() + ":" + newLocationParams.getPageName() + " does not exist");
606       }
607       ChromatticSession session = mowService.getSession();
608       Page movePage = new Page(currentLocationParams.getPageName());
609       destPage.setWikiType(currentLocationParams.getType());
610       destPage.setWikiOwner(currentLocationParams.getOwner());
611       PageImpl movePageImpl = fetchPageImpl(movePage);
612       WikiImpl sourceWiki = (WikiImpl) movePageImpl.getWiki();
613       MovedMixin mix = movePageImpl.getMovedMixin();
614       if (mix == null) {
615         movePageImpl.setMovedMixin(session.create(MovedMixin.class));
616         mix = movePageImpl.getMovedMixin();
617         mix.setTargetPage(movePageImpl.getParentPage());
618       }
619       mix.setTargetPage(destPageImpl);
620       WikiImpl destWiki = (WikiImpl) destPageImpl.getWiki();
621       movePageImpl.setParentPage(destPageImpl);
622       movePageImpl.setMinorEdit(false);
623 
624       // Update permission if moving page to other space or other wiki
625       Collection<AttachmentImpl> attachments = movePageImpl.getAttachmentsExcludeContentByRootPermisison();
626       HashMap<String, String[]> pagePermission = movePageImpl.getPermission();
627       if (PortalConfig.GROUP_TYPE.equals(currentLocationParams.getType())
628               && (!currentLocationParams.getOwner().equals(newLocationParams.getOwner())
629               || !PortalConfig.GROUP_TYPE.equals(newLocationParams.getType()))) {
630         // Remove old space permission first
631         Iterator<Map.Entry<String, String[]>> pagePermissionIterator = pagePermission.entrySet().iterator();
632         while (pagePermissionIterator.hasNext()) {
633           Map.Entry<String, String[]> permissionEntry = pagePermissionIterator.next();
634           if (StringUtils.substringAfter(permissionEntry.getKey(), ":").equals(currentLocationParams.getOwner())) {
635             pagePermissionIterator.remove();
636           }
637         }
638         for (AttachmentImpl attachment : attachments) {
639           HashMap<String, String[]> attachmentPermission = attachment.getPermission();
640           Iterator<Map.Entry<String, String[]>> attachmentPermissionIterator = attachmentPermission.entrySet().iterator();
641           while (attachmentPermissionIterator.hasNext()) {
642             Map.Entry<String, String[]> permissionEntry = attachmentPermissionIterator.next();
643             if (StringUtils.substringAfter(permissionEntry.getKey(), ":").equals(currentLocationParams.getOwner())) {
644               attachmentPermissionIterator.remove();
645             }
646           }
647           attachment.setPermission(attachmentPermission);
648         }
649       }
650 
651       // Update permission by inherit from parent
652       HashMap<String, String[]> parentPermissions = destPageImpl.getPermission();
653       pagePermission.putAll(parentPermissions);
654 
655       // Set permission to page
656       movePageImpl.setPermission(pagePermission);
657 
658       for (AttachmentImpl attachment : attachments) {
659         HashMap<String, String[]> attachmentPermission = attachment.getPermission();
660         attachmentPermission.putAll(parentPermissions);
661         attachment.setPermission(attachmentPermission);
662       }
663 
664 
665       //update LinkRegistry
666       if (!newLocationParams.getType().equals(currentLocationParams.getType())
667               || (PortalConfig.GROUP_TYPE.equals(currentLocationParams.getType())
668               && !currentLocationParams.getOwner().equals(newLocationParams.getOwner()))) {
669         LinkRegistry sourceLinkRegistry = sourceWiki.getLinkRegistry();
670         LinkRegistry destLinkRegistry = destWiki.getLinkRegistry();
671         String newEntryName = getLinkEntryName(newLocationParams.getType(),
672                 newLocationParams.getOwner(),
673                 currentLocationParams.getPageName());
674         String newEntryAlias = getLinkEntryAlias(newLocationParams.getType(),
675                 newLocationParams.getOwner(),
676                 currentLocationParams.getPageName());
677         LinkEntry newEntry = destLinkRegistry.getLinkEntries().get(newEntryName);
678         LinkEntry entry =
679                 sourceLinkRegistry.getLinkEntries().get(
680                         getLinkEntryName(currentLocationParams.getType(),
681                                 currentLocationParams.getOwner(),
682                                 currentLocationParams.getPageName()));
683         if (newEntry == null) {
684           newEntry = destLinkRegistry.createLinkEntry();
685           destLinkRegistry.getLinkEntries().put(newEntryName, newEntry);
686           newEntry.setAlias(newEntryAlias);
687           newEntry.setNewLink(newEntry);
688           newEntry.setTitle(destPageImpl.getTitle());
689           if (entry != null) {
690             entry.setNewLink(newEntry);
691           }
692         } else if (entry == null) {
693           newEntry.setNewLink(newEntry);
694         } else {
695           processCircularRename(entry, newEntry);
696         }
697       }
698       session.save();
699     } finally {
700       mowService.stopSynchronization(created);
701     }
702   }
703 
704   @Override
705   public List<PermissionEntry> getWikiPermission(String wikiType, String wikiOwner) throws WikiException {
706     List<PermissionEntry> permissionEntries = new ArrayList<>();
707 
708     boolean created = mowService.startSynchronization();
709 
710     try {
711       WikiImpl wikiImpl = fetchWikiImpl(wikiType, wikiOwner);
712       if (wikiImpl == null) {
713         return permissionEntries;
714       }
715 
716       List<String> permissions = wikiImpl.getWikiPermissions();
717       permissionEntries = JCRUtils.convertWikiPermissionsToPermissionEntryList(permissions);
718 
719       return permissionEntries;
720     } finally {
721       mowService.stopSynchronization(created);
722     }
723   }
724 
725   @Override
726   public void updateWikiPermission(String wikiType, String wikiOwner, List<PermissionEntry> permissionEntries) throws WikiException {
727     boolean created = mowService.startSynchronization();
728 
729     try {
730       WikiImpl wiki = fetchWikiImpl(wikiType, wikiOwner);
731       List<String> permissions = new ArrayList<>();
732       HashMap<String, String[]> permMap = new HashMap<>();
733       for (PermissionEntry entry : permissionEntries) {
734         StringBuilder actions = new StringBuilder();
735         Permission[] pers = entry.getPermissions();
736         List<String> permlist = new ArrayList<>();
737         // Permission strings has the format:
738         // VIEWPAGE,EDITPAGE,ADMINPAGE,ADMINSPACE:USER:john
739         // VIEWPAGE:GROUP:/platform/users
740         // VIEWPAGE,EDITPAGE,ADMINPAGE,ADMINSPACE:MEMBERSHIP:manager:/platform/administrators
741         for (int i = 0; i < pers.length; i++) {
742           Permission perm = pers[i];
743           if (perm.isAllowed()) {
744             actions.append(perm.getPermissionType().toString());
745             if (i < pers.length - 1) {
746               actions.append(",");
747             }
748 
749             if (perm.getPermissionType().equals(PermissionType.VIEWPAGE)) {
750               permlist.add(org.exoplatform.services.jcr.access.PermissionType.READ);
751             } else if (perm.getPermissionType().equals(PermissionType.EDITPAGE)) {
752               permlist.add(org.exoplatform.services.jcr.access.PermissionType.ADD_NODE);
753               permlist.add(org.exoplatform.services.jcr.access.PermissionType.REMOVE);
754               permlist.add(org.exoplatform.services.jcr.access.PermissionType.SET_PROPERTY);
755             }
756           }
757         }
758         if (actions.toString().length() > 0) {
759           actions.append(":").append(entry.getIdType()).append(":").append(entry.getId());
760           permissions.add(actions.toString());
761         }
762         if (permlist.size() > 0) {
763           permMap.put(entry.getId(), permlist.toArray(new String[permlist.size()]));
764         }
765       }
766       wiki.setWikiPermissions(permissions);
767       // TODO: study performance
768       updateAllPagesPermissions(wikiType, wikiOwner, permMap);
769       mowService.persist();
770     } finally {
771       mowService.stopSynchronization(created);
772     }
773   }
774 
775   @Override
776   public List<Page> getRelatedPagesOfPage(Page page) throws WikiException {
777     boolean created = mowService.startSynchronization();
778 
779     try {
780       List<Page> relatedPages = new ArrayList<>();
781 
782       PageImpl pageImpl = fetchPageImpl(page);
783       List<PageImpl> relatedPageImpls = pageImpl.getRelatedPages();
784       for (PageImpl relatedPageImpl : relatedPageImpls) {
785         relatedPages.add(convertPageImplToPage(relatedPageImpl));
786       }
787 
788       return relatedPages;
789     } catch(RepositoryException e) {
790       throw new WikiException("Cannot get related pages of page " + page.getWikiType()
791               + ":" + page.getWikiOwner() + ":" + page.getName() + " - Cause : " + e.getMessage(), e);
792     } finally {
793       mowService.stopSynchronization(created);
794     }
795   }
796 
797   @Override
798   public Page getRelatedPage(String wikiType, String wikiOwner, String pageId) throws WikiException {
799     boolean created = mowService.startSynchronization();
800 
801     try {
802       WikiImpl wiki = fetchWikiImpl(wikiType, wikiOwner);
803       LinkRegistry linkRegistry = wiki.getLinkRegistry();
804       LinkEntry oldLinkEntry = linkRegistry.getLinkEntries().get(getLinkEntryName(wikiType, wikiOwner, pageId));
805       LinkEntry newLinkEntry = null;
806       if (oldLinkEntry != null) {
807         newLinkEntry = oldLinkEntry.getNewLink();
808       }
809       int circularFlag = CIRCULAR_RENAME_FLAG;// To deal with old circular data if it is existed
810       while (newLinkEntry != null && !newLinkEntry.equals(oldLinkEntry) && circularFlag > 0) {
811         oldLinkEntry = newLinkEntry;
812         newLinkEntry = oldLinkEntry.getNewLink();
813         circularFlag--;
814       }
815       if (newLinkEntry == null) {
816         return null;
817       }
818       if (circularFlag == 0) {
819         // Find link entry mapped with an existed page in old circular data
820         circularFlag = CIRCULAR_RENAME_FLAG;
821         while (circularFlag > 0) {
822           if (getPageWithLinkEntry(newLinkEntry) != null) {
823             break;
824           }
825           newLinkEntry = newLinkEntry.getNewLink();
826           circularFlag--;
827         }
828         // Break old circular data
829         if (circularFlag > 0) {
830           newLinkEntry.setNewLink(newLinkEntry);
831         }
832       }
833       Page pageWithLinkEntry = getPageWithLinkEntry(newLinkEntry);
834 
835       return pageWithLinkEntry;
836     } finally {
837       mowService.stopSynchronization(created);
838     }
839   }
840 
841   @Override
842   public void addRelatedPage(Page page, Page relatedPage) throws WikiException {
843     boolean created = mowService.startSynchronization();
844 
845     try {
846       PageImpl pageImpl = fetchPageImpl(page);
847       PageImpl relatedPageImpl = fetchPageImpl(relatedPage);
848       pageImpl.addRelatedPage(relatedPageImpl);
849     } catch(RepositoryException e) {
850       throw new WikiException("Cannot add related page "
851               + relatedPage.getWikiType() + ":" + relatedPage.getWikiOwner() + ":" + relatedPage.getName()
852               + " for page " + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName()
853               + " - Cause : " + e.getMessage(), e);
854     } finally {
855       mowService.stopSynchronization(created);
856     }
857   }
858 
859   @Override
860   public void removeRelatedPage(Page page, Page relatedPage) throws WikiException {
861     boolean created = mowService.startSynchronization();
862 
863     try {
864       PageImpl pageImpl = fetchPageImpl(page);
865       PageImpl relatedPageImpl = fetchPageImpl(relatedPage);
866       pageImpl.removeRelatedPage(relatedPageImpl);
867     } catch(RepositoryException e) {
868       throw new WikiException("Cannot remove related page "
869               + relatedPage.getWikiType() + ":" + relatedPage.getWikiOwner() + ":" + relatedPage.getName()
870               + " of page " + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName()
871               + " - Cause : " + e.getMessage(), e);
872     } finally {
873       mowService.stopSynchronization(created);
874     }
875   }
876 
877   @Override
878   public Page getExsitedOrNewDraftPageById(String wikiType, String wikiOwner, String pageId, String username) throws WikiException {
879     boolean created = mowService.startSynchronization();
880 
881     try {
882       // if this is ANONIM then use draft in DraftNewPagesContainer
883       if (IdentityConstants.ANONIM.equals(username)) {
884         WikiStore wStore = mowService.getWikiStore();
885         PageImpl draftNewPagesContainer = wStore.getDraftNewPagesContainer();
886         PageImpl draftPage = draftNewPagesContainer.getChildPages().get(pageId);
887         if (draftPage == null) {
888           draftPage = wStore.createPage();
889           draftPage.setName(pageId);
890           draftNewPagesContainer.addPublicPage(draftPage);
891         }
892         return convertPageImplToPage(draftPage);
893       }
894 
895       // check to get draft if exist
896       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
897 
898       UserWiki userWiki;
899 
900       // Check if in the case that access to wiki page by rest service of xwiki
901       if ((username == null) && (pageId.contains(Utils.SPLIT_TEXT_OF_DRAFT_FOR_NEW_PAGE))) {
902         String[] texts = pageId.split(Utils.SPLIT_TEXT_OF_DRAFT_FOR_NEW_PAGE);
903         username = texts[0];
904         WikiContainer<UserWiki> userWikiContainer = wStore.getWikiContainer(WikiType.USER);
905         userWiki = userWikiContainer.getWiki(username);
906         Collection<PageImpl> childPages = userWiki.getDraftPagesContainer().getChildrenByRootPermission().values();
907 
908         // Change collection to List
909         for (PageImpl pageImpl : childPages) {
910           if (pageImpl.getName().equals(pageId)) {
911             return convertPageImplToPage(pageImpl);
912           }
913         }
914       } else {
915         userWiki = (UserWiki) fetchWikiImpl(PortalConfig.USER_TYPE, username);
916         if(userWiki == null) {
917           userWiki = (UserWiki) wStore.addWiki(WikiType.USER, username);
918         }
919         // Get draft page
920         DraftPage draftPage = getDraft(pageId, username);
921         if (draftPage != null) {
922           return draftPage;
923         }
924       }
925 
926       // Get draft page container
927       PageImpl draftPagesContainer = userWiki.getDraftPagesContainer();
928 
929       // Create new draft
930       DraftPageImpl draftPageImpl = userWiki.createDraftPage();
931       draftPageImpl.setName(pageId);
932       draftPagesContainer.addWikiPage(draftPageImpl);
933       draftPageImpl.setNewPage(true);
934       draftPageImpl.setTargetPage(null);
935       draftPageImpl.setTargetRevision("1");
936 
937       // Put any permisison to access by xwiki rest service
938       HashMap<String, String[]> permissions = draftPageImpl.getPermission();
939       permissions.put(IdentityConstants.ANY, new String[]{org.exoplatform.services.jcr.access.PermissionType.READ});
940       draftPageImpl.setPermission(permissions);
941       Page draftPage = convertPageImplToPage(draftPageImpl);
942 
943       return draftPage;
944     } finally {
945       mowService.stopSynchronization(created);
946     }
947   }
948 
949   @Override
950   public DraftPage getDraft(WikiPageParams param, String username) throws WikiException {
951     if (IdentityConstants.ANONIM.equals(username)) {
952       return null;
953     }
954 
955     if ((param.getPageName() == null) || (param.getOwner() == null) || (param.getType() == null)) {
956       return null;
957     }
958 
959     Page page = new Page(param.getPageName());
960     page.setWikiType(param.getType());
961     page.setWikiOwner(param.getOwner());
962     PageImpl targetPage = fetchPageImpl(page);
963     if ((param.getPageName() == null) || (targetPage == null)) {
964       return null;
965     }
966 
967     boolean created = mowService.startSynchronization();
968 
969     try {
970       // Get all draft pages
971       UserWiki userWiki = (UserWiki) fetchWikiImpl(PortalConfig.USER_TYPE, username);
972       Collection<PageImpl> childPages = userWiki.getDraftPagesContainer().getChildPages().values();
973 
974       // Find the lastest draft of target page
975       DraftPageImpl lastestDraft = null;
976       for (PageImpl draft : childPages) {
977         DraftPageImpl draftPage = (DraftPageImpl) draft;
978         // If this draft is use for target page
979         try {
980           if (draftPage.getTargetPage() != null && !draftPage.isNewPage() && draftPage.getTargetPage().equals(targetPage.getJCRPageNode().getUUID())) {
981             // Compare and get the lastest draft
982             if ((lastestDraft == null) || (lastestDraft.getUpdatedDate().getTime() < draftPage.getUpdatedDate().getTime())) {
983               lastestDraft = draftPage;
984             }
985           }
986         } catch(RepositoryException e) {
987           log.error("Cannot get JCR node of page " + param.getType() + ":" + param.getOwner() + ":" + param.getPageName()
988             + " for user " + username + " - Cause : " + e.getMessage(), e);
989         }
990       }
991 
992       DraftPage draftPage = convertDraftPageImplToDraftPage(lastestDraft);
993 
994       return draftPage;
995     } finally {
996       mowService.stopSynchronization(created);
997     }
998   }
999 
1000 
1001   @Override
1002   public DraftPage getLastestDraft(String username) throws WikiException {
1003     boolean created = mowService.startSynchronization();
1004 
1005     try {
1006       // Get all draft pages
1007       UserWiki userWiki = (UserWiki) fetchWikiImpl(PortalConfig.USER_TYPE, username);
1008       Collection<PageImpl> childPages = userWiki.getDraftPagesContainer().getChildPages().values();
1009 
1010       // Find the lastest draft
1011       DraftPageImpl lastestDraft = null;
1012       for (PageImpl draft : childPages) {
1013         DraftPageImpl draftPage = (DraftPageImpl) draft;
1014         // Compare and get the lastest draft
1015         if ((lastestDraft == null) || (lastestDraft.getUpdatedDate().getTime() < draftPage.getUpdatedDate().getTime())) {
1016           lastestDraft = draftPage;
1017         }
1018       }
1019       DraftPage draftPage = convertDraftPageImplToDraftPage(lastestDraft);
1020 
1021       return draftPage;
1022     } finally {
1023       mowService.stopSynchronization(created);
1024     }
1025   }
1026 
1027   @Override
1028   public DraftPage getDraft(String draftName, String username) throws WikiException {
1029     boolean created = mowService.startSynchronization();
1030 
1031     try {
1032       DraftPage page = null;
1033       List<DraftPage> drafts = getDraftPagesOfUser(username);
1034       for (DraftPage draftPage : drafts) {
1035         if (draftPage.getName().equals(draftName)) {
1036           page = draftPage;
1037           break;
1038         }
1039       }
1040 
1041       return page;
1042     } finally {
1043       mowService.stopSynchronization(created);
1044     }
1045   }
1046 
1047   @Override
1048   public List<DraftPage> getDraftPagesOfUser(String username) throws WikiException {
1049     List<DraftPage> draftPages = new ArrayList<>();
1050 
1051     boolean created = mowService.startSynchronization();
1052 
1053     try {
1054       // Get all draft of user
1055       UserWiki userWiki = (UserWiki) mowService.getWikiStore().getWiki(WikiType.USER, username);
1056       if(userWiki != null) {
1057         Collection<PageImpl> childPages = userWiki.getDraftPagesContainer().getChildPages().values();
1058 
1059         // Change collection to List
1060         for (PageImpl page : childPages) {
1061           DraftPage draftPage = convertDraftPageImplToDraftPage((DraftPageImpl) page);
1062           draftPage.setWikiType(userWiki.getType());
1063           draftPage.setWikiOwner(userWiki.getOwner());
1064           draftPages.add(draftPage);
1065         }
1066       }
1067 
1068       return draftPages;
1069     } finally {
1070       mowService.stopSynchronization(created);
1071     }
1072   }
1073 
1074   @Override
1075   public void createDraftPageForUser(DraftPage draftPage, String username) throws WikiException {
1076     boolean created = mowService.startSynchronization();
1077 
1078     try {
1079       WikiStore wikiStore = mowService.getWikiStore();
1080 
1081       UserWiki userWiki = (UserWiki) wikiStore.getWiki(WikiType.USER, username);
1082       if(userWiki == null) {
1083         userWiki = (UserWiki) wikiStore.addWiki(WikiType.USER, username);
1084       }
1085       PageImpl draftPagesContainer = userWiki.getDraftPagesContainer();
1086 
1087       // Create draft page
1088       DraftPageImpl draftPageImpl = userWiki.createDraftPage();
1089       draftPageImpl.setName(draftPage.getName());
1090       draftPagesContainer.addWikiPage(draftPageImpl);
1091       draftPageImpl.setNewPage(draftPage.isNewPage());
1092       draftPageImpl.setTitle(draftPage.getTitle());
1093       draftPageImpl.getContent().setText(draftPage.getContent());
1094       draftPageImpl.setTargetPage(draftPage.getTargetPageId());
1095       draftPageImpl.setTargetRevision(draftPage.getTargetPageRevision());
1096       draftPageImpl.setCreatedDate(draftPage.getCreatedDate());
1097       draftPageImpl.setUpdatedDate(draftPage.getUpdatedDate());
1098 
1099       mowService.persist();
1100     } finally {
1101       mowService.stopSynchronization(created);
1102     }
1103   }
1104 
1105   @Override
1106   public PageList<SearchResult> search(WikiSearchData data) throws WikiException {
1107     List<SearchResult> resultList = new ArrayList<>();
1108     List<JCRSearchResult> jcrResultList = new ArrayList<>();
1109     long numberOfSearchForTitleResult = 0;
1110 
1111     boolean created = mowService.startSynchronization();
1112 
1113 
1114     try {
1115       ChromatticSession session = mowService.getSession();
1116       if (!StringUtils.isEmpty(data.getTitle())) {
1117         // Search for title
1118         String statement = new JCRWikiSearchQueryBuilder(data).getStatementForSearchingTitle();
1119         QueryImpl q = (QueryImpl) ((ChromatticSessionImpl) session).getDomainSession().getSessionWrapper().createQuery(statement);
1120         if (data.getOffset() > 0) {
1121           q.setOffset(data.getOffset());
1122         }
1123         if (data.getLimit() > 0) {
1124           q.setLimit(data.getLimit());
1125         }
1126         QueryResult result = q.execute();
1127         RowIterator iter = result.getRows();
1128         numberOfSearchForTitleResult = iter.getSize();
1129         if (numberOfSearchForTitleResult > 0) {
1130           while (iter.hasNext()) {
1131             JCRSearchResult tempResult = getResult(iter.nextRow(), data);
1132             // If contains, merges with the exist
1133             if (tempResult != null && !isContains(jcrResultList, tempResult)) {
1134               jcrResultList.add(tempResult);
1135             }
1136           }
1137         }
1138       }
1139 
1140       // if we don't have enough result, search in wiki pages content
1141       if (!((jcrResultList.size() >= data.getLimit()) || StringUtils.isEmpty(data.getContent()))) {
1142         // Search for wiki content
1143         long searchForContentOffset = data.getOffset();
1144         long searchForContentLimit = data.getLimit() - numberOfSearchForTitleResult;
1145         if (data.getLimit() == Integer.MAX_VALUE) {
1146           searchForContentLimit = Integer.MAX_VALUE;
1147         }
1148 
1149         if (searchForContentOffset >= 0 && searchForContentLimit > 0) {
1150           JCRWikiSearchQueryBuilder queryBuilder = new JCRWikiSearchQueryBuilder(data);
1151           String statement = queryBuilder.getStatementForSearchingContent();
1152           QueryImpl q = (QueryImpl) ((ChromatticSessionImpl) session).getDomainSession().getSessionWrapper().createQuery(statement);
1153           q.setOffset(searchForContentOffset);
1154           q.setLimit(searchForContentLimit);
1155           QueryResult result = q.execute();
1156           RowIterator iter = result.getRows();
1157           while (iter.hasNext()) {
1158             JCRSearchResult tempResult = getResult(iter.nextRow(), data);
1159             // If contains, merges with the exist
1160             if (tempResult != null && !isContains(jcrResultList, tempResult) && !isDuplicateTitle(jcrResultList, tempResult)) {
1161               jcrResultList.add(tempResult);
1162             }
1163           }
1164         }
1165       }
1166 
1167       // convert list of JCRSearchResult to list of SearchResult
1168       for(SearchResult searchResult : jcrResultList) {
1169         resultList.add(searchResult);
1170       }
1171 
1172       // Return all the result
1173       return new ObjectPageList<>(resultList, resultList.size());
1174     } catch (RepositoryException e) {
1175       throw new WikiException("Cannot search in wiki " + data.getWikiType() + ":" + data.getWikiOwner(), e);
1176     } finally {
1177       mowService.stopSynchronization(created);
1178     }
1179   }
1180 
1181   @Override
1182   public List<Attachment> getAttachmentsOfPage(Page page) throws WikiException {
1183     List<Attachment> attachments = new ArrayList<>();
1184 
1185     boolean created = mowService.startSynchronization();
1186 
1187     try {
1188       PageImpl pageImpl = fetchPageImpl(page);
1189       if(pageImpl != null) {
1190         try {
1191           Collection<AttachmentImpl> attachmentsExcludeContent = pageImpl.getAttachmentsExcludeContent();
1192           if(attachmentsExcludeContent != null) {
1193             for (AttachmentImpl attachmentImpl : attachmentsExcludeContent) {
1194               attachments.add(convertAttachmentImplToAttachment(attachmentImpl));
1195             }
1196           }
1197         } catch (RepositoryException e) {
1198           throw new WikiException("Cannot get attachments of page "
1199                   + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName(), e);
1200         }
1201       } else {
1202         throw new WikiException("Cannot get attachments of page "
1203                 + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName() + " because the page does not exist.");
1204       }
1205 
1206       return attachments;
1207     } finally {
1208       mowService.stopSynchronization(created);
1209     }
1210   }
1211 
1212   @Override
1213   public void addAttachmentToPage(Attachment attachment, Page page) throws WikiException {
1214     boolean created = mowService.startSynchronization();
1215 
1216     try {
1217       PageImpl pageImpl = fetchPageImpl(page);
1218       AttachmentImpl attachmentImpl = pageImpl.createAttachment(attachment.getName(), new Resource(attachment.getMimeType(), "UTF-8", attachment.getContent()));
1219       attachmentImpl.setTitle(attachment.getTitle());
1220       attachmentImpl.setCreator(attachment.getCreator());
1221     } finally {
1222       mowService.stopSynchronization(created);
1223     }
1224   }
1225 
1226   @Override
1227   public void deleteAttachmentOfPage(String attachmentId, Page page) throws WikiException {
1228     boolean created = mowService.startSynchronization();
1229 
1230     try {
1231       PageImpl pageImpl = fetchPageImpl(page);
1232       pageImpl.removeAttachment(attachmentId);
1233     } finally {
1234       mowService.stopSynchronization(created);
1235     }
1236   }
1237 
1238   @Override
1239   public Page getHelpSyntaxPage(String syntaxId, boolean fullContent, List<ValuesParam> syntaxHelpParams, ConfigurationManager configurationManager) throws WikiException {
1240     boolean created = mowService.startSynchronization();
1241 
1242     try {
1243       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
1244       HelpPage helpPageByChromattic = wStore.getHelpPageByChromattic();
1245 
1246       if(helpPageByChromattic == null || wStore.getHelpPagesContainer().getChildPages().size() == 0) {
1247         createHelpPages(syntaxHelpParams, configurationManager);
1248       }
1249 
1250       PageImpl helpPageImpl = null;
1251       Iterator<PageImpl> syntaxPageIterator = wStore.getHelpPagesContainer()
1252               .getChildPages()
1253               .values()
1254               .iterator();
1255       while (syntaxPageIterator.hasNext()) {
1256         PageImpl syntaxPage = syntaxPageIterator.next();
1257         if (syntaxPage.getSyntax().equals(syntaxId)) {
1258           helpPageImpl = syntaxPage;
1259           break;
1260         }
1261       }
1262 
1263       // the full help page is stored as a child page of the small help page
1264       if(helpPageImpl != null && fullContent) {
1265         Map<String, PageImpl> childPages = helpPageImpl.getChildPages();
1266         if(childPages != null && childPages.size() > 0) {
1267           helpPageImpl = childPages.values().iterator().next();
1268         }
1269       }
1270 
1271       return convertPageImplToPage(helpPageImpl);
1272     } finally {
1273       mowService.stopSynchronization(created);
1274     }
1275   }
1276 
1277   @Override
1278   public void createEmotionIcon(EmotionIcon emotionIcon) throws WikiException {
1279     boolean created = mowService.startSynchronization();
1280 
1281     try {
1282       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
1283       PageImpl emotionIconsPage = wStore.getEmotionIconsContainer();
1284 
1285       String mimetype;
1286       try {
1287         mimetype = URLConnection.guessContentTypeFromStream(new ByteArrayInputStream(emotionIcon.getImage()));
1288       } catch (IOException e) {
1289         log.warn("Cannot guess mimetype from inputstream for emotion icon " + emotionIcon.getName() + " - Cause : " + e.getMessage());
1290         mimetype = URLConnection.guessContentTypeFromName(emotionIcon.getName());
1291         if(mimetype == null) {
1292           mimetype = "image/*";
1293         }
1294       }
1295 
1296       AttachmentImpl emotionIconAttachment = emotionIconsPage.createAttachment(emotionIcon.getName(),
1297               new Resource(mimetype, "UTF-8", emotionIcon.getImage()));
1298       emotionIconsPage.addAttachment(emotionIconAttachment);
1299     } finally {
1300       mowService.stopSynchronization(created);
1301     }
1302   }
1303 
1304   @Override
1305   public List<EmotionIcon> getEmotionIcons() throws WikiException {
1306     List<EmotionIcon> emotionIcons = null;
1307 
1308     boolean created = mowService.startSynchronization();
1309 
1310     try {
1311       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
1312 
1313       PageImpl emotionIconsPage = wStore.getEmotionIconsContainer();
1314       if(emotionIconsPage != null) {
1315         emotionIcons = new ArrayList<>();
1316 
1317         String baseUrl = JCRUtils.getCurrentRepositoryWebDavUri();
1318 
1319         Collection<AttachmentImpl> emotionIconsAttachments = emotionIconsPage.getAttachments();
1320         for(AttachmentImpl emotionIconAttachment : emotionIconsAttachments) {
1321           EmotionIcon emotionIcon = new EmotionIcon();
1322           emotionIcon.setName(emotionIconAttachment.getName());
1323           StringBuilder sbUrl = new StringBuilder(baseUrl)
1324                   .append(mowService.getSession().getJCRSession().getWorkspace().getName())
1325                   .append(emotionIconsPage.getPath())
1326                   .append("/")
1327                   .append(emotionIconAttachment.getName());
1328           emotionIcon.setUrl(sbUrl.toString());
1329           emotionIcons.add(emotionIcon);
1330         }
1331       }
1332 
1333       return emotionIcons;
1334     } finally {
1335       mowService.stopSynchronization(created);
1336     }
1337   }
1338 
1339   @Override
1340   public EmotionIcon getEmotionIconByName(String name) throws WikiException {
1341     EmotionIcon emotionIcon = null;
1342 
1343     boolean created = mowService.startSynchronization();
1344 
1345     try {
1346       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
1347 
1348       String baseUrl = JCRUtils.getCurrentRepositoryWebDavUri();
1349 
1350       PageImpl emotionIconsPage = wStore.getEmotionIconsContainer();
1351       if(emotionIconsPage != null) {
1352         AttachmentImpl emotionIconAttachment = emotionIconsPage.getAttachment(name);
1353         if(emotionIconAttachment != null) {
1354           emotionIcon = new EmotionIcon();
1355           emotionIcon.setName(name);
1356           StringBuilder sbUrl = new StringBuilder(baseUrl)
1357                   .append(mowService.getSession().getJCRSession().getWorkspace().getName())
1358                   .append(emotionIconsPage.getPath())
1359                   .append("/")
1360                   .append(emotionIconAttachment.getName());
1361           emotionIcon.setUrl(sbUrl.toString());
1362           emotionIcon.setImage(emotionIconAttachment.getContentResource().getData());
1363         }
1364       }
1365 
1366       return emotionIcon;
1367     } finally {
1368       mowService.stopSynchronization(created);
1369     }
1370   }
1371 
1372   private synchronized void createHelpPages(List<ValuesParam> syntaxHelpParams, ConfigurationManager configurationManager) throws WikiException {
1373     boolean created = mowService.startSynchronization();
1374 
1375     try {
1376       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
1377       PageImpl helpPage = wStore.getHelpPagesContainer();
1378       if (helpPage.getChildPages().size() == 0) {
1379         for (ValuesParam syntaxhelpParam : syntaxHelpParams) {
1380           try {
1381             String syntaxName = syntaxhelpParam.getName();
1382             List<String> syntaxValues = syntaxhelpParam.getValues();
1383             String shortFilePath = syntaxValues.get(0);
1384             String fullFilePath = syntaxValues.get(1);
1385             InputStream shortFile = configurationManager.getInputStream(shortFilePath);
1386             InputStream fullFile = configurationManager.getInputStream(fullFilePath);
1387             HelpPage syntaxPage = addSyntaxPage(wStore, helpPage, syntaxName, shortFile, " Short help Page");
1388             addSyntaxPage(wStore, syntaxPage, syntaxName, fullFile, " Full help Page");
1389             mowService.persist();
1390           } catch (Exception e) {
1391             log.error("Can not create Help page " + syntaxhelpParam.getName() + " - Cause : " + e.getMessage(), e);
1392           }
1393         }
1394       }
1395     } finally {
1396       mowService.stopSynchronization(created);
1397     }
1398   }
1399 
1400   @Override
1401   public boolean hasAdminSpacePermission(String wikiType, String owner, Identity user) throws WikiException {
1402     boolean created = mowService.startSynchronization();
1403 
1404     try {
1405       List<AccessControlEntry> aces = getAccessControls(wikiType, owner);
1406       AccessControlList acl = new AccessControlList(owner, aces);
1407       String[] permission = new String[]{PermissionType.ADMINSPACE.toString()};
1408       boolean hasPermission = JCRUtils.hasPermission(acl, permission, user);
1409 
1410       return hasPermission;
1411     } finally {
1412       mowService.stopSynchronization(created);
1413     }
1414   }
1415 
1416   @Override
1417   public boolean hasAdminPagePermission(String wikiType, String owner, Identity user) throws WikiException {
1418     boolean created = mowService.startSynchronization();
1419 
1420     try {
1421       List<AccessControlEntry> aces = getAccessControls(wikiType, owner);
1422       AccessControlList acl = new AccessControlList(owner, aces);
1423       String[] permission = new String[]{PermissionType.ADMINPAGE.toString()};
1424       boolean hasPermission = JCRUtils.hasPermission(acl, permission, user);
1425 
1426       return hasPermission;
1427     } finally {
1428       mowService.stopSynchronization(created);
1429     }
1430   }
1431 
1432   @Override
1433   public boolean hasPermissionOnPage(Page page, PermissionType permissionType, Identity user) throws WikiException {
1434     boolean created = mowService.startSynchronization();
1435 
1436     boolean hasPermission = false;
1437 
1438     try {
1439       PageImpl pageImpl = fetchPageImpl(page);
1440       if (pageImpl != null) {
1441         hasPermission = pageImpl.hasPermission(permissionType, user);
1442       } else {
1443         log.error("Cannot check permissions on page " + page.getWikiType() + ":" + page.getWikiOwner()
1444                 + ":" + page.getName() + " because page cannot be fetched");
1445       }
1446     } finally {
1447       mowService.stopSynchronization(created);
1448     }
1449 
1450     return hasPermission;
1451   }
1452 
1453   private List<AccessControlEntry> getAccessControls(String wikiType, String wikiOwner) throws WikiException {
1454     boolean created = mowService.startSynchronization();
1455 
1456     List<AccessControlEntry> aces = new ArrayList<>();
1457     try {
1458       List<PermissionEntry> permissionEntries = getWikiPermission(wikiType, wikiOwner);
1459       for (PermissionEntry perm : permissionEntries) {
1460         Permission[] permissions = perm.getPermissions();
1461         List<String> actions = new ArrayList<>();
1462         for (Permission permission : permissions) {
1463           if (permission.isAllowed()) {
1464             actions.add(permission.getPermissionType().toString());
1465           }
1466         }
1467 
1468         for (String action : actions) {
1469           aces.add(new AccessControlEntry(perm.getId(), action));
1470         }
1471       }
1472     } catch (WikiException e) {
1473       if (log.isDebugEnabled()) {
1474         log.debug("failed in method getAccessControls:", e);
1475       }
1476     } finally {
1477       mowService.stopSynchronization(created);
1478     }
1479 
1480     return aces;
1481   }
1482 
1483   @Override
1484   public List<PageVersion> getVersionsOfPage(Page page) throws WikiException {
1485     boolean created = mowService.startSynchronization();
1486 
1487     try {
1488       PageImpl pageImpl = fetchPageImpl(page);
1489 
1490       List<PageVersion> versions = new ArrayList<>();
1491       VersionableMixin versionableMixin = pageImpl.getVersionableMixin();
1492       if(versionableMixin != null) {
1493         for (NTVersion version : versionableMixin.getVersionHistory()) {
1494           if (!(WikiNodeType.Definition.ROOT_VERSION.equals(version.getName()))) {
1495             try {
1496               PageVersion pageVersion = new PageVersion();
1497               pageVersion.setName(version.getName());
1498               pageVersion.setAuthor(version.getNTFrozenNode().getAuthor());
1499               pageVersion.setCreatedDate(version.getCreated());
1500               pageVersion.setUpdatedDate(version.getNTFrozenNode().getUpdatedDate());
1501               //pageVersion.setPredecessors(version.getPredecessors());
1502               //pageVersion.setSuccessors(version.getSuccessors());
1503               pageVersion.setContent(version.getNTFrozenNode().getContentString());
1504               pageVersion.setComment(version.getNTFrozenNode().getComment());
1505               versions.add(pageVersion);
1506             } catch(RepositoryException e) {
1507               log.error("Cannot get version " + version.getName() + " of page "
1508                       + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName()
1509                       + " - Cause : " + e.getMessage(), e);
1510             }
1511           }
1512         }
1513       }
1514       Collections.sort(versions, new VersionNameComparatorDesc());
1515 
1516       return versions;
1517     } finally {
1518       mowService.stopSynchronization(created);
1519     }
1520   }
1521 
1522   @Override
1523   public void addPageVersion(Page page) throws WikiException {
1524     boolean created = mowService.startSynchronization();
1525 
1526     try {
1527       PageImpl pageImpl = fetchPageImpl(page);
1528       if(pageImpl.getVersionableMixin() == null) {
1529         pageImpl.makeVersionable();
1530       }
1531       pageImpl.checkin();
1532       pageImpl.checkout();
1533     } catch(RepositoryException e) {
1534       throw new WikiException("Cannot create new version of page "
1535               + page.getWikiType() + ":" + page.getWikiOwner() + ":" + page.getName(), e);
1536     } finally {
1537       mowService.stopSynchronization(created);
1538     }
1539   }
1540 
1541   @Override
1542   public void restoreVersionOfPage(String versionName, Page page) throws WikiException {
1543     boolean created = mowService.startSynchronization();
1544     try {
1545       PageImpl pageImpl = fetchPageImpl(page);
1546       pageImpl.restore(versionName, false);
1547     } finally {
1548       mowService.stopSynchronization(created);
1549     }
1550   }
1551 
1552   @Override
1553   public void updatePage(Page page) throws WikiException {
1554     boolean created = mowService.startSynchronization();
1555 
1556     try {
1557       PageImpl pageImpl = fetchPageImpl(page);
1558       pageImpl.setTitle(page.getTitle());
1559       pageImpl.setOwner(page.getOwner());
1560       pageImpl.setAuthor(page.getAuthor());
1561       pageImpl.setSyntax(page.getSyntax());
1562 
1563       List<PermissionEntry> currentPermissions = JCRUtils.convertToPermissionEntryList(pageImpl.getPermission());
1564       if(!CollectionUtils.isEqualCollection(currentPermissions, page.getPermissions())) {
1565         pageImpl.setPermission(JCRUtils.convertToPermissionMap(page.getPermissions()));
1566         pageImpl.setOverridePermission(true);
1567       }
1568       pageImpl.setURL(page.getUrl());
1569       pageImpl.getContent().setText(page.getContent());
1570       pageImpl.setComment(page.getComment());
1571       pageImpl.setUpdatedDate(GregorianCalendar.getInstance().getTime());
1572 
1573       if(page.getActivityId() != null) {
1574         pageImpl.setActivityId(page.getActivityId());
1575       }
1576 
1577       mowService.persist();
1578     } finally {
1579       mowService.stopSynchronization(created);
1580     }
1581   }
1582 
1583   @Override
1584   public List<String> getPreviousNamesOfPage(Page page) throws WikiException {
1585     boolean created = mowService.startSynchronization();
1586 
1587     try {
1588       PageImpl pageImpl = fetchPageImpl(page);
1589       if(pageImpl != null) {
1590         List<String> previousNames = new ArrayList<>();
1591         RenamedMixin renamedMixin = pageImpl.getRenamedMixin();
1592         if(renamedMixin != null) {
1593           previousNames = Arrays.asList(renamedMixin.getOldPageIds());
1594         }
1595 
1596         return previousNames;
1597       } else {
1598         throw new WikiException("Cannot get previous names of page " + page.getWikiType() + ":"
1599                 + page.getWikiOwner() + ":" + page.getName() + " because the page does not exist.");
1600       }
1601     } finally {
1602       mowService.stopSynchronization(created);
1603     }
1604   }
1605 
1606   @Override
1607   public List<String> getWatchersOfPage(Page page) throws WikiException {
1608     List<String> watchers;
1609 
1610     boolean created = mowService.startSynchronization();
1611 
1612     try {
1613       PageImpl pageImpl = fetchPageImpl(page);
1614       if(pageImpl != null) {
1615         WatchedMixin watchedMixin = pageImpl.getWatchedMixin();
1616         if(watchedMixin != null) {
1617           watchers = watchedMixin.getWatchers();
1618         } else {
1619           watchers = Collections.EMPTY_LIST;
1620         }
1621 
1622         return watchers;
1623       } else {
1624         throw new WikiException("Cannot get watchers of page " + page.getWikiType() + ":"
1625                 + page.getWikiOwner() + ":" + page.getName() + " because the page does not exist.");
1626       }
1627     } finally {
1628       mowService.stopSynchronization(created);
1629     }
1630   }
1631 
1632   @Override
1633   public void addWatcherToPage(String username, Page page) throws WikiException {
1634     boolean created = mowService.startSynchronization();
1635 
1636     try {
1637       PageImpl pageImpl = fetchPageImpl(page);
1638       if(pageImpl != null) {
1639         pageImpl.makeWatched();
1640         List<String> watchers = pageImpl.getWatchedMixin().getWatchers();
1641         if (watchers == null) {
1642           watchers = new ArrayList<>();
1643         }
1644         if (!watchers.contains(username)) {
1645           watchers.add(username);
1646           pageImpl.getWatchedMixin().setWatchers(watchers);
1647         }
1648 
1649         mowService.persist();
1650       } else {
1651         throw new WikiException("Cannot add watcher " + username + " to page " + page.getWikiType() + ":"
1652                 + page.getWikiOwner() + ":" + page.getName() + " because the page does not exist.");
1653       }
1654     } finally {
1655       mowService.stopSynchronization(created);
1656     }
1657   }
1658 
1659   @Override
1660   public void deleteWatcherOfPage(String username, Page page) throws WikiException {
1661     boolean created = mowService.startSynchronization();
1662 
1663     try {
1664       PageImpl pageImpl = fetchPageImpl(page);
1665       if(pageImpl != null) {
1666         pageImpl.makeWatched();
1667         List<String> watchers = pageImpl.getWatchedMixin().getWatchers();
1668         if (watchers != null && watchers.contains(username)) {
1669           watchers.remove(username);
1670           pageImpl.getWatchedMixin().setWatchers(watchers);
1671         }
1672 
1673         mowService.persist();
1674       } else {
1675         throw new WikiException("Cannot delete watcher " + username + " of page " + page.getWikiType() + ":"
1676                 + page.getWikiOwner() + ":" + page.getName() + " because the page does not exist.");
1677       }
1678     } finally {
1679       mowService.stopSynchronization(created);
1680     }
1681   }
1682 
1683   private HelpPage addSyntaxPage(WikiStoreImpl wStore,
1684                                  PageImpl parentPage,
1685                                  String name,
1686                                  InputStream content,
1687                                  String type) throws WikiException {
1688     boolean created = mowService.startSynchronization();
1689 
1690     StringBuilder stringContent = new StringBuilder();
1691     BufferedReader bufferReader = null;
1692     String tempLine;
1693     try {
1694       bufferReader = new BufferedReader(new InputStreamReader(content));
1695       while ((tempLine = bufferReader.readLine()) != null) {
1696         stringContent.append(tempLine).append("\n");
1697       }
1698 
1699       HelpPage syntaxPage = wStore.createHelpPage();
1700       String realName = name.replace("/", "");
1701       syntaxPage.setName(realName + type);
1702       parentPage.addPublicPage(syntaxPage);
1703       AttachmentImpl pageContent = syntaxPage.getContent();
1704       syntaxPage.setTitle(realName + type);
1705       pageContent.setText(stringContent.toString());
1706       syntaxPage.setSyntax(name);
1707       syntaxPage.setNonePermission();
1708       return syntaxPage;
1709     } catch (IOException e) {
1710       throw new WikiException("Cannot create help page " + type, e);
1711     } finally {
1712       if (content != null) {
1713         try {
1714           content.close();
1715         } catch (IOException e) {
1716           log.error("Cannot close input stream of help page " + type + " - Cause : " + e.getMessage(), e);
1717         }
1718       }
1719       if (bufferReader != null) {
1720         try {
1721           bufferReader.close();
1722         } catch (IOException e) {
1723           log.error("Cannot close buffer reader of help page " + type + " - Cause : " + e.getMessage(), e);
1724         }
1725       }
1726       mowService.stopSynchronization(created);
1727     }
1728 
1729   }
1730 
1731   private boolean isDuplicateTitle(List<JCRSearchResult> list, JCRSearchResult result) {
1732     for (JCRSearchResult searchResult : list) {
1733       if (result.getTitle().equals(searchResult.getTitle())) {
1734         return true;
1735       }
1736     } 
1737     return false;
1738   }
1739 
1740   private void updateAllPagesPermissions(String wikiType, String wikiOwner, HashMap<String, String[]> permMap) throws WikiException {
1741     boolean created = mowService.startSynchronization();
1742 
1743     try {
1744       PageImpl page = fetchWikiImpl(wikiType, wikiOwner).getWikiHome();
1745       Queue<PageImpl> queue = new LinkedList<>();
1746       queue.add(page);
1747       while (queue.peek() != null) {
1748         PageImpl p = queue.poll();
1749         if (!p.getOverridePermission()) {
1750           p.setPermission(permMap);
1751           p.setUpdateAttachmentMixin(null);
1752         }
1753         Iterator<PageImpl> iter = p.getChildPages().values().iterator();
1754         while (iter.hasNext()) {
1755           queue.add(iter.next());
1756         }
1757       }
1758     } finally {
1759       mowService.stopSynchronization(created);
1760     }
1761   }
1762 
1763   private Page getPageWithLinkEntry(LinkEntry entry) throws WikiException {
1764     boolean created = mowService.startSynchronization();
1765 
1766     try {
1767       String linkEntryAlias = entry.getAlias();
1768       String[] splits = linkEntryAlias.split("@");
1769       String wikiType = splits[0];
1770       String wikiOwner = splits[1];
1771       String pageId = linkEntryAlias.substring((wikiType + "@" + wikiOwner + "@").length());
1772       Page page = getPageOfWikiByName(wikiType, wikiOwner, pageId);
1773 
1774       return page;
1775     } finally {
1776       mowService.stopSynchronization(created);
1777     }
1778   }
1779 
1780   private String getLinkEntryName(String wikiType, String wikiOwner, String pageId) {
1781     if (PortalConfig.GROUP_TYPE.equals(wikiType)) {
1782       wikiOwner = wikiOwner.replace("/", "-");
1783     }
1784     return wikiType + "@" + wikiOwner + "@" + pageId;
1785   }
1786 
1787   private String getLinkEntryAlias(String wikiType, String wikiOwner, String pageId) {
1788     return wikiType + "@" + wikiOwner + "@" + pageId;
1789   }
1790 
1791   private Object findByPath(String path, String objectNodeType) throws WikiException {
1792     String relPath = path;
1793     if (relPath.startsWith("/")) {
1794       relPath = relPath.substring(1);
1795     }
1796 
1797     boolean created = mowService.startSynchronization();
1798 
1799     try {
1800       Object object = null;
1801       if (WikiNodeType.WIKI_PAGE.equals(objectNodeType)) {
1802         object = mowService.getSession().findByPath(PageImpl.class, relPath);
1803       } else if (WikiNodeType.WIKI_ATTACHMENT.equals(objectNodeType)) {
1804         object = mowService.getSession().findByPath(AttachmentImpl.class, relPath);
1805       } else if (WikiNodeType.WIKI_TEMPLATE.equals(objectNodeType)) {
1806         object = mowService.getSession().findByPath(Template.class, relPath);
1807       }
1808 
1809       return object;
1810     } finally {
1811       mowService.stopSynchronization(created);
1812     }
1813   }
1814   
1815   private JCRSearchResult getResult(Row row, WikiSearchData data) throws WikiException {
1816     boolean created = mowService.startSynchronization();
1817 
1818     try {
1819       String type = row.getValue(WikiNodeType.Definition.PRIMARY_TYPE).getString();
1820       String path = row.getValue(WikiNodeType.Definition.PATH).getString();
1821 
1822       JCRSearchResult result = new JCRSearchResult();
1823 
1824       long score = row.getValue("jcr:score").getLong();
1825       Calendar createdDate = GregorianCalendar.getInstance();
1826       Calendar updatedDate = GregorianCalendar.getInstance();
1827       PageImpl page;
1828       if (WikiNodeType.WIKI_ATTACHMENT.equals(type) || WikiNodeType.WIKI_ATTACHMENT_CONTENT.equals(type)) {
1829         // Transform to Attachment result
1830         result.setType(SearchResultType.ATTACHMENT);
1831         if (!path.endsWith(WikiNodeType.Definition.CONTENT)) {
1832           result.setType(SearchResultType.PAGE_CONTENT);
1833           AttachmentImpl searchAtt = (AttachmentImpl) findByPath(path, WikiNodeType.WIKI_ATTACHMENT);
1834           updatedDate = searchAtt.getUpdatedDate();
1835           page = searchAtt.getParentPage();
1836           createdDate.setTime(page.getCreatedDate());
1837           result.setAttachmentName(searchAtt.getName());
1838         } else {
1839           result.setType(SearchResultType.ATTACHMENT);
1840           String pagePath = path.substring(0, path.lastIndexOf("/" + WikiNodeType.Definition.CONTENT));
1841           result.setType(SearchResultType.PAGE_CONTENT);
1842           page = (PageImpl) findByPath(pagePath, WikiNodeType.WIKI_PAGE);
1843           updatedDate.setTime(page.getUpdatedDate());
1844           createdDate.setTime(page.getCreatedDate());
1845         }
1846       } else if (WikiNodeType.WIKI_PAGE.equals(type)) {
1847         result.setType(SearchResultType.PAGE);
1848         page = (PageImpl) findByPath(path, type);
1849         updatedDate.setTime(page.getUpdatedDate());
1850         createdDate.setTime(page.getCreatedDate());
1851       } else {
1852         return null;
1853       }
1854 
1855       if (page == null || !page.hasPermission(PermissionType.VIEWPAGE)) {
1856         return null;
1857       }
1858 
1859       result.setWikiType(page.getWiki().getType());
1860       result.setWikiOwner(page.getWiki().getOwner());
1861       result.setPageName(page.getName());
1862       result.setTitle(page.getTitle());
1863       result.setPath(path);
1864       result.setCreatedDate(createdDate);
1865       result.setUpdatedDate(updatedDate);
1866       result.setUrl(page.getURL());
1867       result.setScore(score);
1868 
1869       //get the excerpt from row result
1870       result.setExcerpt(getExcerpt(row, type));
1871 
1872       return result;
1873     } catch(RepositoryException e) {
1874       throw new WikiException("Cannot get search result", e);
1875     } finally {
1876       mowService.stopSynchronization(created);
1877     }
1878   }
1879 
1880   private void processCircularRename(LinkEntry entry, LinkEntry newEntry) {
1881     boolean created = mowService.startSynchronization();
1882 
1883     try {
1884       // Check circular rename
1885       boolean isCircular = true;
1886       int circularFlag = CIRCULAR_RENAME_FLAG;// To deal with old circular data if it is existed
1887       LinkEntry checkEntry = newEntry;
1888       while (!checkEntry.equals(entry) && circularFlag > 0) {
1889         checkEntry = checkEntry.getNewLink();
1890         if (checkEntry == null || (checkEntry.equals(checkEntry.getNewLink()) && !checkEntry.equals(entry))) {
1891           isCircular = false;
1892           break;
1893         }
1894         circularFlag--;
1895       }
1896       if (!isCircular || circularFlag == 0) {
1897         entry.setNewLink(newEntry);
1898       } else {
1899         LinkEntry nextEntry = newEntry.getNewLink();
1900         while (!nextEntry.equals(newEntry)) {
1901           LinkEntry deletedEntry = nextEntry;
1902           nextEntry = nextEntry.getNewLink();
1903           if (!nextEntry.equals(deletedEntry)) {
1904             deletedEntry.remove();
1905           } else {
1906             deletedEntry.remove();
1907             break;
1908           }
1909         }
1910       }
1911       newEntry.setNewLink(newEntry);
1912     } finally {
1913       mowService.stopSynchronization(created);
1914     }
1915   }
1916 
1917   /**
1918    * gets except of row result based on specific properties, but all to get nice excerpt
1919    * @param row the result row
1920    * @param type the result type
1921    * @return the excerpt
1922    * @throws ItemNotFoundException
1923    * @throws RepositoryException
1924    */
1925   private String getExcerpt(Row row, String type) throws RepositoryException {
1926     boolean created = mowService.startSynchronization();
1927 
1928     try {
1929       StringBuilder ret = new StringBuilder();
1930       String[] properties = (WikiNodeType.WIKI_PAGE_CONTENT.equals(type) || WikiNodeType.WIKI_ATTACHMENT.equals(type)) ?
1931                             new String[]{"."} :
1932                             new String[]{"title", "url"};
1933       for (String prop : properties) {
1934         Value excerptValue = row.getValue("rep:excerpt(" + prop + ")");
1935         if (excerptValue != null) {
1936           ret.append(excerptValue.getString()).append("...");
1937         }
1938       }
1939       if (ret.length() > MAX_EXCERPT_LENGTH) {
1940         return ret.substring(0, MAX_EXCERPT_LENGTH) + "...";
1941       }
1942 
1943       return ret.toString();
1944     } finally {
1945       mowService.stopSynchronization(created);
1946     }
1947   }
1948   
1949   private SearchResult getResult(Node node)throws RepositoryException, IOException {
1950     boolean created = mowService.startSynchronization();
1951 
1952     try {
1953       SearchResult result = new SearchResult() ;
1954       result.setPageName(node.getName()) ;
1955       String title = node.getProperty(WikiNodeType.Definition.TITLE).getString();
1956       InputStream data = node.getNode(WikiNodeType.Definition.CONTENT).getNode(WikiNodeType.Definition.ATTACHMENT_CONTENT).getProperty(WikiNodeType.Definition.DATA).getStream();
1957       byte[] bytes = IO.getBytes(data);
1958       String content = new String(bytes, "UTF-8");
1959       if(content.length() > 100) content = content.substring(0, 100) + "...";
1960       result.setExcerpt(content) ;
1961       result.setTitle(title) ;
1962 
1963       return result ;
1964     } finally {
1965       mowService.stopSynchronization(created);
1966     }
1967   }
1968   
1969   private boolean isContains(List<JCRSearchResult> list, JCRSearchResult result) throws WikiException {
1970     boolean created = mowService.startSynchronization();
1971 
1972     try {
1973       boolean contains = false;
1974       AttachmentImpl att = null;
1975       PageImpl page = null;
1976       if (WikiNodeType.WIKI_ATTACHMENT.equals(result.getType())) {
1977         att = (AttachmentImpl) findByPath(result.getPath(), WikiNodeType.WIKI_ATTACHMENT);
1978       } else if (WikiNodeType.WIKI_ATTACHMENT_CONTENT.equals(result.getType())) {
1979         String attPath = result.getPath().substring(0, result.getPath().lastIndexOf("/"));
1980         att = (AttachmentImpl) findByPath(attPath, WikiNodeType.WIKI_ATTACHMENT);
1981       } else if(WikiNodeType.WIKI_PAGE.equals(result.getType()) || WikiNodeType.WIKI_HOME.equals(result.getType())){
1982         page = (PageImpl) findByPath(result.getPath(), WikiNodeType.WIKI_PAGE);
1983       } else if (WikiNodeType.WIKI_PAGE_CONTENT.equals(result.getType())) {
1984         att = (AttachmentImpl) findByPath(result.getPath(), WikiNodeType.WIKI_ATTACHMENT);
1985         page = att.getParentPage();
1986       }
1987       if (att != null || page != null) {
1988         Iterator<JCRSearchResult> iter = list.iterator();
1989         while (iter.hasNext()) {
1990           JCRSearchResult child = iter.next();
1991           if (WikiNodeType.WIKI_ATTACHMENT.equals(child.getType()) || WikiNodeType.WIKI_PAGE_CONTENT.equals(child.getType())) {
1992             AttachmentImpl tempAtt = (AttachmentImpl) findByPath(child.getPath(), WikiNodeType.WIKI_ATTACHMENT);
1993             if (att != null && att.equals(tempAtt)) {
1994               // Merge data
1995               if (child.getExcerpt()==null && result.getExcerpt()!=null ){
1996                 child.setExcerpt(result.getExcerpt());
1997               }
1998               contains = true;
1999             }
2000             if (page != null && page.getName().equals(tempAtt.getParentPage())) {
2001               contains = true;
2002             }
2003           } else if (WikiNodeType.WIKI_PAGE.equals(child.getType())) {
2004             if (page != null && page.getPath().equals(child.getPath())) {
2005               iter.remove();
2006               contains = false;
2007             }
2008           }
2009         }
2010       }
2011 
2012       return contains;
2013     } finally {
2014       mowService.stopSynchronization(created);
2015     }
2016   }
2017 
2018   @Override
2019   public List<TemplateSearchResult> searchTemplate(TemplateSearchData data) throws WikiException {
2020     boolean created = mowService.startSynchronization();
2021 
2022     try {
2023       ChromatticSession session = mowService.getSession();
2024 
2025       List<TemplateSearchResult> resultList = new ArrayList<>();
2026       String statement = new JCRTemplateSearchQueryBuilder(data).getStatementForSearchingTitle();
2027       Query q = ((ChromatticSessionImpl) session).getDomainSession().getSessionWrapper().createQuery(statement);
2028       QueryResult result = q.execute();
2029       RowIterator iter = result.getRows();
2030       while (iter.hasNext()) {
2031         TemplateSearchResult tempResult = getTemplateResult(iter.nextRow(), data);
2032         resultList.add(tempResult);
2033       }
2034 
2035       return resultList;
2036     } catch(RepositoryException e) {
2037       throw new WikiException("Cannot search templates in wiki " + data.getWikiType() + ":" + data.getWikiOwner(), e);
2038     } finally {
2039       mowService.stopSynchronization(created);
2040     }
2041   }
2042 
2043   private TemplateSearchResult getTemplateResult(Row row, TemplateSearchData data) throws WikiException {
2044     boolean created = mowService.startSynchronization();
2045 
2046     try {
2047       String path = row.getValue(WikiNodeType.Definition.PATH).getString();
2048       String title = (row.getValue(WikiNodeType.Definition.TITLE) == null ? null : row.getValue(WikiNodeType.Definition.TITLE).getString());
2049 
2050       TemplateImpl templateImpl = (TemplateImpl) findByPath(path, WikiNodeType.WIKI_PAGE);
2051       String description = templateImpl.getDescription();
2052       TemplateSearchResult result = new TemplateSearchResult(data.getWikiType(),
2053               data.getWikiOwner(),
2054               templateImpl.getName(),
2055               title,
2056               SearchResultType.TEMPLATE,
2057               null,
2058               null,
2059               description);
2060       return result;
2061     } catch(RepositoryException e) {
2062       throw new WikiException("Cannot get template", e);
2063     } finally {
2064       mowService.stopSynchronization(created);
2065     }
2066   }
2067 
2068   /**
2069    * Fetch a WikiImpl object with Chrommatic
2070    * @param wikiType
2071    * @param wikiOwner
2072    * @return
2073    */
2074   private WikiImpl fetchWikiImpl(String wikiType, String wikiOwner) throws WikiException {
2075     boolean created = mowService.startSynchronization();
2076 
2077     try {
2078       WikiStoreImpl wStore = (WikiStoreImpl) mowService.getWikiStore();
2079       WikiImpl wiki = null;
2080       if (PortalConfig.PORTAL_TYPE.equals(wikiType)) {
2081         WikiContainer<PortalWiki> portalWikiContainer = wStore.getWikiContainer(WikiType.PORTAL);
2082         wiki = portalWikiContainer.getWiki(wikiOwner);
2083       } else if (PortalConfig.GROUP_TYPE.equals(wikiType)) {
2084         WikiContainer<GroupWiki> groupWikiContainer = wStore.getWikiContainer(WikiType.GROUP);
2085         wiki = groupWikiContainer.getWiki(wikiOwner);
2086       } else if (PortalConfig.USER_TYPE.equals(wikiType)) {
2087         WikiContainer<UserWiki> userWikiContainer = wStore.getWikiContainer(WikiType.USER);
2088         wiki = userWikiContainer.getWiki(wikiOwner);
2089       }
2090 
2091       return wiki;
2092     } finally {
2093       mowService.stopSynchronization(created);
2094     }
2095   }
2096 
2097   /**
2098    * Fetch a PageImpl object with Chrommatic
2099    * @return
2100    */
2101   private PageImpl fetchPageImpl(Page page) throws WikiException {
2102     boolean created = mowService.startSynchronization();
2103 
2104     try {
2105       PageImpl wikiPage = null;
2106       ChromatticSession session = mowService.getSession();
2107 
2108       if(page.getId() != null && !StringUtils.isEmpty(page.getId())) {
2109         wikiPage = session.findById(PageImpl.class, page.getId());
2110       } else {
2111         if (WikiConstants.WIKI_HOME_NAME.equals(page.getName())) {
2112           WikiImpl wikiImpl = fetchWikiImpl(page.getWikiType(), page.getWikiOwner());
2113           wikiPage = wikiImpl.getWikiHome();
2114         } else {
2115           WikiSearchData searchData = new WikiSearchData(page.getWikiType(), page.getWikiOwner(), Text.escapeIllegalJcrChars(page.getName()));
2116           JCRWikiSearchQueryBuilder queryBuilder = new JCRWikiSearchQueryBuilder(searchData);
2117           String statement = queryBuilder.getPageConstraint();
2118 
2119           if (statement != null) {
2120             Iterator<PageImpl> result = session.createQueryBuilder(PageImpl.class)
2121                     .where(statement)
2122                     .get()
2123                     .objects();
2124             if (result.hasNext()) {
2125               wikiPage = result.next();
2126             }
2127           }
2128           // TODO: still don't know reason but following code is necessary.
2129           if (wikiPage != null) {
2130             String path = wikiPage.getPath();
2131             if (path.startsWith("/")) {
2132               path = path.substring(1, path.length());
2133             }
2134             wikiPage = session.findByPath(PageImpl.class, path);
2135           }
2136           if (wikiPage != null) {
2137           }
2138         }
2139       }
2140 
2141       return wikiPage;
2142     } finally {
2143       mowService.stopSynchronization(created);
2144     }
2145   }
2146 
2147   private Wiki convertWikiImplToWiki(WikiImpl wikiImpl) throws WikiException {
2148     Wiki wiki = null;
2149     if(wikiImpl != null) {
2150       boolean created = mowService.startSynchronization();
2151 
2152       try {
2153         wiki = new Wiki();
2154         wiki.setId(wikiImpl.getName());
2155         wiki.setType(wikiImpl.getType());
2156         wiki.setOwner(wikiImpl.getOwner());
2157         Page wikiHome = convertPageImplToPage(wikiImpl.getWikiHome());
2158         wikiHome.setWikiId(wikiImpl.getName());
2159         wikiHome.setWikiType(wikiImpl.getType());
2160         wikiHome.setWikiOwner(wikiImpl.getOwner());
2161         wiki.setWikiHome(wikiHome);
2162         wiki.setPermissions(JCRUtils.convertWikiPermissionsToPermissionEntryList(wikiImpl.getWikiPermissions()));
2163         wiki.setDefaultPermissionsInited(wikiImpl.getDefaultPermissionsInited());
2164         PreferencesImpl preferencesImpl = wikiImpl.getPreferences();
2165         if (preferencesImpl != null) {
2166           WikiPreferencesSyntax wikiPreferencesSyntax = new WikiPreferencesSyntax();
2167           PreferencesSyntax preferencesSyntax = preferencesImpl.getPreferencesSyntax();
2168           if (preferencesSyntax != null) {
2169             wikiPreferencesSyntax.setDefaultSyntax(preferencesSyntax.getDefaultSyntax());
2170             wikiPreferencesSyntax.setAllowMultipleSyntaxes(preferencesSyntax.getAllowMutipleSyntaxes());
2171           }
2172           WikiPreferences wikiPreferences = new WikiPreferences();
2173           wikiPreferences.setPath(preferencesImpl.getPath());
2174           wikiPreferences.setWikiPreferencesSyntax(wikiPreferencesSyntax);
2175           wiki.setPreferences(wikiPreferences);
2176         }
2177       } finally {
2178         mowService.stopSynchronization(created);
2179       }
2180     }
2181     return wiki;
2182   }
2183 
2184   /**
2185    * Utility method to convert PageImpl object to Page object
2186    * @param pageImpl PageImpl object to convert
2187    * @return
2188    * @throws WikiException
2189    */
2190   private Page convertPageImplToPage(PageImpl pageImpl) throws WikiException {
2191     Page page = null;
2192     if(pageImpl != null) {
2193       boolean created = mowService.startSynchronization();
2194 
2195       try {
2196         page = new Page();
2197         try {
2198           page.setId(pageImpl.getID());
2199         } catch(RepositoryException e) {
2200           throw new WikiException("Cannot get page id", e);
2201         }
2202         WikiImpl wiki = pageImpl.getWiki();
2203         if(wiki != null) {
2204           page.setWikiId(wiki.getName());
2205           page.setWikiType(wiki.getWikiType().toString().toLowerCase());
2206           page.setWikiOwner(wiki.getOwner());
2207         }
2208         page.setOwner(pageImpl.getOwner());
2209         page.setName(pageImpl.getName());
2210         page.setTitle(pageImpl.getTitle());
2211         page.setAuthor(pageImpl.getAuthor());
2212         page.setUrl(pageImpl.getURL());
2213         page.setCreatedDate(pageImpl.getCreatedDate());
2214         page.setUpdatedDate(pageImpl.getUpdatedDate());
2215         page.setComment(pageImpl.getComment());
2216         page.setContent(pageImpl.getContent().getText());
2217         page.setSyntax(pageImpl.getSyntax());
2218         page.setPermissions(JCRUtils.convertToPermissionEntryList(pageImpl.getPermission()));
2219         page.setActivityId(pageImpl.getActivityId());
2220       } finally {
2221         mowService.stopSynchronization(created);
2222       }
2223     }
2224     return page;
2225   }
2226 
2227   /**
2228    * Utility method to convert DraftPageImpl object to DraftPage object
2229    * @param draftPageImpl DraftPageImpl object to convert
2230    * @return
2231    * @throws WikiException
2232    */
2233   private DraftPage convertDraftPageImplToDraftPage(DraftPageImpl draftPageImpl) throws WikiException {
2234     DraftPage draftPage = null;
2235     if(draftPageImpl != null) {
2236       boolean created = mowService.startSynchronization();
2237 
2238       try {
2239         draftPage = new DraftPage();
2240         try {
2241           draftPage.setId(draftPageImpl.getID());
2242         } catch(RepositoryException e) {
2243           throw new WikiException("Cannot get draft page id", e);
2244         }
2245         draftPage.setOwner(draftPageImpl.getOwner());
2246         draftPage.setName(draftPageImpl.getName());
2247         draftPage.setAuthor(draftPageImpl.getAuthor());
2248         draftPage.setTitle(draftPageImpl.getTitle());
2249         draftPage.setUrl(draftPageImpl.getURL());
2250         draftPage.setCreatedDate(draftPageImpl.getCreatedDate());
2251         draftPage.setUpdatedDate(draftPageImpl.getUpdatedDate());
2252         draftPage.setComment(draftPageImpl.getComment());
2253         draftPage.setContent(draftPageImpl.getContent().getText());
2254         draftPage.setSyntax(draftPageImpl.getSyntax());
2255         draftPage.setPermissions(JCRUtils.convertToPermissionEntryList(draftPageImpl.getPermission()));
2256 
2257         draftPage.setTargetPageId(draftPageImpl.getTargetPage());
2258         draftPage.setTargetPageRevision(draftPageImpl.getTargetRevision());
2259         draftPage.setNewPage(draftPageImpl.isNewPage());
2260       } finally {
2261         mowService.stopSynchronization(created);
2262       }
2263     }
2264     return draftPage;
2265   }
2266 
2267   private Attachment convertAttachmentImplToAttachment(AttachmentImpl attachmentImpl) throws WikiException {
2268     Attachment attachment = null;
2269     if(attachmentImpl != null) {
2270       boolean created = mowService.startSynchronization();
2271 
2272       try {
2273         attachment = new Attachment();
2274         attachment.setName(attachmentImpl.getName());
2275         attachment.setTitle(attachmentImpl.getTitle());
2276         attachment.setFullTitle(attachmentImpl.getFullTitle());
2277         attachment.setCreator(attachmentImpl.getCreator());
2278         attachment.setCreatedDate(attachmentImpl.getCreatedDate());
2279         attachment.setUpdatedDate(attachmentImpl.getUpdatedDate());
2280         attachment.setContent(attachmentImpl.getContentResource().getData());
2281         attachment.setMimeType(attachmentImpl.getContentResource().getMimeType());
2282         attachment.setPermissions(JCRUtils.convertToPermissionEntryList(attachmentImpl.getPermission()));
2283         attachment.setDownloadURL(attachmentImpl.getDownloadURL());
2284         attachment.setWeightInBytes(attachmentImpl.getWeightInBytes());
2285       } finally {
2286         mowService.stopSynchronization(created);
2287       }
2288     }
2289     return attachment;
2290   }
2291 
2292   private Template convertTemplateImplToTemplate(TemplateImpl templateImpl) throws WikiException {
2293     Template template = null;
2294     if(templateImpl != null) {
2295       boolean created = mowService.startSynchronization();
2296 
2297       try {
2298         template = new Template();
2299         template.setName(templateImpl.getName());
2300         template.setTitle(templateImpl.getTitle());
2301         template.setDescription(templateImpl.getDescription());
2302         template.setContent(templateImpl.getContent().getText());
2303       } finally {
2304         mowService.stopSynchronization(created);
2305       }
2306     }
2307     return template;
2308   }
2309 }