All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.usergrid.tools.DupOrgRepair Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright 2012 Apigee Corporation
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package org.usergrid.tools;

import java.io.FileWriter;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.usergrid.management.OrganizationInfo;
import org.usergrid.management.UserInfo;
import org.usergrid.persistence.Entity;
import org.usergrid.persistence.EntityManager;
import org.usergrid.persistence.Query;
import org.usergrid.persistence.Results;
import org.usergrid.persistence.SimpleEntityRef;
import org.usergrid.persistence.cassandra.CassandraService;
import org.usergrid.persistence.entities.Application;
import org.usergrid.utils.JsonUtils;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;

/**
 * This is a utility to load all entities in an application and re-save them,
 * this forces the secondary indexing to be updated.
 * 
 * @author tnine
 * 
 */
public class DupOrgRepair extends ExportingToolBase {

  /**
     * 
     */
  private static final int PAGE_SIZE = 100;

  private static final Logger logger = LoggerFactory.getLogger(DupOrgRepair.class);

  @Override
  @SuppressWarnings("static-access")
  public Options createOptions() {

    Option hostOption = OptionBuilder.withArgName("host").hasArg().isRequired(true).withDescription("Cassandra host")
        .create("host");

    Option outputOption = OptionBuilder.withArgName("output").hasArg().isRequired(true)
        .withDescription("Cassandra host").create("output");

    Options options = new Options();
    options.addOption(hostOption);
    options.addOption(outputOption);

    return options;
  }

  /*
   * (non-Javadoc)
   * 
   * @see
   * org.usergrid.tools.ToolBase#runTool(org.apache.commons.cli.CommandLine)
   */
  @Override
  public void runTool(CommandLine line) throws Exception {
    String outputDir = line.getOptionValue("output");

    createDir(outputDir);

    startSpring();

    logger.info("Starting crawl of all admins");

    EntityManager em = emf.getEntityManager(CassandraService.MANAGEMENT_APPLICATION_ID);
    Application app = em.getApplication();

    // search for all orgs

    Query query = new Query();
    query.setLimit(PAGE_SIZE);
    Results r = null;

    Multimap orgs = HashMultimap.create();

    do {

      r = em.searchCollection(app, "groups", query);

      for (Entity entity : r.getEntities()) {
        String name = entity.getProperty("path").toString().toLowerCase();
        orgs.put(name, entity.getUuid());
      }

      query.setCursor(r.getCursor());

      logger.info("Searching next page");

    } while (r != null && r.size() == PAGE_SIZE);

    // now go through and print out duplicate emails

    for (String name : orgs.keySet()) {
      Collection ids = orgs.get(name);

      if (ids.size() > 1) {
        logger.warn("Found multiple orgs with the name {}", name);

        // look this up the same way the REST tier does. This way we will always
        // map the same way and the user will not notice a background merge
        OrganizationInfo orgInfo = managementService.getOrganizationByName(name);

        UUID targetOrgId = orgInfo.getUuid();

        ids.remove(targetOrgId);

        for (UUID sourceId : ids) {
          mergeOrganizations(outputDir, sourceId, targetOrgId);
        }

      }
    }

    logger.info("Merge complete");

  }

  /**
   * Merge the source orgId into the targetId in the following way.
   * 
   * 1) link all admins from the source org to the target org 2) link all apps
   * from the source org to the target or 3) delete the target org
   * 
   * @param sourceOrgId
   * @param targetOrgId
   * @throws Exception
   */
  @SuppressWarnings("unchecked")
  private void mergeOrganizations(String outputDir, UUID sourceOrgId, UUID targetOrgId) throws Exception {

    OrganizationInfo sourceOrgInfo = managementService.getOrganizationByUuid(sourceOrgId);

    Map sourceOrg = managementService.getOrganizationData(sourceOrgInfo);

    OrganizationInfo targetOrgInfo = managementService.getOrganizationByUuid(targetOrgId);

    Map targetOrg = managementService.getOrganizationData(targetOrgInfo);

    // Dump the output on these two orgs
    FileWriter file = new FileWriter(String.format("%s/%s.%s.orig", outputDir, sourceOrgInfo.getName(), sourceOrgId));

    file.write(JsonUtils.mapToFormattedJsonString(sourceOrg));

    file.write("\n\n");

    file.write(JsonUtils.mapToFormattedJsonString(targetOrg));

    file.flush();
    file.close();

    // BiMap targetApps =
    // managementService.getApplicationsForOrganization(targetOrgId);

    // now perform the merge

    // add all the admins
    Map admins = (Map) sourceOrg.get("users");

    for (Entry adminEntry : admins.entrySet()) {
      UserInfo admin = adminEntry.getValue();

      logger.info("adding admin with uuid {} and email {} to org with name {} and uuid {}",
          new Object[] { admin.getUuid(), admin.getEmail(), targetOrgInfo.getName(), targetOrgInfo.getUuid() });

      // copy the admins over
      managementService.addAdminUserToOrganization(admin, targetOrgInfo, false);
    }

    // get the root entity manager
    EntityManager em = emf.getEntityManager(CassandraService.MANAGEMENT_APPLICATION_ID);

    // Add the apps to the org
    Map sourceApps = (Map) sourceOrg.get("applications");

    Map targetApps = (Map) targetOrg.get("applications");

    for (Entry app : sourceApps.entrySet()) {

      // we have colliding app names
      if (targetApps.get(app.getKey()) != null) {

        // already added, skip it
        if (app.getValue().equals(targetApps.get(app.getKey()))) {
          continue;
        }

        // check to see if this orgname/appname lookup returns the app we're
        // about to re-assign. If it does NOT, then we need to rename this app
        // before performing the link.
        UUID appIdToKeep = emf.lookupApplication(app.getKey());

        UUID appIdToChange = appIdToKeep.equals(app.getValue()) ? targetApps.get(app.getKey()) : app.getValue();

        // get the existing target entity
        Entity appEntity = em.get(appIdToChange);

        if (appEntity != null) {

          String oldName = appEntity.getProperty("name").toString();
          String newName = oldName + appEntity.getUuid();

          //force the property to be updated
          em.setProperty(appEntity, "name", newName, true);

          logger.info("Renamed app from {} to {}", oldName, newName);

        }
      }

      logger.info("Adding application with name {} and id {} to organization with uuid {}", new Object[] {
          app.getKey(), app.getValue(), targetOrgId });
      managementService.addApplicationToOrganization(targetOrgId, app.getValue());
    }

    // now delete the original org

    logger.info("Deleting org with the name {} and uuid {}", sourceOrgInfo.getName(), sourceOrgInfo.getUuid());

    // delete the source org
    em.delete(new SimpleEntityRef("group", sourceOrgId));

    // re-dump the target from the cassandra stat
    targetOrgInfo = managementService.getOrganizationByUuid(targetOrgId);

    targetOrg = managementService.getOrganizationData(targetOrgInfo);

    file = new FileWriter(String.format("%s/%s.%s.new", outputDir, targetOrgInfo.getName(), targetOrgId));

    file.write(JsonUtils.mapToFormattedJsonString(targetOrg));

    file.flush();
    file.close();

  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy