You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2016/06/09 12:24:01 UTC

ambari git commit: AMBARI-16836 : View Instance: Data Migration. (Nitiraj Rathore via dipayanb)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.4 e149d0864 -> a20fd0e26


AMBARI-16836 : View Instance: Data Migration. (Nitiraj Rathore via dipayanb)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/a20fd0e2
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a20fd0e2
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a20fd0e2

Branch: refs/heads/branch-2.4
Commit: a20fd0e26e6a9d08a025a3ef6ba7c2092df39f61
Parents: e149d08
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Thu Jun 9 17:53:44 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Thu Jun 9 17:53:44 2016 +0530

----------------------------------------------------------------------
 .../api/services/ViewDataMigrationService.java  | 143 ++----------
 .../view/ViewDataMigrationContextImpl.java      |  44 +++-
 .../server/view/ViewDataMigrationUtility.java   | 228 +++++++++++++++++++
 .../ambari/server/view/ViewExtractor.java       |   7 +-
 .../apache/ambari/server/view/ViewRegistry.java | 147 +++++++++++-
 .../main/python/ambari_server/serverUpgrade.py  |   5 -
 .../services/ViewDataMigrationServiceTest.java  | 178 ++-------------
 .../view/ViewDataMigrationContextImplTest.java  |  55 ++---
 .../view/ViewDataMigrationUtilityTest.java      | 184 +++++++++++++++
 .../ambari/server/view/ViewRegistryTest.java    |   6 +-
 10 files changed, 658 insertions(+), 339 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
index c6846ce..4a71ce2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewDataMigrationService.java
@@ -18,11 +18,9 @@
 package org.apache.ambari.server.api.services;
 
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
-import org.apache.ambari.server.view.ViewDataMigrationContextImpl;
+import org.apache.ambari.server.view.ViewDataMigrationUtility;
 import org.apache.ambari.server.view.ViewRegistry;
-import org.apache.ambari.view.migration.ViewDataMigrationContext;
 import org.apache.ambari.view.migration.ViewDataMigrationException;
-import org.apache.ambari.view.migration.ViewDataMigrator;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -31,7 +29,6 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.Response;
-import java.util.Map;
 
 /**
  * Service responsible for data migration between view instances.
@@ -57,7 +54,15 @@ public class ViewDataMigrationService extends BaseService {
    */
   private final String instanceName;
 
-  private ViewRegistry viewRegistry;
+  /**
+   * The singleton view registry.
+   */
+  ViewRegistry viewRegistry;
+
+  /**
+   * The view data migration utility.
+   */
+  private ViewDataMigrationUtility viewDataMigrationUtility;
 
   /**
    * Constructor.
@@ -77,8 +82,8 @@ public class ViewDataMigrationService extends BaseService {
    * Migrates view instance persistence data from origin view instance
    * specified in the path params.
    *
-   * @param originViewVersion    the origin view version
-   * @param originInstanceName   the origin view instance name
+   * @param originViewVersion  the origin view version
+   * @param originInstanceName the origin view instance name
    */
   @PUT
   @Path("{originVersion}/{originInstanceName}")
@@ -93,127 +98,25 @@ public class ViewDataMigrationService extends BaseService {
     LOG.info("Data Migration to view instance " + viewName + "/" + viewVersion + "/" + instanceName +
         " from " + viewName + "/" + originViewVersion + "/" + originInstanceName);
 
-    ViewInstanceEntity instanceDefinition = getViewInstanceEntity(viewName, viewVersion, instanceName);
-    ViewInstanceEntity originInstanceDefinition = getViewInstanceEntity(viewName, originViewVersion, originInstanceName);
+    ViewInstanceEntity instanceDefinition = viewRegistry.getInstanceDefinition(
+        viewName, viewVersion, instanceName);
+    ViewInstanceEntity originInstanceDefinition = viewRegistry.getInstanceDefinition(
+        viewName, originViewVersion, originInstanceName);
 
-    ViewDataMigrationContextImpl migrationContext = getViewDataMigrationContext(instanceDefinition, originInstanceDefinition);
-
-    ViewDataMigrator dataMigrator = getViewDataMigrator(instanceDefinition, migrationContext);
-
-    LOG.debug("Running before-migration hook");
-    if (!dataMigrator.beforeMigration()) {
-      String msg = "View " + viewName + "/" + viewVersion + "/" + instanceName + " canceled the migration process";
-
-      LOG.error(msg);
-      throw new ViewDataMigrationException(msg);
-    }
-
-    Map<String, Class> originClasses = migrationContext.getOriginEntityClasses();
-    Map<String, Class> currentClasses = migrationContext.getCurrentEntityClasses();
-    for (Map.Entry<String, Class> originEntity : originClasses.entrySet()) {
-      LOG.debug("Migrating persistence entity " + originEntity.getKey());
-      if (currentClasses.containsKey(originEntity.getKey())) {
-        Class entity = currentClasses.get(originEntity.getKey());
-        dataMigrator.migrateEntity(originEntity.getValue(), entity);
-      } else {
-        LOG.debug("Entity " + originEntity.getKey() + " not found in target view");
-        dataMigrator.migrateEntity(originEntity.getValue(), null);
-      }
-    }
-
-    LOG.debug("Migrating instance data");
-    dataMigrator.migrateInstanceData();
-
-    LOG.debug("Running after-migration hook");
-    dataMigrator.afterMigration();
-
-    LOG.debug("Copying user permissions");
-    viewRegistry.copyPrivileges(originInstanceDefinition, instanceDefinition);
+    getViewDataMigrationUtility().migrateData(instanceDefinition, originInstanceDefinition, false);
 
     Response.ResponseBuilder builder = Response.status(Response.Status.OK);
     return builder.build();
   }
 
