Package org.hive2hive.core.processes.implementations.files.move

Source Code of org.hive2hive.core.processes.implementations.files.move.RelinkUserProfileStep

package org.hive2hive.core.processes.implementations.files.move;

import java.security.KeyPair;
import java.security.PublicKey;
import java.util.HashSet;
import java.util.Set;

import org.hive2hive.core.exceptions.GetFailedException;
import org.hive2hive.core.exceptions.NoPeerConnectionException;
import org.hive2hive.core.exceptions.NoSessionException;
import org.hive2hive.core.exceptions.PutFailedException;
import org.hive2hive.core.model.FolderIndex;
import org.hive2hive.core.model.Index;
import org.hive2hive.core.model.UserProfile;
import org.hive2hive.core.network.NetworkManager;
import org.hive2hive.core.network.data.UserProfileManager;
import org.hive2hive.core.processes.framework.RollbackReason;
import org.hive2hive.core.processes.framework.abstracts.ProcessStep;
import org.hive2hive.core.processes.framework.exceptions.InvalidProcessStateException;
import org.hive2hive.core.processes.framework.exceptions.ProcessExecutionException;
import org.hive2hive.core.processes.implementations.context.MoveFileProcessContext;
import org.hive2hive.core.processes.implementations.context.MoveFileProcessContext.AddNotificationContext;
import org.hive2hive.core.processes.implementations.context.MoveFileProcessContext.DeleteNotificationContext;
import org.hive2hive.core.processes.implementations.context.MoveFileProcessContext.MoveNotificationContext;
import org.hive2hive.core.processes.implementations.context.MoveUpdateProtectionKeyContext;
import org.hive2hive.core.processes.implementations.files.add.UploadNotificationMessageFactory;
import org.hive2hive.core.processes.implementations.files.delete.DeleteNotifyMessageFactory;
import org.hive2hive.core.processes.implementations.share.pkupdate.InitializeMetaUpdateStep;
import org.hive2hive.core.security.H2HEncryptionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RelinkUserProfileStep extends ProcessStep {

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

  private final MoveFileProcessContext context;
  private final NetworkManager networkManager;

  private boolean profileUpdated;
  private PublicKey oldParentKey = null;

  public RelinkUserProfileStep(MoveFileProcessContext context, NetworkManager networkManager) {
    this.context = context;
    this.networkManager = networkManager;
  }

  @Override
  protected void doExecute() throws InvalidProcessStateException, ProcessExecutionException {
    logger.debug("Start relinking the moved file in the user profile.");

    // different possibilities of movement:
    // - file moved from root to other destination
    // - file moved from other source to root
    // - file moved from other source to other destination
    // Additionally, the file can be renamed (within any directory)
    try {
      UserProfileManager profileManager = networkManager.getSession().getProfileManager();
      UserProfile userProfile = profileManager.getUserProfile(getID(), true);

      logger.debug("Start relinking the moved file in the user profile.");
      Index movedNode = userProfile.getFileById(context.getFileNodeKeys().getPublic());

      // consider renaming
      movedNode.setName(context.getDestination().getName());

      FolderIndex oldParent = movedNode.getParent();
      oldParentKey = oldParent.getFileKeys().getPublic();

      // source's parent needs to be updated, no matter if it's root or not
      oldParent.removeChild(movedNode);

      // add to the new parent
      FolderIndex newParent = (FolderIndex) userProfile.getFileByPath(context.getDestination()
          .getParentFile(), networkManager.getSession().getRoot());
      movedNode.setParent(newParent);
      newParent.addChild(movedNode);

      // validate
      if (!oldParent.canWrite()) {
        throw new ProcessExecutionException("No write access to the source directory");
      } else if (!newParent.canWrite()) {
        throw new ProcessExecutionException("No write access to the destination directory");
      }

      // update in DHT
      profileManager.readyToPut(userProfile, getID());
      profileUpdated = true;
      logger.debug("Successfully relinked the moved file in the user profile.");

      // check if the protection key needs to be updated
      if (!H2HEncryptionUtil.compare(oldParent.getProtectionKeys(), newParent.getProtectionKeys())) {
        // update the protection key of the meta file and eventually all chunks
        logger.info("Required to update the protection key of the moved file(s)/folder(s).");
        initPKUpdateStep(movedNode, oldParent.getProtectionKeys(), newParent.getProtectionKeys());
      }

      // notify other users
      initNotificationParameters(oldParent.getCalculatedUserList(), movedNode);

    } catch (NoSessionException | GetFailedException | PutFailedException | NoPeerConnectionException e) {
      throw new ProcessExecutionException(e);
    }
  }

  private void initPKUpdateStep(Index movedNode, KeyPair oldProtectionKeys, KeyPair newProtectionKeys)
      throws NoPeerConnectionException {
    MoveUpdateProtectionKeyContext pkUpdateContext = new MoveUpdateProtectionKeyContext(movedNode,
        oldProtectionKeys, newProtectionKeys);
    getParent().insertNext(
        new InitializeMetaUpdateStep(pkUpdateContext, networkManager.getDataManager()), this);
  }

  /**
   * Sends three notification types:
   * 1. users that have access to the file prior and after file movement
   * 2. users that don't have access to the file anymore
   * 3. users that now have access to the file but didn't have prior movement
   */
  private void initNotificationParameters(Set<String> usersAtSource, Index movedNode) {
    // the users at the destination
    Set<String> usersAtDestination = movedNode.getCalculatedUserList();

    // add all common users to a list
    Set<String> common = new HashSet<String>();

    for (String user : usersAtSource) {
      if (usersAtDestination.contains(user))
        common.add(user);
    }

    for (String user : usersAtDestination) {
      if (usersAtSource.contains(user))
        common.add(user);
    }

    // convenience fields
    PublicKey fileKey = movedNode.getFilePublicKey();
    String sourceName = context.getSource().getName();
    String destName = context.getDestination().getName();

    // inform common users
    logger.debug("Inform {} users that a file has been moved.", common.size());
    PublicKey newParentKey = movedNode.getParent().getFilePublicKey();
    MoveNotificationContext moveContext = context.getMoveNotificationContext();
    moveContext.provideMessageFactory(new MoveNotificationMessageFactory(sourceName, destName,
        oldParentKey, newParentKey));
    moveContext.provideUsersToNotify(common);

    // inform users that don't have access to the new destination anymore
    logger.debug("Inform {} users that a file has been removed (after movement).", usersAtSource.size());
    usersAtSource.removeAll(common);
    DeleteNotificationContext deleteContext = context.getDeleteNotificationContext();
    deleteContext
        .provideMessageFactory(new DeleteNotifyMessageFactory(fileKey, oldParentKey, sourceName));
    deleteContext.provideUsersToNotify(usersAtSource);

    // inform users that have now access to the moved file
    logger.debug("Inform {} users that a file has been added (after movement).", usersAtDestination.size());
    usersAtDestination.removeAll(common);
    AddNotificationContext addContext = context.getAddNotificationContext();
    addContext.provideMessageFactory(new UploadNotificationMessageFactory(movedNode, movedNode
        .getParent().getFilePublicKey()));
    addContext.provideUsersToNotify(usersAtDestination);
  }

  @Override
  protected void doRollback(RollbackReason reason) throws InvalidProcessStateException {
    // only when user profile has been updated
    if (profileUpdated) {
      try {
        UserProfileManager profileManager = networkManager.getSession().getProfileManager();
        UserProfile userProfile = profileManager.getUserProfile(getID(), true);

        // relink them
        Index movedNode = userProfile.getFileById(context.getFileNodeKeys().getPublic());
        userProfile.getRoot().removeChild(movedNode);
        FolderIndex oldParent = (FolderIndex) userProfile.getFileById(oldParentKey);
        movedNode.setParent(oldParent);
        oldParent.addChild(movedNode);

        // update in DHT
        profileManager.readyToPut(userProfile, getID());
      } catch (NoSessionException | GetFailedException | PutFailedException e) {
        // ignore
      }
    }
  }
}
TOP

Related Classes of org.hive2hive.core.processes.implementations.files.move.RelinkUserProfileStep

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.