WikiDataInjector.java

/*
 * Copyright (C) 2003-2011 eXo Platform SAS.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see<http://www.gnu.org/licenses/>.
 */
package org.exoplatform.wiki.bench;

import org.exoplatform.container.xml.InitParams;
import org.exoplatform.services.bench.DataInjector;
import org.exoplatform.services.jcr.util.IdGenerator;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.wiki.WikiException;
import org.exoplatform.wiki.mow.api.*;
import org.exoplatform.wiki.resolver.TitleResolver;
import org.exoplatform.wiki.service.IDType;
import org.exoplatform.wiki.service.WikiService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
 * Plugin for injecting Wiki data.
 */
public class WikiDataInjector extends DataInjector {
  
  private HashMap<String, Integer> prefixesIndex = new HashMap<String, Integer>();
  
  public static final String       QUANTITY      = "q";

  public static final String       PREFIX        = "pre";

  public static final String       PAGE_SIZE     = "mP";

  public static final String       ATTACH_SIZE   = "maxAtt";

  public static final String       WIKI_OWNER    = "wo";

  public static final String       WIKI_TYPE     = "wt";

  public static final String       RECURSIVE     = "rcs";

  public static final String       PERMISSION    = "perm";
  
  public enum CONSTANTS {
    TYPE("type"), DATA("data"), PERM("perm");
    private final String name;

    CONSTANTS(String name) {
      this.name = name;
    }
    
    public String getName() {
      return name;
    }
  };
  
  public static final String             ARRAY_SPLIT   = ",";
  
  private static Log         log             = ExoLogger.getLogger(WikiDataInjector.class);
  
  private WikiService wikiService;

  public WikiDataInjector(WikiService wikiService,  InitParams params) {
    this.wikiService = wikiService;
  }
  
  private List<Integer> readQuantities(HashMap<String, String> queryParams) {
    String quantitiesString = queryParams.get(QUANTITY);
    List<Integer> quantities = new LinkedList<Integer>();
    for (String s : quantitiesString.split(ARRAY_SPLIT)) {
      if (s.length() > 0) {
        int quantity = Integer.parseInt(s.trim());
        quantities.add(quantity);
      }
    }
    return quantities;
  }
  
  private List<String> readPrefixes(HashMap<String, String> queryParams) {
    String prefixesString = queryParams.get(PREFIX);
    List<String> prefixes = new LinkedList<String>();
    for (String s : prefixesString.split(ARRAY_SPLIT)) {
      if (s.length() > 0) {
        prefixes.add(s);
      }
    }
    return prefixes;
  }
  
  private String readWikiOwner(HashMap<String, String> queryParams) {
    return queryParams.get(WIKI_OWNER);
  }
  
  private String readWikiType(HashMap<String, String> queryParams) {
    return queryParams.get(WIKI_TYPE);
  }

  private int readMaxAttachmentIfExist(HashMap<String, String> queryParams) {
    String value = queryParams.get(ATTACH_SIZE);
    if (value != null)
      return Integer.parseInt(value);
    else return 0;
  }
  
  private int readMaxPagesIfExist(HashMap<String, String> queryParams) {
    String value = queryParams.get(PAGE_SIZE);
    if (value != null)
      return Integer.parseInt(value);
    else return 0;
  }
  
  private boolean readRecursive(HashMap<String, String> queryParams) {
    boolean recursive = false;
    String value = queryParams.get(RECURSIVE);
    if (value != null) {
      recursive = Boolean.parseBoolean(value);
    }
    return recursive;
  }
  
  private List<Permission> readPermission(HashMap<String, String> queryParams) {
    String permString = queryParams.get(PERMISSION);
    List<Permission> permissions = new LinkedList<>();
    boolean flag = Integer.parseInt(permString.substring(0, 1)) > 0;
    if (flag) // check read permission
      permissions.add(new Permission(PermissionType.VIEWPAGE, true));
    
    flag = Integer.parseInt(permString.substring(1, 2)) > 0;
    if (flag) { // check edit permission
      permissions.add(new Permission(PermissionType.EDITPAGE, true));
    }
    return permissions;
  }
  