-  protected ViewDataMigrationContextImpl getViewDataMigrationContext(ViewInstanceEntity instanceDefinition, ViewInstanceEntity originInstanceDefinition) {
-    return new ViewDataMigrationContextImpl(
-        originInstanceDefinition, instanceDefinition);
-  }
-
-  protected ViewInstanceEntity getViewInstanceEntity(String viewName, String viewVersion, String instanceName) {
-    return viewRegistry.getInstanceDefinition(viewName, viewVersion, instanceName);
-  }
-
-  /**
-   * Get the migrator instance for view instance with injected migration context.
-   * If versions of instances are same returns copy-all-data migrator.
-   * If versions are different, loads the migrator from the current view (view should
-   * contain ViewDataMigrator implementation, otherwise exception will be raised).
-   *
-   * @param currentInstanceDefinition    the current view instance definition
-   * @param migrationContext             the migration context to inject into migrator
-   * @throws ViewDataMigrationException  if view does not support migration
-   * @return  the data migration instance
-   */
-  protected ViewDataMigrator getViewDataMigrator(ViewInstanceEntity currentInstanceDefinition,
-                                                 ViewDataMigrationContextImpl migrationContext)
-      throws ViewDataMigrationException {
-    ViewDataMigrator dataMigrator;
-
-    LOG.info("Migrating " + viewName + "/" + viewVersion + "/" + instanceName +
-        " data from " + migrationContext.getOriginDataVersion() + " to " +
-        migrationContext.getCurrentDataVersion() + " data version");
-
-    if (migrationContext.getOriginDataVersion() == migrationContext.getCurrentDataVersion()) {
-
-      LOG.info("Instances of same version, copying all data.");
-      dataMigrator = new CopyAllDataMigrator(migrationContext);
-    } else {
-      try {
-        dataMigrator = currentInstanceDefinition.getDataMigrator(migrationContext);
-        if (dataMigrator == null) {
-          throw new ViewDataMigrationException("A view instance " +
-              viewName + "/" + viewVersion + "/" + instanceName + " does not support migration.");
-        }
-        LOG.debug("Data migrator loaded");
-      } catch (ClassNotFoundException e) {
-        String msg = "Caught exception loading data migrator of " + viewName + "/" + viewVersion + "/" + instanceName;
-
-        LOG.error(msg, e);
-        throw new RuntimeException(msg);
-      }
+  protected ViewDataMigrationUtility getViewDataMigrationUtility() {
+    if (viewDataMigrationUtility == null) {
+      viewDataMigrationUtility = new ViewDataMigrationUtility(viewRegistry);
     }
-    return dataMigrator;
+    return viewDataMigrationUtility;
   }
 
-  /**
-   * The data migrator implementation that copies all data without modification.
-   * Used to copy data between instances of same version.
-   */
-  public static class CopyAllDataMigrator implements ViewDataMigrator {
-    private ViewDataMigrationContext migrationContext;
-
-    public CopyAllDataMigrator(ViewDataMigrationContext migrationContext) {
-      this.migrationContext = migrationContext;
-    }
-
-    @Override
-    public boolean beforeMigration() {
-      return true;
-    }
-
-    @Override
-    public void afterMigration() {
-    }
-
-    @Override
-    public void migrateEntity(Class originEntityClass, Class currentEntityClass)
-        throws ViewDataMigrationException {
-      migrationContext.copyAllObjects(originEntityClass, currentEntityClass);
-    }
-
-    @Override
-    public void migrateInstanceData() {
-      migrationContext.copyAllInstanceData();
-    }
+  protected void setViewDataMigrationUtility(ViewDataMigrationUtility viewDataMigrationUtility) {
+    this.viewDataMigrationUtility = viewDataMigrationUtility;
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationContextImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationContextImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationContextImpl.java
index 94e3e28..909b3a1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationContextImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationContextImpl.java
@@ -20,6 +20,7 @@ package org.apache.ambari.server.view;
 
 import com.google.inject.Guice;
 import com.google.inject.Injector;
+import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceDataEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
@@ -119,6 +120,7 @@ public class ViewDataMigrationContextImpl implements ViewDataMigrationContext {
   }
 
   @Override
+  @Transactional
   public void putCurrentInstanceData(String user, String key, String value) {
     putInstanceData(currentInstanceDefinition, user, key, value);
   }
@@ -135,6 +137,7 @@ public class ViewDataMigrationContextImpl implements ViewDataMigrationContext {
   }
 
   @Override
+  @Transactional
   public void copyAllObjects(Class originEntityClass, Class currentEntityClass, EntityConverter entityConverter)
       throws ViewDataMigrationException {
     try{
@@ -209,6 +212,7 @@ public class ViewDataMigrationContextImpl implements ViewDataMigrationContext {
   }
 
   @Override
+  @Transactional
   public void putOriginInstanceData(String user, String key, String value) {
     putInstanceData(originInstanceDefinition, user, key, value);
   }
@@ -227,15 +231,37 @@ public class ViewDataMigrationContextImpl implements ViewDataMigrationContext {
    * @param value               the value
    */
   private static void putInstanceData(ViewInstanceEntity instanceDefinition, String user, String name, String value) {
-    ViewInstanceDataEntity viewInstanceDataEntity = new ViewInstanceDataEntity();
-    viewInstanceDataEntity.setViewName(instanceDefinition.getViewName());
-    viewInstanceDataEntity.setViewInstanceName(instanceDefinition.getName());
-    viewInstanceDataEntity.setName(name);
-    viewInstanceDataEntity.setUser(user);
-    viewInstanceDataEntity.setValue(value);
-    viewInstanceDataEntity.setViewInstanceEntity(instanceDefinition);
-
-    instanceDefinition.getData().add(viewInstanceDataEntity);
+    ViewInstanceDataEntity oldInstanceDataEntity = getInstanceData(instanceDefinition, user, name);
+    if (oldInstanceDataEntity != null) {
+      instanceDefinition.getData().remove(oldInstanceDataEntity);
+    }
+
+    ViewInstanceDataEntity instanceDataEntity = new ViewInstanceDataEntity();
+    instanceDataEntity.setViewName(instanceDefinition.getViewName());
+    instanceDataEntity.setViewInstanceName(instanceDefinition.getName());
+    instanceDataEntity.setName(name);
+    instanceDataEntity.setUser(user);
+    instanceDataEntity.setValue(value);
+    instanceDataEntity.setViewInstanceEntity(instanceDefinition);
+
+    instanceDefinition.getData().add(instanceDataEntity);
+  }
+
+  /**
+   * Get the instance data entity for the given key and user.
+   *
+   * @param user owner of the data
+   * @param key the key
+   * @return the instance data entity associated with the given key and user
+   */
+  private static ViewInstanceDataEntity getInstanceData(ViewInstanceEntity instanceDefinition, String user, String key) {
+    for (ViewInstanceDataEntity viewInstanceDataEntity : instanceDefinition.getData()) {
+      if (viewInstanceDataEntity.getName().equals(key) &&
+          viewInstanceDataEntity.getUser().equals(user)) {
+        return viewInstanceDataEntity;
+      }
+    }
+    return null;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationUtility.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationUtility.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationUtility.java
new file mode 100644
index 0000000..15318c0
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewDataMigrationUtility.java
@@ -0,0 +1,228 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.ambari.server.view;
+
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.view.PersistenceException;
+import org.apache.ambari.view.ViewInstanceDefinition;
+import org.apache.ambari.view.migration.ViewDataMigrationContext;
+import org.apache.ambari.view.migration.ViewDataMigrationException;
+import org.apache.ambari.view.migration.ViewDataMigrator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Map;
+
+/**
+ * Helper class for view data migration.
+ */
+public class ViewDataMigrationUtility {
+
+  /**
+   * The logger.
+   */
+  protected final static Logger LOG = LoggerFactory.getLogger(ViewDataMigrationUtility.class);
+
+  /**
+   * The View Registry.
+   */
+  private ViewRegistry viewRegistry;
+
+  /**
+   * Constructor.
+   * @param viewRegistry the view registry
+   */
+  public ViewDataMigrationUtility(ViewRegistry viewRegistry) {
+    this.viewRegistry = viewRegistry;
+  }
+
+  /**
+   * Migrates data from source to target instance
+   * @param targetInstanceDefinition target instance entity
+   * @param sourceInstanceDefinition source instance entity
+   *
+   * @throws ViewDataMigrationException when view does not support migration or an error during migration occurs.
+   */
+  public void migrateDataOnce(ViewInstanceEntity targetInstanceDefinition, ViewInstanceEntity sourceInstanceDefinition)
+      throws ViewDataMigrationException {
+    ViewDataMigrationContextImpl migrationContext = getViewDataMigrationContext(targetInstanceDefinition, sourceInstanceDefinition);
+  }
+
+  /**
+   * Migrates data from source to target instance
+   * @param targetInstanceDefinition target instance entity
+   * @param sourceInstanceDefinition source instance entity
+   * @param migrateOnce cancel if previously migrated
+   *
+   * @throws ViewDataMigrationException when view does not support migration or an error during migration occurs.
+   */
+  public void migrateData(ViewInstanceEntity targetInstanceDefinition, ViewInstanceEntity sourceInstanceDefinition,
+                          boolean migrateOnce)
+      throws ViewDataMigrationException {
+    ViewDataMigrationContextImpl migrationContext = getViewDataMigrationContext(targetInstanceDefinition, sourceInstanceDefinition);
+
+    if (migrateOnce) {
+      if (!isTargetEmpty(migrationContext)) {
+          LOG.error("Migration canceled because target instance is not empty");
+          return;
+      }
+    }
+
+    ViewDataMigrator dataMigrator = getViewDataMigrator(targetInstanceDefinition, migrationContext);
+
+    LOG.debug("Running before-migration hook");
+    if (!dataMigrator.beforeMigration()) {
+      String msg = "View " + targetInstanceDefinition.getInstanceName() + " canceled the migration process";
+
+      LOG.error(msg);
+      throw new ViewDataMigrationException(msg);
+    }
+
+    Map<String, Class> originClasses = migrationContext.getOriginEntityClasses();
+    Map<String, Class> currentClasses = migrationContext.getCurrentEntityClasses();
+    for (Map.Entry<String, Class> originEntity : originClasses.entrySet()) {
+      LOG.debug("Migrating persistence entity " + originEntity.getKey());
+      if (currentClasses.containsKey(originEntity.getKey())) {
+        Class entity = currentClasses.get(originEntity.getKey());
+        dataMigrator.migrateEntity(originEntity.getValue(), entity);
+      } else {
+        LOG.debug("Entity " + originEntity.getKey() + " not found in target view");
+        dataMigrator.migrateEntity(originEntity.getValue(), null);
+      }
+    }
+
+    LOG.debug("Migrating instance data");
+    dataMigrator.migrateInstanceData();
+
+    LOG.debug("Running after-migration hook");
+    dataMigrator.afterMigration();
+
+    LOG.debug("Copying user permissions");
+    viewRegistry.copyPrivileges(sourceInstanceDefinition, targetInstanceDefinition);
+
+    migrationContext.putCurrentInstanceData("upgrade", "upgradedFrom", sourceInstanceDefinition.getViewEntity().getVersion());
+  }
+
+  private boolean isTargetEmpty(ViewDataMigrationContext migrationContext) {
+    if (migrationContext.getCurrentInstanceDataByUser().size() > 0) {
+      return false;
+    }
+
+    try {
+      for (Class entity : migrationContext.getCurrentEntityClasses().values()) {
+        if (migrationContext.getCurrentDataStore().findAll(entity, null).size() > 0) {
+          return false;
+        }
+      }
+    } catch (PersistenceException e) {
+      ViewInstanceDefinition current = migrationContext.getCurrentInstanceDefinition();
+      LOG.error("Persistence exception while check if instance is empty: " +
+          current.getViewDefinition().getViewName() + "{" + current.getViewDefinition().getVersion() + "}/" +
+          current.getInstanceName(), e);
+    }
+
+    return true;
+  }
+
+  /**
+   * Create the data migration context for DataMigrator to access data of current
+   * and origin instances.
+   * @param targetInstanceDefinition target instance definition
+   * @param sourceInstanceDefinition source instance definition
+   * @return data migration context
+   */
+  protected ViewDataMigrationContextImpl getViewDataMigrationContext(ViewInstanceEntity targetInstanceDefinition,
+                                                                            ViewInstanceEntity sourceInstanceDefinition) {
+    return new ViewDataMigrationContextImpl(sourceInstanceDefinition, targetInstanceDefinition);
+  }
+
+  /**
+   * Get the migrator instance for view instance with injected migration context.
+   * If versions of instances are same returns copy-all-data migrator.
+   * If versions are different, loads the migrator from the current view (view should
+   * contain ViewDataMigrator implementation, otherwise exception will be raised).
+   *
+   * @param currentInstanceDefinition    the current view instance definition
+   * @param migrationContext             the migration context to inject into migrator
+   * @throws ViewDataMigrationException  if view does not support migration
+   * @return  the data migration instance
+   */
+  protected ViewDataMigrator getViewDataMigrator(ViewInstanceEntity currentInstanceDefinition,
+                                                        ViewDataMigrationContextImpl migrationContext)
+      throws ViewDataMigrationException {
+    ViewDataMigrator dataMigrator;
+
+    LOG.info("Migrating " + currentInstanceDefinition.getInstanceName() +
+        " data from " + migrationContext.getOriginDataVersion() + " to " +
+        migrationContext.getCurrentDataVersion() + " data version");
+
+    if (migrationContext.getOriginDataVersion() == migrationContext.getCurrentDataVersion()) {
+
+      LOG.info("Instances of same version, copying all data.");
+      dataMigrator = new CopyAllDataMigrator(migrationContext);
+    } else {
+      try {
+        dataMigrator = currentInstanceDefinition.getDataMigrator(migrationContext);
+        if (dataMigrator == null) {
+          throw new ViewDataMigrationException("A view instance " +
+              currentInstanceDefinition.getInstanceName() + " does not support migration.");
+        }
+        LOG.debug("Data migrator loaded");
+      } catch (ClassNotFoundException e) {
+        String msg = "Caught exception loading data migrator of " + currentInstanceDefinition.getInstanceName();
+
+        LOG.error(msg, e);
+        throw new RuntimeException(msg);
+      }
+    }
+    return dataMigrator;
+  }
+
+
+  /**
+   * The data migrator implementation that copies all data without modification.
+   * Used to copy data between instances of same version.
+   */
+  public static class CopyAllDataMigrator implements ViewDataMigrator {
+    private ViewDataMigrationContext migrationContext;
+
+    public CopyAllDataMigrator(ViewDataMigrationContext migrationContext) {
+      this.migrationContext = migrationContext;
+    }
+
+    @Override
+    public boolean beforeMigration() {
+      return true;
+    }
+
+    @Override
+    public void afterMigration() {
+    }
+
+    @Override
+    public void migrateEntity(Class originEntityClass, Class currentEntityClass)
+        throws ViewDataMigrationException {
+      migrationContext.copyAllObjects(originEntityClass, currentEntityClass);
+    }
+
+    @Override
+    public void migrateInstanceData() {
+      migrationContext.copyAllInstanceData();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
index 3550f98..3425691 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
@@ -19,6 +19,7 @@ package org.apache.ambari.server.view;
 
 import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.view.configuration.ViewConfig;
+import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -72,9 +73,13 @@ public class ViewExtractor {
     String archivePath = archiveDir.getAbsolutePath();
 
     try {
+      // Remove directory if jar was updated since last extracting
+      if (archiveDir.exists() && viewArchive.lastModified() > archiveDir.lastModified()) {
+        FileUtils.deleteDirectory(archiveDir);
+      }
+
       // Skip if the archive has already been extracted
       if (!archiveDir.exists()) {
-
         String msg = "Creating archive folder " + archivePath + ".";
 
         view.setStatusDetail(msg);

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index bda1079..90144e2 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -97,14 +97,17 @@ import org.apache.ambari.view.ViewResourceHandler;
 import org.apache.ambari.view.cluster.Cluster;
 import org.apache.ambari.view.events.Event;
 import org.apache.ambari.view.events.Listener;
+import org.apache.ambari.view.migration.ViewDataMigrationException;
 import org.apache.ambari.view.validation.Validator;
 import org.apache.log4j.PropertyConfigurator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
 import javax.inject.Singleton;
+import javax.xml.bind.JAXBException;
 import java.beans.IntrospectionException;
 import java.io.File;
 import java.io.FileInputStream;
@@ -192,6 +195,11 @@ public class ViewRegistry {
   protected final static Logger LOG = LoggerFactory.getLogger(ViewRegistry.class);
 
   /**
+   * View Data Migration Utility
+   */
+  protected ViewDataMigrationUtility viewDataMigrationUtility;
+
+  /**
    * View data access object.
    */
   @Inject
@@ -305,7 +313,6 @@ public class ViewRegistry {
   @Inject
   RemoteAmbariClusterDAO remoteAmbariClusterDAO;
 
-
  // ----- Constructors -----------------------------------------------------
 
   /**
@@ -709,12 +716,14 @@ public class ViewRegistry {
     }
 
     List<PrivilegeEntity> sourceInstancePrivileges = privilegeDAO.findByResourceId(sourceInstanceEntity.getResource().getId());
-    for (PrivilegeEntity privilegeEntity : sourceInstancePrivileges) {
-      privilegeDAO.detach(privilegeEntity);
-      privilegeEntity.setResource(targetInstanceEntity.getResource());
-      privilegeEntity.setId(null);
-      privilegeDAO.create(privilegeEntity);
-      privilegeEntity.getPrincipal().getPrivileges().add(privilegeEntity);
+    for (PrivilegeEntity sourcePrivilege : sourceInstancePrivileges) {
+      PrivilegeEntity targetPrivilege = new PrivilegeEntity();
+      targetPrivilege.setPrincipal(sourcePrivilege.getPrincipal());
+      targetPrivilege.setResource(targetInstanceEntity.getResource());
+      targetPrivilege.setPermission(sourcePrivilege.getPermission());
+      privilegeDAO.create(targetPrivilege);
+
+      targetPrivilege.getPrincipal().getPrivileges().add(sourcePrivilege);
     }
   }
 
@@ -1582,6 +1591,7 @@ public class ViewRegistry {
                       @Override
                       public void run() {
                         readViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile, serverVersion);
+                        migrateDataFromPreviousVersion(viewDefinition, serverVersion);
                       }
                     });
                   }
@@ -1593,6 +1603,13 @@ public class ViewRegistry {
             }
           }
 
+          for(ViewEntity view : getDefinitions()) {
+            if (view.getStatus() == ViewDefinition.ViewStatus.DEPLOYED) {
+              // migrate views that are not need extraction, for ones that need call will be done in the runnable.
+              migrateDataFromPreviousVersion(view, serverVersion);
+            }
+          }
+
           if (useExecutor && extractionRunnables.size() > 0) {
             final ExecutorService executorService = getExecutorService(configuration);
 
@@ -1630,7 +1647,7 @@ public class ViewRegistry {
       // extract the archive and get the class loader
       ClassLoader cl = extractor.extractViewArchive(viewDefinition, archiveFile, extractedArchiveDirFile);
 
-      configureViewLogging(viewDefinition,cl);
+      configureViewLogging(viewDefinition, cl);
 
       ViewConfig viewConfig = archiveUtility.getViewConfigFromExtractedArchive(extractedArchiveDirPath,
           configuration.isViewValidationEnabled());
@@ -1664,6 +1681,39 @@ public class ViewRegistry {
     }
   }
 
+  private void migrateDataFromPreviousVersion(ViewEntity viewDefinition, String serverVersion) {
+    if (!viewDefinitions.containsKey(viewDefinition.getName())) { // migrate only registered views to avoid recursive calls
+      LOG.debug("Cancel auto migration of not loaded view: " + viewDefinition.getName() + ".");
+      return;
+    }
+    try {
+
+      for (ViewInstanceEntity instance : viewDefinition.getInstances()) {
+        LOG.debug("Try to migrate the data from previous version of: " + viewDefinition.getName() + "/" +
+            instance.getInstanceName() + ".");
+        ViewInstanceEntity latestUnregisteredView = getLatestUnregisteredInstance(serverVersion, instance);
+
+        if (latestUnregisteredView != null) {
+          String instanceName = instance.getViewEntity().getName() + "/" + instance.getName();
+          try {
+            LOG.info("Found previous version of the view instance " + instanceName + ": " +
+                latestUnregisteredView.getViewEntity().getName() + "/" + latestUnregisteredView.getName());
+            getViewDataMigrationUtility().migrateData(instance, latestUnregisteredView, true);
+            LOG.info("View data migrated: " + viewDefinition.getName() + ".");
+          } catch (ViewDataMigrationException e) {
+            LOG.error("Error occurred during migration", e);
+          }
+        }
+      }
+
+    } catch (Exception e) {
+      String msg = "Caught exception migrating data in view " + viewDefinition.getName();
+
+      setViewStatus(viewDefinition, ViewEntity.ViewStatus.ERROR, msg + " : " + e.getMessage());
+      LOG.error(msg, e);
+    }
+  }
+
   /**
    * copies non-log4j properties (like ambari.log.dir) from ambari's log4j.properties into view's log4j properties
    * and removes log4j specific properties (log4j.rootLogger) inside ambari's log4j.properties from view's log4j properties
@@ -1972,8 +2022,89 @@ public class ViewRegistry {
     return url.substring(0,index);
   }
 
+  /**
+   * From all extracted views in the work directory finds ones that are present only in
+   * extracted version (not registered in the registry during startup).
+   * If jar is not exists, that means that this view is previous version of view.
+   * Finds latest between unregistered instances and returns it.
+   *
+   * @param serverVersion server version
+   * @param instance view instance entity
+   * @return latest unregistered instance of same name of same view.
+   */
+  private ViewInstanceEntity getLatestUnregisteredInstance(String serverVersion, ViewInstanceEntity instance)
+      throws JAXBException, IOException, SAXException {
+    File viewDir = configuration.getViewsDir();
 
+    String extractedArchivesPath = viewDir.getAbsolutePath() +
+        File.separator + EXTRACTED_ARCHIVES_DIR;
+
+    File extractedArchivesDir = new File(extractedArchivesPath);
+    File[] extractedArchives = extractedArchivesDir.listFiles();
+
+    // find all view archives from previous Ambari versions
+    Map<ViewInstanceEntity, Long> unregInstancesTimestamps = new HashMap<>();
+    if (extractedArchives != null) {
+
+      for (File archiveDir : extractedArchives) {
+        if (archiveDir.isDirectory()) {
+          ViewConfig uViewConfig = archiveUtility.getViewConfigFromExtractedArchive(archiveDir.getPath(), false);
+          if (!uViewConfig.isSystem()) {
+            // load prev versions of same view
+            if (!uViewConfig.getName().equals(instance.getViewEntity().getViewName())) {
+              continue;
+            }
+
+            // check if it's not registered yet. It means that jar file is not present while directory in
+            // work dir present, so maybe it's prev version of view.
+            if (viewDefinitions.containsKey(ViewEntity.getViewName(uViewConfig.getName(), uViewConfig.getVersion()))) {
+              continue;
+            }
+
+            LOG.debug("Unregistered extracted view found: " + archiveDir.getPath());
+
+            ViewEntity uViewDefinition = new ViewEntity(uViewConfig, configuration, archiveDir.getPath());
+            readViewArchive(uViewDefinition, archiveDir, archiveDir, serverVersion);
+            for (ViewInstanceEntity instanceEntity : uViewDefinition.getInstances()) {
+              LOG.debug(uViewDefinition.getName() + " instance found: " + instanceEntity.getInstanceName());
+              unregInstancesTimestamps.put(instanceEntity, archiveDir.lastModified());
+            }
+          }
+        }
+      }
 
+    }
+
+    // Find latest previous version
+    long latestPrevInstanceTimestamp = 0;
+    ViewInstanceEntity latestPrevInstance = null;
+    for (ViewInstanceEntity unregInstance : unregInstancesTimestamps.keySet()) {
+      if (unregInstance.getName().equals(instance.getName())) {
+        if (unregInstancesTimestamps.get(unregInstance) > latestPrevInstanceTimestamp) {
+          latestPrevInstance = unregInstance;
+          latestPrevInstanceTimestamp = unregInstancesTimestamps.get(latestPrevInstance);
+        }
+      }
+    }
+    if (latestPrevInstance != null) {
+      LOG.debug("Previous version of " + instance.getViewEntity().getName() + "/" + instance.getName() + " found: " +
+          latestPrevInstance.getViewEntity().getName() + "/" + latestPrevInstance.getName());
+    } else {
+      LOG.debug("Previous version of " + instance.getViewEntity().getName() + "/" + instance.getName() + " not found");
+    }
+    return latestPrevInstance;
+  }
+
+  protected ViewDataMigrationUtility getViewDataMigrationUtility() {
+    if (viewDataMigrationUtility == null) {
+      viewDataMigrationUtility = new ViewDataMigrationUtility(this);
+    }
+    return viewDataMigrationUtility;
+  }
+
+  protected void setViewDataMigrationUtility(ViewDataMigrationUtility viewDataMigrationUtility) {
+    this.viewDataMigrationUtility = viewDataMigrationUtility;
+  }
 
   /**
    * Module for stand alone view registry.

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/main/python/ambari_server/serverUpgrade.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverUpgrade.py b/ambari-server/src/main/python/ambari_server/serverUpgrade.py
index 483b79e..8bd7c51 100644
--- a/ambari-server/src/main/python/ambari_server/serverUpgrade.py
+++ b/ambari-server/src/main/python/ambari_server/serverUpgrade.py
@@ -404,11 +404,6 @@ def upgrade(args):
   for admin_views_dir in admin_views_dirs:
     shutil.rmtree(admin_views_dir)
 
-  # Remove ambari views directory for the rest of the jars, at the time of upgrade. At restart all jars present in Ambari will be extracted into work directory
-  views_dir =  get_views_dir(properties)
-  for views in views_dir:
-    shutil.rmtree(views)
-
   # check if ambari has obsolete LDAP configuration
   if properties.get_property(LDAP_PRIMARY_URL_PROPERTY) and not properties.get_property(IS_LDAP_CONFIGURED):
     args.warnings.append("Existing LDAP configuration is detected. You must run the \"ambari-server setup-ldap\" command to adjust existing LDAP configuration.")

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
index 1eb7ac2..39b2d96 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ViewDataMigrationServiceTest.java
@@ -17,21 +17,14 @@
  */
 package org.apache.ambari.server.api.services;
 
-import junit.framework.Assert;
-import org.apache.ambari.server.orm.entities.ViewEntity;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
-import org.apache.ambari.server.view.ViewDataMigrationContextImpl;
+import org.apache.ambari.server.view.ViewDataMigrationUtility;
 import org.apache.ambari.server.view.ViewRegistry;
-import org.apache.ambari.view.migration.ViewDataMigrationContext;
-import org.apache.ambari.view.migration.ViewDataMigrationException;
-import org.apache.ambari.view.migration.ViewDataMigrator;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
-import java.util.Collections;
-import java.util.Map;
+import javax.ws.rs.WebApplicationException;
 
 import static org.easymock.EasyMock.*;
 
@@ -45,171 +38,38 @@ public class ViewDataMigrationServiceTest {
   private static String version1 = "1.0.0";
   private static String version2 = "2.0.0";
 
-  private static String xml_view_with_migrator_v2 = "<view>\n" +
-      "    <name>" + viewName + "</name>\n" +
-      "    <label>My View!</label>\n" +
-      "    <version>" + version2 + "</version>\n" +
-      "    <data-version>1</data-version>\n" +
-      "    <data-migrator-class>org.apache.ambari.server.api.services.ViewDataMigrationServiceTest$MyDataMigrator</data-migrator-class>\n" +
-      "    <instance>\n" +
-      "        <name>" + instanceName + "</name>\n" +
-      "        <label>My Instance 1!</label>\n" +
-      "    </instance>\n" +
-      "</view>";
-
-  private static String xml_view_with_migrator_v1 = "<view>\n" +
-      "    <name>" + viewName + "</name>\n" +
-      "    <label>My View!</label>\n" +
-      "    <version>" + version1 + "</version>\n" +
-      "    <instance>\n" +
-      "        <name>" + instanceName + "</name>\n" +
-      "        <label>My Instance 1!</label>\n" +
-      "    </instance>\n" +
-      "</view>";
-
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
-  @Before
-  public void setUp() throws Exception {
+  @Test
+  public void testServiceMigrateCallAdmin() throws Exception {
     ViewRegistry viewRegistry = createNiceMock(ViewRegistry.class);
     expect(viewRegistry.checkAdmin()).andReturn(true).anyTimes();
-    viewRegistry.copyPrivileges(anyObject(ViewInstanceEntity.class), anyObject(ViewInstanceEntity.class));
-    expectLastCall().anyTimes();
     replay(viewRegistry);
     ViewRegistry.initInstance(viewRegistry);
-  }
 
-  @Test
-  public void testMigrateDataSameVersions() throws Exception {
-    TestViewDataMigrationService service = new TestViewDataMigrationService(viewName, version2, instanceName);
+    ViewDataMigrationService service = new ViewDataMigrationService(viewName, version1, instanceName);
 
-    ViewDataMigrationContextImpl context = createNiceMock(ViewDataMigrationContextImpl.class);
-    expect(context.getOriginDataVersion()).andReturn(42);
-    expect(context.getCurrentDataVersion()).andReturn(42);
-    replay(context);
-    service.setMigrationContext(context);
+    ViewDataMigrationUtility migrationUtility = createStrictMock(ViewDataMigrationUtility.class);
+    migrationUtility.migrateData(anyObject(ViewInstanceEntity.class), anyObject(ViewInstanceEntity.class), eq(false));
+    replay(migrationUtility);
+    service.setViewDataMigrationUtility(migrationUtility);
 
-    ViewDataMigrator migrator =  service.getViewDataMigrator(
-        service.getViewInstanceEntity(viewName, version2, instanceName), context);
+    service.migrateData(version2, instanceName);
 
-    Assert.assertTrue(migrator instanceof ViewDataMigrationService.CopyAllDataMigrator);
+    verify(migrationUtility);
   }
 
   @Test
-  public void testMigrateDataDifferentVersions() throws Exception {
-    TestViewDataMigrationService service = new TestViewDataMigrationService(viewName, version2, instanceName);
-
-    ViewDataMigrationContextImpl context = getViewDataMigrationContext();
-    service.setMigrationContext(context);
-
-    ViewDataMigrator migrator = createStrictMock(ViewDataMigrator.class);
-    expect(migrator.beforeMigration()).andReturn(true);
-    migrator.migrateEntity(anyObject(Class.class), anyObject(Class.class)); expectLastCall();
-    migrator.migrateInstanceData(); expectLastCall();
-    migrator.afterMigration(); expectLastCall();
-
-    replay(migrator);
-    service.setMigrator(migrator);
-
-    service.migrateData(version1, instanceName);
-
-    verify(migrator);
-  }
-
-  @Test
-  public void testMigrateDataDifferentVersionsCancel() throws Exception {
-    TestViewDataMigrationService service = new TestViewDataMigrationService(viewName, version2, instanceName);
-
-    ViewDataMigrationContextImpl context = getViewDataMigrationContext();
-    service.setMigrationContext(context);
-
-    ViewDataMigrator migrator = createStrictMock(ViewDataMigrator.class);
-    expect(migrator.beforeMigration()).andReturn(false);
-
-    replay(migrator);
-    service.setMigrator(migrator);
-
-    thrown.expect(ViewDataMigrationException.class);
-    service.migrateData(version1, instanceName);
-  }
-
-  private static ViewDataMigrationContextImpl getViewDataMigrationContext() {
-    Map<String, Class> entities = Collections.<String, Class>singletonMap("MyEntityClass", Object.class);
-    ViewDataMigrationContextImpl context = createNiceMock(ViewDataMigrationContextImpl.class);
-    expect(context.getOriginDataVersion()).andReturn(2).anyTimes();
-    expect(context.getCurrentDataVersion()).andReturn(1).anyTimes();
-    expect(context.getOriginEntityClasses()).andReturn(entities).anyTimes();
-    expect(context.getCurrentEntityClasses()).andReturn(entities).anyTimes();
-    replay(context);
-    return context;
-  }
-
-  //Migration service that avoids ViewRegistry and DB calls
-  private static class TestViewDataMigrationService extends ViewDataMigrationService {
-
-    private ViewDataMigrator migrator;
-    private ViewDataMigrationContextImpl migrationContext;
-
-    public TestViewDataMigrationService(String viewName, String viewVersion, String instanceName) {
-      super(viewName, viewVersion, instanceName);
-    }
-
-    @Override
-    protected ViewInstanceEntity getViewInstanceEntity(String viewName, String viewVersion, String instanceName) {
-      ViewEntity viewEntity = createNiceMock(ViewEntity.class);
-      expect(viewEntity.getViewName()).andReturn(viewName);
-      expect(viewEntity.getVersion()).andReturn(viewVersion);
-
-      replay(viewEntity);
-
-      ViewInstanceEntity instanceEntity = createNiceMock(ViewInstanceEntity.class);
-      expect(instanceEntity.getViewEntity()).andReturn(viewEntity);
-      expect(instanceEntity.getViewName()).andReturn(viewName);
-      expect(instanceEntity.getInstanceName()).andReturn(instanceName);
-
-      try {
-        ViewDataMigrator mockMigrator;
-        if (migrator == null) {
-          mockMigrator = createNiceMock(ViewDataMigrator.class);
-        } else {
-          mockMigrator = migrator;
-        }
-        expect(instanceEntity.getDataMigrator(anyObject(ViewDataMigrationContext.class))).
-            andReturn(mockMigrator);
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-
-      replay(instanceEntity);
-      return instanceEntity;
-    }
-
-    @Override
-    protected ViewDataMigrationContextImpl getViewDataMigrationContext(ViewInstanceEntity instanceDefinition,
-                                                                       ViewInstanceEntity originInstanceDefinition) {
-      if (migrationContext == null) {
-        ViewDataMigrationContextImpl contextMock = createNiceMock(ViewDataMigrationContextImpl.class);
-        replay(contextMock);
-        return contextMock;
-      }
-      return migrationContext;
-    }
-
-    public ViewDataMigrator getMigrator() {
-      return migrator;
-    }
-
-    public void setMigrator(ViewDataMigrator migrator) {
-      this.migrator = migrator;
-    }
+  public void testServiceMigrateCallNotAdmin() throws Exception {
+    ViewRegistry viewRegistry = createNiceMock(ViewRegistry.class);
+    expect(viewRegistry.checkAdmin()).andReturn(false).anyTimes();
+    replay(viewRegistry);
+    ViewRegistry.initInstance(viewRegistry);
 
-    public ViewDataMigrationContextImpl getMigrationContext() {
-      return migrationContext;
-    }
+    ViewDataMigrationService service = new ViewDataMigrationService(viewName, version1, instanceName);
 
-    public void setMigrationContext(ViewDataMigrationContextImpl migrationContext) {
-      this.migrationContext = migrationContext;
-    }
+    thrown.expect(WebApplicationException.class);
+    service.migrateData(version2, instanceName);
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationContextImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationContextImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationContextImplTest.java
index a636e0b..1ae7afb 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationContextImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationContextImplTest.java
@@ -30,9 +30,7 @@ import org.apache.ambari.view.migration.EntityConverter;
 import org.easymock.Capture;
 import org.junit.Test;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Map;
+import java.util.*;
 
 import static org.easymock.EasyMock.*;
 
@@ -93,34 +91,27 @@ public class ViewDataMigrationContextImplTest {
     ViewEntity entity2 = getViewEntityMock(VERSION_2);
     replay(entity1, entity2);
 
-    Capture<ViewInstanceDataEntity> capturedInstanceData1 = Capture.newInstance();
-    Collection data1 = createNiceMock(Collection.class);
-    expect(data1.add(capture(capturedInstanceData1))).andReturn(true);
-    replay(data1);
-
-    Capture<ViewInstanceDataEntity> capturedInstanceData2 = Capture.newInstance();
-    Collection data2 = createStrictMock(Collection.class);
-    expect(data2.add(capture(capturedInstanceData2))).andReturn(true);
-    replay(data2);
-
     ViewInstanceEntity instanceEntity1 = getViewInstanceEntityMock(entity1);
-    expect(instanceEntity1.getData()).andReturn(data1);
+    List<ViewInstanceDataEntity> data1 = new ArrayList<>();
+    expect(instanceEntity1.getData()).andReturn(data1).anyTimes();
     ViewInstanceEntity instanceEntity2 = getViewInstanceEntityMock(entity2);
-    expect(instanceEntity2.getData()).andReturn(data2);
+    List<ViewInstanceDataEntity> data2 = new ArrayList<>();
+    expect(instanceEntity2.getData()).andReturn(data2).anyTimes();
     replay(instanceEntity1, instanceEntity2);
 
     ViewDataMigrationContextImpl context = new TestViewDataMigrationContextImpl(instanceEntity1, instanceEntity2);
     context.putOriginInstanceData("user1", "key1", "val1");
     context.putCurrentInstanceData("user2", "key2", "val2");
 
-    verify(data2);
-    Assert.assertEquals("user1", capturedInstanceData1.getValue().getUser());
-    Assert.assertEquals("key1", capturedInstanceData1.getValue().getName());
-    Assert.assertEquals("val1", capturedInstanceData1.getValue().getValue());
+    Assert.assertEquals(1, data1.size());
+    Assert.assertEquals("user1", data1.get(0).getUser());
+    Assert.assertEquals("key1", data1.get(0).getName());
+    Assert.assertEquals("val1", data1.get(0).getValue());
 
-    Assert.assertEquals("user2", capturedInstanceData2.getValue().getUser());
-    Assert.assertEquals("key2", capturedInstanceData2.getValue().getName());
-    Assert.assertEquals("val2", capturedInstanceData2.getValue().getValue());
+    Assert.assertEquals(1, data2.size());
+    Assert.assertEquals("user2", data2.get(0).getUser());
+    Assert.assertEquals("key2", data2.get(0).getName());
+    Assert.assertEquals("val2", data2.get(0).getValue());
   }
 
   @Test
@@ -215,26 +206,22 @@ public class ViewDataMigrationContextImplTest {
     dataEntity.setName("name1");
     dataEntity.setValue("value1");
     dataEntity.setUser("user1");
-    Collection data1 = Arrays.asList(dataEntity);
-
-    Capture<ViewInstanceDataEntity> capturedInstanceData = Capture.newInstance();
-    Collection data2 = createStrictMock(Collection.class);
-    expect(data2.add(capture(capturedInstanceData))).andReturn(true);
-    replay(data2);
+    Collection<ViewInstanceDataEntity> data1 = Arrays.asList(dataEntity);
+    List<ViewInstanceDataEntity> data2 = new ArrayList<>();
 
     ViewInstanceEntity instanceEntity1 = getViewInstanceEntityMock(entity1);
-    expect(instanceEntity1.getData()).andReturn(data1);
+    expect(instanceEntity1.getData()).andReturn(data1).anyTimes();
     ViewInstanceEntity instanceEntity2 = getViewInstanceEntityMock(entity2);
-    expect(instanceEntity2.getData()).andReturn(data2);
+    expect(instanceEntity2.getData()).andReturn(data2).anyTimes();
     replay(instanceEntity1, instanceEntity2);
 
     ViewDataMigrationContextImpl context = new TestViewDataMigrationContextImpl(instanceEntity1, instanceEntity2);
     context.copyAllInstanceData();
 
-    verify(data2);
-    Assert.assertEquals("user1", capturedInstanceData.getValue().getUser());
-    Assert.assertEquals("name1", capturedInstanceData.getValue().getName());
-    Assert.assertEquals("value1", capturedInstanceData.getValue().getValue());
+    Assert.assertEquals(1, data2.size());
+    Assert.assertEquals("user1", data2.get(0).getUser());
+    Assert.assertEquals("name1", data2.get(0).getName());
+    Assert.assertEquals("value1", data2.get(0).getValue());
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationUtilityTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationUtilityTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationUtilityTest.java
new file mode 100644
index 0000000..f997589
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewDataMigrationUtilityTest.java
@@ -0,0 +1,184 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.ambari.server.view;
+
+import junit.framework.Assert;
+import org.apache.ambari.server.api.services.ViewDataMigrationService;
+import org.apache.ambari.server.orm.entities.ViewEntity;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.view.migration.ViewDataMigrationContext;
+import org.apache.ambari.view.migration.ViewDataMigrationException;
+import org.apache.ambari.view.migration.ViewDataMigrator;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.*;
+
+/**
+ * ViewDataMigrationUtility Tests.
+ */
+public class ViewDataMigrationUtilityTest {
+
+  private static String viewName = "MY_VIEW";
+  private static String instanceName = "INSTANCE1";
+  private static String version1 = "1.0.0";
+  private static String version2 = "2.0.0";
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  ViewRegistry viewRegistry;
+
+  @Before
+  public void setUp() throws Exception {
+    viewRegistry = createNiceMock(ViewRegistry.class);
+    viewRegistry.copyPrivileges(anyObject(ViewInstanceEntity.class), anyObject(ViewInstanceEntity.class));
+    expectLastCall().anyTimes();
+    replay(viewRegistry);
+    ViewRegistry.initInstance(viewRegistry);
+  }
+
+  @Test
+  public void testMigrateDataSameVersions() throws Exception {
+    TestViewDataMigrationUtility migrationUtility = new TestViewDataMigrationUtility(viewRegistry);
+
+    ViewDataMigrationContextImpl context = getViewDataMigrationContext(42, 42);
+    migrationUtility.setMigrationContext(context);
+
+    ViewDataMigrator migrator =  migrationUtility.getViewDataMigrator(
+        getInstanceDefinition(viewName, version2, instanceName), context);
+
+    Assert.assertTrue(migrator instanceof ViewDataMigrationUtility.CopyAllDataMigrator);
+  }
+
+  @Test
+  public void testMigrateDataDifferentVersions() throws Exception {
+    TestViewDataMigrationUtility migrationUtility = new TestViewDataMigrationUtility(viewRegistry);
+
+    ViewDataMigrationContextImpl context = getViewDataMigrationContext(2, 1);
+    migrationUtility.setMigrationContext(context);
+
+    ViewDataMigrator migrator = createStrictMock(ViewDataMigrator.class);
+    expect(migrator.beforeMigration()).andReturn(true);
+    migrator.migrateEntity(anyObject(Class.class), anyObject(Class.class)); expectLastCall();
+    migrator.migrateInstanceData(); expectLastCall();
+    migrator.afterMigration(); expectLastCall();
+
+    replay(migrator);
+
+    ViewInstanceEntity targetInstance = getInstanceDefinition(viewName, version2, instanceName, migrator);
+    ViewInstanceEntity sourceInstance = getInstanceDefinition(viewName, version1, instanceName);
+    migrationUtility.migrateData(targetInstance, sourceInstance, false);
+
+    verify(migrator);
+  }
+
+  @Test
+  public void testMigrateDataDifferentVersionsCancel() throws Exception {
+    TestViewDataMigrationUtility migrationUtility = new TestViewDataMigrationUtility(viewRegistry);
+
+    ViewDataMigrationContextImpl context = getViewDataMigrationContext(2, 1);
+    migrationUtility.setMigrationContext(context);
+
+    ViewDataMigrator migrator = createStrictMock(ViewDataMigrator.class);
+    expect(migrator.beforeMigration()).andReturn(false);
+
+    ViewInstanceEntity targetInstance = getInstanceDefinition(viewName, version2, instanceName, migrator);
+    ViewInstanceEntity sourceInstance = getInstanceDefinition(viewName, version1, instanceName);
+
+    thrown.expect(ViewDataMigrationException.class);
+    migrationUtility.migrateData(targetInstance, sourceInstance, false);
+  }
+
+  private static ViewDataMigrationContextImpl getViewDataMigrationContext(int currentVersion, int originVersion) {
+    Map<String, Class> entities = Collections.<String, Class>singletonMap("MyEntityClass", Object.class);
+    ViewDataMigrationContextImpl context = createNiceMock(ViewDataMigrationContextImpl.class);
+    expect(context.getOriginDataVersion()).andReturn(originVersion).anyTimes();
+    expect(context.getCurrentDataVersion()).andReturn(currentVersion).anyTimes();
+    expect(context.getOriginEntityClasses()).andReturn(entities).anyTimes();
+    expect(context.getCurrentEntityClasses()).andReturn(entities).anyTimes();
+
+    expect(context.getCurrentInstanceDataByUser()).andReturn(new HashMap<String, Map<String, String>>());
+    replay(context);
+    return context;
+  }
+
+  private static class TestViewDataMigrationUtility extends ViewDataMigrationUtility {
+    private ViewDataMigrationContextImpl migrationContext;
+
+    public TestViewDataMigrationUtility(ViewRegistry viewRegistry) {
+      super(viewRegistry);
+    }
+
+    @Override
+    protected ViewDataMigrationContextImpl getViewDataMigrationContext(ViewInstanceEntity targetInstanceDefinition,
+                                                                       ViewInstanceEntity sourceInstanceDefinition) {
+      if (migrationContext == null) {
+        return super.getViewDataMigrationContext(targetInstanceDefinition, sourceInstanceDefinition);
+      }
+      return migrationContext;
+    }
+
+    public ViewDataMigrationContextImpl getMigrationContext() {
+      return migrationContext;
+    }
+
+    public void setMigrationContext(ViewDataMigrationContextImpl migrationContext) {
+      this.migrationContext = migrationContext;
+    }
+  }
+
+  private ViewInstanceEntity getInstanceDefinition(String viewName, String viewVersion, String instanceName) {
+    ViewDataMigrator migrator = createNiceMock(ViewDataMigrator.class);
+    replay(migrator);
+    return getInstanceDefinition(viewName, viewVersion, instanceName, migrator);
+  }
+
+  private ViewInstanceEntity getInstanceDefinition(String viewName, String viewVersion, String instanceName,
+                                                   ViewDataMigrator migrator) {
+    ViewEntity viewEntity = createNiceMock(ViewEntity.class);
+    expect(viewEntity.getViewName()).andReturn(viewName);
+    expect(viewEntity.getVersion()).andReturn(viewVersion);
+
+    replay(viewEntity);
+
+    ViewInstanceEntity instanceEntity = createNiceMock(ViewInstanceEntity.class);
+    expect(instanceEntity.getViewEntity()).andReturn(viewEntity);
+    expect(instanceEntity.getViewName()).andReturn(viewName);
+    expect(instanceEntity.getInstanceName()).andReturn(instanceName);
+
+    try {
+      expect(instanceEntity.getDataMigrator(anyObject(ViewDataMigrationContext.class))).
+          andReturn(migrator);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    replay(instanceEntity);
+    return instanceEntity;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/a20fd0e2/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
index 5b24b19..6b560ee 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
@@ -334,12 +334,12 @@ public class ViewRegistryTest {
     jarFiles.put(viewArchive, viewJarFile);
 
     // set expectations
-    expect(configuration.getViewsDir()).andReturn(viewDir);
+    expect(configuration.getViewsDir()).andReturn(viewDir).anyTimes();
     if (System.getProperty("os.name").contains("Windows")) {
-      expect(viewDir.getAbsolutePath()).andReturn("\\var\\lib\\ambari-server\\resources\\views");
+      expect(viewDir.getAbsolutePath()).andReturn("\\var\\lib\\ambari-server\\resources\\views").anyTimes();
     }
     else {
-      expect(viewDir.getAbsolutePath()).andReturn("/var/lib/ambari-server/resources/views");
+      expect(viewDir.getAbsolutePath()).andReturn("/var/lib/ambari-server/resources/views").anyTimes();
     }
 
     expect(configuration.getViewExtractionThreadPoolCoreSize()).andReturn(2).anyTimes();