  private List<PermissionEntry> readPermissions(HashMap<String, String> queryParams) {
    List<PermissionEntry> permissionEntries = new ArrayList<>();
    Permission[] permissions = readPermission(queryParams).toArray(new Permission[] {});
    for (String identity : readGroupsIfExist(queryParams)) {
      permissionEntries.add(new PermissionEntry(identity, "", IDType.GROUP, permissions));
    }
    for (String identity : readUsersIfExist(queryParams)) {
      permissionEntries.add(new PermissionEntry(identity, "", IDType.USER, permissions));
    }
    for (String identity : readMembershipIfExist(queryParams)) {
      permissionEntries.add(new PermissionEntry(identity, "", IDType.MEMBERSHIP, permissions));
    }
    return permissionEntries;
  }
  
   
  private String makeTitle(String prefix, int order) {
    return new StringBuilder(prefix).append("_").append(order).toString();
  }
  
  private Page createPage(Page father, String title, String wikiOwner, String wikiType, int attSize) throws WikiException {
    Page newPage = new Page();
    newPage.setTitle(title);
    newPage.setContent(title + "_content " + randomParagraphs(10));
    Page page = wikiService.createPage(new Wiki(wikiType, wikiOwner), father.getName(), newPage);
    if (attSize > 0) {
      Attachment attachment = new Attachment();
      String attachmentTitle = "att" + IdGenerator.generate();
      attachment.setName(attachmentTitle + ".txt");
      attachment.setTitle(attachmentTitle);
      int sizeInBytes = attSize * 1024;
      StringBuilder content = new StringBuilder(sizeInBytes);
      content.append(attachment.getName()).append("_content ");
      while(content.length() <= sizeInBytes) {
        content.append(randomParagraphs(1));
      }
      attachment.setContent(content.toString().getBytes());
      attachment.setMimeType("text/plain");
      wikiService.addAttachmentToPage(attachment, page);
    }
    return page;
  }
  
  private void generatePages(List<Integer> quantities,
                             List<String> prefixes,
                             int depth,
                             int attSize,
                             int totalPages,
                             String wikiOwner,
                             String wikiType,
                             Page father) throws WikiException {
    int numOfPages = quantities.get(depth).intValue();
    String prefix = prefixes.get(depth);
    // Achieve 'prefix' pages
    List<Page> childrenPagesWithPrefix = getPagesByPrefix(prefix, father);
    for(Page childPage : childrenPagesWithPrefix) {
      log.info(String.format("%1$" + ((depth + 1) * 4) + "s Process page: %2$s in depth %3$s .......", " ", childPage.getTitle(), depth + 1));
      if (depth < quantities.size() - 1) {
        generatePages(quantities, prefixes, depth + 1, attSize, totalPages, wikiOwner, wikiType, childPage);
      }
    }
    int prefixSize = childrenPagesWithPrefix.size();
    // Check and add more pages to be equals to numOfPages
    if (prefixSize < numOfPages) {
      for (int i = prefixSize; i < numOfPages; i++) {
        Integer index = prefixesIndex.get(prefix);
        if (index == null) {
          index = i;
        }
        index++;
        prefixesIndex.put(prefix, index);
        Page page = createPage(father, makeTitle(prefix, index), wikiOwner, wikiType, attSize);
        log.info(String.format("%1$" + ((depth + 1)*4) + "s Process page: %2$s in depth %3$s .......", " ", page.getTitle(), depth + 1));
        if (depth < quantities.size() - 1) {
          generatePages(quantities, prefixes, depth + 1, attSize, totalPages, wikiOwner, wikiType, page);
        }
      }
    }
  }
  
  private void injectData(HashMap<String, String> queryParams) throws WikiException {
    log.info("Start to inject data ............... ");
    List<Integer> quantities = readQuantities(queryParams);
    List<String> prefixes = readPrefixes(queryParams);
    int attSize = readMaxAttachmentIfExist(queryParams);
    int totalPages = readMaxPagesIfExist(queryParams);
    String wikiOwner = readWikiOwner(queryParams);
    String wikiType = readWikiType(queryParams);    
    generatePages(quantities, prefixes, 0, attSize, totalPages, wikiOwner, wikiType, wikiService.getWikiByTypeAndOwner(wikiType, wikiOwner).getWikiHome());
    log.info("Injecting data has been done successfully!");
  }
  
  private void grantPermission(List<Integer> quantities, List<String> prefixes, int depth, Page father, String wikiOwner, String wikiType, List<PermissionEntry> permissions, boolean isRecursive) throws WikiException {
    int numOfPages = quantities.get(depth).intValue();
    String prefix = prefixes.get(depth);
    List<Page> childrenPagesWithPrefix = getPagesByPrefix(prefix, father);
    for(Page childPage : childrenPagesWithPrefix) {
      if(numOfPages-- <= 0) {
        break;
      }
      if (isRecursive || depth == (quantities.size() - 1)) {
        log.info(String.format("Grant permissions %1$s for page: %2$s", permissionsToString(permissions), childPage.getTitle()));
        childPage.setPermissions(permissions);
        wikiService.updatePage(childPage, null);
        if (depth < quantities.size() - 1) {
          grantPermission(quantities, prefixes, depth + 1, childPage, wikiOwner, wikiType, permissions, isRecursive);
        }
      }
    }
  }
  
  private String permissionsToString(List<PermissionEntry> permissions) {
    StringBuilder sb = new StringBuilder();
    sb.append("(");
    for(PermissionEntry permissionEntry : permissions) {
      Permission[] value = permissionEntry.getPermissions();
      sb.append("[" + permissionEntry.getIdType() + ":" + permissionEntry.getId() + ":");
      for (Permission permission : value) {
        if(permission.isAllowed()) {
          sb.append(permission.getPermissionType().toString()).append(",");
        }
      }
      sb.delete(sb.length() - 1, sb.length());
      sb.append("],");
    }
    if (sb.length() > 1) sb.delete(sb.length() - 1, sb.length());
    sb.append(")");
    return sb.toString();
  }
  
  private void grantPermission(HashMap<String, String> queryParams) throws WikiException {
    log.info("Start to grant permissions ............... ");
    List<Integer> quantities = readQuantities(queryParams);
    List<String> prefixes = readPrefixes(queryParams);
    String wikiOwner = readWikiOwner(queryParams);
    String wikiType = readWikiType(queryParams);
    List<PermissionEntry> permissions = readPermissions(queryParams);
    boolean isRecursive = readRecursive(queryParams);    
    grantPermission(quantities, prefixes, 0, wikiService.getWikiByTypeAndOwner(wikiType, wikiOwner).getWikiHome(), wikiOwner, wikiType, permissions, isRecursive);
    log.info("Permissions have been granted successfully!");
  }
  
  @Override
  public void inject(HashMap<String, String> queryParams) throws WikiException {
    String type = queryParams.get(CONSTANTS.TYPE.getName());
    if (CONSTANTS.DATA.getName().equalsIgnoreCase(type)) {
      injectData(queryParams);
    } else if (CONSTANTS.PERM.getName().equalsIgnoreCase(type)) {
      grantPermission(queryParams);
    }
  }

  @Override
  public void reject(HashMap<String, String> params) throws WikiException {
    log.info("Start to reject data ............. ");
    String wikiOwner = readWikiOwner(params);
    String wikiType = readWikiType(params);
    List<Integer> quantities = readQuantities(params);
    List<String> prefixes = readPrefixes(params);
    int numOfPages = quantities.get(0);
    String prefix = prefixes.get(0);    
      for (int i = 0; i < numOfPages; i++) {
        String title = makeTitle(prefix, i + 1);
        String pageId = TitleResolver.getId(title, true);
        if (wikiService.getPageOfWikiByName(wikiType, wikiOwner, pageId) != null) {
          if (log.isInfoEnabled()) 
            log.info(String.format("    Delete page: %1$s and its children ...", title));
          wikiService.deletePage(wikiType, wikiOwner, pageId);
        }
      }
    
    log.info("Rejecting data has been done successfully!");
  }

  public List<Page> getPagesByPrefix(String prefix, Page father) throws WikiException {
    List<Page> childrenPagesWithPrefix = new ArrayList<>();
    List<Page> childrenPages = wikiService.getChildrenPageOf(father);
    for(Page childPage : childrenPages) {
      if(childPage.getTitle() != null && childPage.getTitle().startsWith(prefix)) {
        childrenPagesWithPrefix.add(childPage);
      }
    }

    return childrenPagesWithPrefix;
  }

  @Override
  public Log getLog() {
    return log;
  }

  @Override
  public Object execute(HashMap<String, String> params) throws WikiException {
    return new Object();
  }

}