You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sqoop.apache.org by ab...@apache.org on 2014/10/28 01:17:09 UTC

git commit: SQOOP-1576: Sqoop2: Validations: Migrate Repository upgrade to the new validator infrastructure

Repository: sqoop
Updated Branches:
  refs/heads/sqoop2 3c7e3ea9f -> 96cb5ef1f


SQOOP-1576: Sqoop2: Validations: Migrate Repository upgrade to the new validator infrastructure

(Jarek Jarcec Cecho via Abraham Elmahrek)


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

Branch: refs/heads/sqoop2
Commit: 96cb5ef1f67fda33e8fa03f24385b5f7a90f63bd
Parents: 3c7e3ea
Author: Abraham Elmahrek <ab...@elmahrek.com>
Authored: Mon Oct 27 16:59:30 2014 -0700
Committer: Abraham Elmahrek <ab...@elmahrek.com>
Committed: Mon Oct 27 16:59:30 2014 -0700

----------------------------------------------------------------------
 .../org/apache/sqoop/model/ConfigUtils.java     | 33 ++++++++
 .../java/org/apache/sqoop/model/ModelError.java |  4 +-
 .../org/apache/sqoop/model/TestConfigUtils.java |  9 ++
 .../org/apache/sqoop/repository/Repository.java | 75 ++++++++++-------
 .../sqoop/repository/TestJdbcRepository.java    | 89 ++++++--------------
 .../apache/sqoop/handler/JobRequestHandler.java | 35 ++++----
 .../sqoop/handler/LinkRequestHandler.java       | 17 ++--
 7 files changed, 137 insertions(+), 125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sqoop/blob/96cb5ef1/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java b/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
index 372e7d3..923a943 100644
--- a/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
+++ b/common/src/main/java/org/apache/sqoop/model/ConfigUtils.java
@@ -20,6 +20,7 @@ package org.apache.sqoop.model;
 import org.apache.commons.lang.StringUtils;
 import org.apache.sqoop.common.SqoopException;
 import org.apache.sqoop.utils.ClassUtils;
+import org.apache.sqoop.validation.ConfigValidationRunner;
 import org.apache.sqoop.validation.Message;
 import org.apache.sqoop.validation.Status;
 import org.apache.sqoop.validation.ConfigValidator;
@@ -208,6 +209,38 @@ public class  ConfigUtils {
   }
 
   /**
+   * Convenience method to directly validate given model classes without the need to
+   * manually create the configuration instance.
+   *
+   * @param configs Model representation with filled values
+   * @param configClass Configuration class
+   * @return Validation result
+   */
+  public static ConfigValidationResult validateConfigs(List<MConfig> configs, Class configClass) {
+    ConfigValidationRunner validationRunner = new ConfigValidationRunner();
+    Object configInstance = fromConfigs(configs, configClass);
+    return validationRunner.validate(configInstance);
+  }
+
+  /**
+   * Convenience method to convert given model structure into configuration object
+   * that will be created from given class.
+   *
+   * @param configs Model representation with filled values
+   * @param configClass Configuration class
+   * @return Created instance based on the class with filled values
+   */
+  public static Object fromConfigs(List<MConfig> configs, Class configClass) {
+    Object configInstance = ClassUtils.instantiate(configClass);
+    if(configInstance == null) {
+      throw new SqoopException(ModelError.MODEL_016, configClass.getCanonicalName());
+    }
+
+    fromConfigs(configs, configInstance);
+    return configInstance;
+  }
+
+  /**
    * Move config values from config list into corresponding configuration object.
    *
    * @param configs Input config list

http://git-wip-us.apache.org/repos/asf/sqoop/blob/96cb5ef1/common/src/main/java/org/apache/sqoop/model/ModelError.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/model/ModelError.java b/common/src/main/java/org/apache/sqoop/model/ModelError.java
index 35a8943..a991781 100644
--- a/common/src/main/java/org/apache/sqoop/model/ModelError.java
+++ b/common/src/main/java/org/apache/sqoop/model/ModelError.java
@@ -52,7 +52,9 @@ public enum ModelError implements ErrorCode {
 
   MODEL_014("Form name attribute cannot be more than 30 characters long"),
 
-  MODEL_015("Can't get value from object")
+  MODEL_015("Can't get value from object"),
+
+  MODEL_016("Can't instantiate class"),
 
   ;
 

http://git-wip-us.apache.org/repos/asf/sqoop/blob/96cb5ef1/common/src/test/java/org/apache/sqoop/model/TestConfigUtils.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/sqoop/model/TestConfigUtils.java b/common/src/test/java/org/apache/sqoop/model/TestConfigUtils.java
index 2a7281a..64ffdd1 100644
--- a/common/src/test/java/org/apache/sqoop/model/TestConfigUtils.java
+++ b/common/src/test/java/org/apache/sqoop/model/TestConfigUtils.java
@@ -111,6 +111,15 @@ public class TestConfigUtils extends TestCase {
     assertEquals("value", config.aConfig.a1);
   }
 
+  public void testFromConfigWithClass() {
+    List<MConfig> configs = getConfigs();
+
+    ((MStringInput)configs.get(0).getInputs().get(0)).setValue("value");
+
+    TestConfiguration config = (TestConfiguration) ConfigUtils.fromConfigs(configs, TestConfiguration.class);
+    assertEquals("value", config.aConfig.a1);
+  }
+
   public void testFillValuesObjectReuse() {
     List<MConfig> configs = getConfigs();
 

http://git-wip-us.apache.org/repos/asf/sqoop/blob/96cb5ef1/core/src/main/java/org/apache/sqoop/repository/Repository.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/sqoop/repository/Repository.java b/core/src/main/java/org/apache/sqoop/repository/Repository.java
index bd2a3be..fcee48b 100644
--- a/core/src/main/java/org/apache/sqoop/repository/Repository.java
+++ b/core/src/main/java/org/apache/sqoop/repository/Repository.java
@@ -21,7 +21,9 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
+import org.apache.sqoop.common.Direction;
 import org.apache.sqoop.common.SqoopException;
 import org.apache.sqoop.connector.ConnectorManager;
 import org.apache.sqoop.connector.spi.ConnectorConfigurableUpgrader;
@@ -41,9 +43,8 @@ import org.apache.sqoop.model.MLinkConfig;
 import org.apache.sqoop.model.MPersistableEntity;
 import org.apache.sqoop.model.MSubmission;
 import org.apache.sqoop.model.MToConfig;
-import org.apache.sqoop.utils.ClassUtils;
-import org.apache.sqoop.validation.ConfigValidator;
-import org.apache.sqoop.validation.Validator;
+import org.apache.sqoop.validation.ConfigValidationResult;
+import org.apache.sqoop.validation.Message;
 
 
 /**
@@ -402,7 +403,6 @@ public abstract class Repository {
       SqoopConnector connector = ConnectorManager.getInstance().getSqoopConnector(
           newConnector.getUniqueName());
 
-      Validator connectorConfigValidator = connector.getConfigValidator();
       boolean upgradeSuccessful = true;
       // 1. Get an upgrader for the connector
       ConnectorConfigurableUpgrader upgrader = connector.getConfigurableUpgrader();
@@ -430,19 +430,17 @@ public abstract class Repository {
           upgrader.upgradeLinkConfig(oldLinkConfig, newLinkConfig);
           MLink newlink = new MLink(link, newLinkConfig);
 
-          Object newConfigurationObject = ClassUtils.instantiate(connector
-              .getLinkConfigurationClass());
-          ConfigUtils.fromConfigs(newlink.getConnectorLinkConfig().getConfigs(),
-              newConfigurationObject);
           // 7. Run link config validation
-          ConfigValidator configValidator = connectorConfigValidator
-              .validateConfigForLink(newConfigurationObject);
-          if (configValidator.getStatus().canProceed()) {
+          ConfigValidationResult validationResult = ConfigUtils.validateConfigs(
+            newlink.getConnectorLinkConfig().getConfigs(),
+            connector.getLinkConfigurationClass()
+          );
+          if (validationResult.getStatus().canProceed()) {
             updateLink(newlink, tx);
           } else {
             // If any invalid links or jobs detected, throw an exception
             // and stop the bootup of Sqoop server
-            logInvalidModelObject("link", newlink, configValidator);
+            logInvalidModelObject("link", newlink, validationResult);
             upgradeSuccessful = false;
           }
         }
@@ -461,10 +459,20 @@ public abstract class Repository {
             // create a job with new FROM direction configs but old TO direction
             // configs
             MJob newJob = new MJob(job, newFromConfig, oldToConfig, job.getDriverConfig());
-            // TODO( jarcec) : will add the job config validation logic similar
-            // to the link config validation before updating job
-            updateJob(newJob, tx);
+
+            ConfigValidationResult validationResult = ConfigUtils.validateConfigs(
+              newJob.getFromJobConfig().getConfigs(),
+              connector.getJobConfigurationClass(Direction.FROM)
+            );
+
+            if(validationResult.getStatus().canProceed()) {
+              updateJob(newJob, tx);
+            } else {
+              logInvalidModelObject("job", newJob, validationResult);
+              upgradeSuccessful = false;
+            }
           }
+
           List<MConfig> toConfig = newConnector.getToConfig().clone(false).getConfigs();
           if (job.getToConnectorId() == newConnector.getPersistenceId()) {
             MToConfig oldToConfig = job.getToJobConfig();
@@ -474,9 +482,18 @@ public abstract class Repository {
             // create a job with old FROM direction configs but new TO direction
             // configs
             MJob newJob = new MJob(job, oldFromConfig, newToConfig, job.getDriverConfig());
-            // TODO( jarcec) : will add the job config validation logic similar
-            // to the link config validation before updating job
-            updateJob(newJob, tx);
+
+            ConfigValidationResult validationResult = ConfigUtils.validateConfigs(
+              newJob.getToJobConfig().getConfigs(),
+              connector.getJobConfigurationClass(Direction.TO)
+            );
+
+             if(validationResult.getStatus().canProceed()) {
+               updateJob(newJob, tx);
+             } else {
+               logInvalidModelObject("job", newJob, validationResult);
+               upgradeSuccessful = false;
+             }
           }
         }
       }
@@ -512,7 +529,6 @@ public abstract class Repository {
       DriverUpgrader upgrader = Driver.getInstance().getConfigurableUpgrader();
       //2. find all jobs in the system
       List<MJob> existingJobs = findJobs();
-      Validator validator = Driver.getInstance().getValidator();
       boolean upgradeSuccessful = true;
 
       // -- BEGIN TXN --
@@ -533,16 +549,16 @@ public abstract class Repository {
         // create a new job with old FROM and TO configs but new driver configs
         MJob newJob = new MJob(job, job.getFromJobConfig(), job.getToJobConfig(), newDriver.getDriverConfig());
 
-        Object newConfigurationObject = ClassUtils.instantiate(Driver.getInstance().getDriverJobConfigurationClass());
-        ConfigUtils.fromConfigs(newJob.getDriverConfig().getConfigs(), newConfigurationObject);
-
         // 5. validate configs
-        ConfigValidator validation = validator.validateConfigForJob(newConfigurationObject);
-        if (validation.getStatus().canProceed()) {
+        ConfigValidationResult validationResult = ConfigUtils.validateConfigs(
+          newJob.getDriverConfig().getConfigs(),
+          Driver.getInstance().getDriverJobConfigurationClass()
+        );
+        if (validationResult.getStatus().canProceed()) {
           // 6. update job
           updateJob(newJob, tx);
         } else {
-          logInvalidModelObject("job", newJob, validation);
+          logInvalidModelObject("job", newJob, validationResult);
           upgradeSuccessful = false;
         }
       }
@@ -570,11 +586,12 @@ public abstract class Repository {
     }
   }
 
-  private void logInvalidModelObject(String objectType, MPersistableEntity entity, ConfigValidator validation) {
-    LOG.error("Upgrader created invalid " + objectType + " with id" + entity.getPersistenceId());
+  private void logInvalidModelObject(String objectType, MPersistableEntity entity, ConfigValidationResult validation) {
+    LOG.error("Upgrader created invalid " + objectType + " with id " + entity.getPersistenceId());
+    LOG.error("Validation errors:");
 
-    for(Map.Entry<ConfigValidator.ConfigInput, ConfigValidator.Message> entry : validation.getMessages().entrySet()) {
-      LOG.error("\t" + entry.getKey() + ": " + entry.getValue());
+    for(Map.Entry<String, List<Message>> entry : validation.getMessages().entrySet()) {
+      LOG.error("\t" + entry.getKey() + ": " + StringUtils.join(entry.getValue(), ","));
     }
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sqoop/blob/96cb5ef1/core/src/test/java/org/apache/sqoop/repository/TestJdbcRepository.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/sqoop/repository/TestJdbcRepository.java b/core/src/test/java/org/apache/sqoop/repository/TestJdbcRepository.java
index e11fd10..a1e734e 100644
--- a/core/src/test/java/org/apache/sqoop/repository/TestJdbcRepository.java
+++ b/core/src/test/java/org/apache/sqoop/repository/TestJdbcRepository.java
@@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
@@ -43,6 +42,7 @@ import java.util.List;
 import org.apache.sqoop.common.Direction;
 import org.apache.sqoop.common.SqoopException;
 import org.apache.sqoop.connector.ConnectorManager;
+import org.apache.sqoop.connector.common.EmptyConfiguration;
 import org.apache.sqoop.connector.spi.ConnectorConfigurableUpgrader;
 import org.apache.sqoop.connector.spi.SqoopConnector;
 import org.apache.sqoop.driver.Driver;
@@ -59,9 +59,9 @@ import org.apache.sqoop.model.MJob;
 import org.apache.sqoop.model.MLink;
 import org.apache.sqoop.model.MLinkConfig;
 import org.apache.sqoop.model.MToConfig;
-import org.apache.sqoop.validation.ConfigValidator;
+import org.apache.sqoop.model.Validator;
 import org.apache.sqoop.validation.Status;
-import org.apache.sqoop.validation.Validator;
+import org.apache.sqoop.validation.validators.AbstractValidator;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.InOrder;
@@ -73,20 +73,15 @@ public class TestJdbcRepository {
   private ConnectorManager connectorMgrMock;
   private Driver driverMock;
   private JdbcRepositoryHandler repoHandlerMock;
-  private Validator validatorMock;
   private ConnectorConfigurableUpgrader connectorUpgraderMock;
   private DriverUpgrader driverUpgraderMock;
 
-  private ConfigValidator validRepoMock;
-  private ConfigValidator invalidRepoMock;
-
   @Before
   public void setUp() throws Exception {
     repoTransactionMock = mock(JdbcRepositoryTransaction.class);
     connectorMgrMock = mock(ConnectorManager.class);
     driverMock = mock(Driver.class);
     repoHandlerMock = mock(JdbcRepositoryHandler.class);
-    validatorMock = mock(Validator.class);
     connectorUpgraderMock = mock(ConnectorConfigurableUpgrader.class);
     driverUpgraderMock = mock(DriverUpgrader.class);
     repoSpy = spy(new JdbcRepository(repoHandlerMock, null));
@@ -96,11 +91,6 @@ public class TestJdbcRepository {
     ConnectorManager.setInstance(connectorMgrMock);
     Driver.setInstance(driverMock);
 
-    validRepoMock = mock(ConfigValidator.class);
-    when(validRepoMock.getStatus()).thenReturn(Status.ACCEPTABLE);
-    invalidRepoMock = mock(ConfigValidator.class);
-    when(invalidRepoMock.getStatus()).thenReturn(Status.UNACCEPTABLE);
-
     doNothing().when(connectorUpgraderMock).upgradeLinkConfig(any(MLinkConfig.class),
         any(MLinkConfig.class));
     doNothing().when(connectorUpgraderMock).upgradeFromJobConfig(any(MFromConfig.class),
@@ -223,13 +213,9 @@ public class TestJdbcRepository {
 
     // prepare the sqoop connector
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(validatorMock.validateConfigForLink(any(MLink.class))).thenReturn(validRepoMock);
-    when(validatorMock.validateConfigForJob(any(MJob.class))).thenReturn(validRepoMock);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
-    when(sqconnector.getLinkConfigurationClass()).thenReturn(EmptyLinkConfiguration.class);
-    when(sqconnector.getJobConfigurationClass(any(Direction.class))).thenReturn(
-        EmptyJobConfiguration.class);
+    when(sqconnector.getLinkConfigurationClass()).thenReturn(EmptyConfiguration.class);
+    when(sqconnector.getJobConfigurationClass(any(Direction.class))).thenReturn(EmptyConfiguration.class);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
     // prepare the links and jobs
@@ -249,7 +235,6 @@ public class TestJdbcRepository {
     InOrder repoOrder = inOrder(repoSpy);
     InOrder txOrder = inOrder(repoTransactionMock);
     InOrder upgraderOrder = inOrder(connectorUpgraderMock);
-    InOrder validatorOrder = inOrder(validatorMock);
 
     repoOrder.verify(repoSpy, times(1)).findLinksForConnector(anyLong());
     repoOrder.verify(repoSpy, times(1)).findJobsForConnector(anyLong());
@@ -272,9 +257,6 @@ public class TestJdbcRepository {
     upgraderOrder.verify(connectorUpgraderMock, times(1)).upgradeFromJobConfig(any(MFromConfig.class), any(MFromConfig.class));
     upgraderOrder.verify(connectorUpgraderMock, times(1)).upgradeToJobConfig(any(MToConfig.class), any(MToConfig.class));
     upgraderOrder.verifyNoMoreInteractions();
-    validatorOrder.verify(validatorMock, times(2)).validateConfigForLink(anyObject());
-    validatorOrder.verify(validatorMock, times(0)).validateConfigForJob(anyObject());
-    validatorOrder.verifyNoMoreInteractions();
   }
 
   /**
@@ -285,11 +267,8 @@ public class TestJdbcRepository {
   public void testDriverConfigUpgradeWithValidJobs() {
     MDriver newDriverConfig = driver();
 
-    when(validatorMock.validateConfigForLink(any(MLink.class))).thenReturn(validRepoMock);
-    when(validatorMock.validateConfigForJob(any(MJob.class))).thenReturn(validRepoMock);
-    when(driverMock.getValidator()).thenReturn(validatorMock);
     when(driverMock.getConfigurableUpgrader()).thenReturn(driverUpgraderMock);
-    when(driverMock.getDriverJobConfigurationClass()).thenReturn(EmptyJobConfiguration.class);
+    when(driverMock.getDriverJobConfigurationClass()).thenReturn(ValidConfiguration.class);
     List<MJob> jobList = jobs(job(1,1,1,1,1), job(2,1,1,2,1));
 
     doReturn(jobList).when(repoSpy).findJobs();
@@ -302,7 +281,6 @@ public class TestJdbcRepository {
     InOrder repoOrder = inOrder(repoSpy);
     InOrder txOrder = inOrder(repoTransactionMock);
     InOrder upgraderOrder = inOrder(driverUpgraderMock);
-    InOrder validatorOrder = inOrder(validatorMock);
 
     repoOrder.verify(repoSpy, times(1)).findJobs();
     repoOrder.verify(repoSpy, times(1)).getTransaction();
@@ -317,8 +295,6 @@ public class TestJdbcRepository {
     txOrder.verifyNoMoreInteractions();
     upgraderOrder.verify(driverUpgraderMock, times(2)).upgradeJobConfig(any(MDriverConfig.class), any(MDriverConfig.class));
     upgraderOrder.verifyNoMoreInteractions();
-    validatorOrder.verify(validatorMock, times(2)).validateConfigForJob(anyObject());
-    validatorOrder.verifyNoMoreInteractions();
   }
 
   /**
@@ -329,11 +305,8 @@ public class TestJdbcRepository {
   public void testDriverConfigUpgradeWithInvalidJobs() {
     MDriver newDriverConfig = driver();
 
-    when(validatorMock.validateConfigForLink(any(MLink.class))).thenReturn(invalidRepoMock);
-    when(validatorMock.validateConfigForJob(any(MJob.class))).thenReturn(invalidRepoMock);
-    when(driverMock.getValidator()).thenReturn(validatorMock);
     when(driverMock.getConfigurableUpgrader()).thenReturn(driverUpgraderMock);
-    when(driverMock.getDriverJobConfigurationClass()).thenReturn(EmptyJobConfiguration.class);
+    when(driverMock.getDriverJobConfigurationClass()).thenReturn(InvalidConfiguration.class);
     List<MJob> jobList = jobs(job(1,1,1,1,1), job(2,1,1,2,1));
 
     doReturn(jobList).when(repoSpy).findJobs();
@@ -348,7 +321,6 @@ public class TestJdbcRepository {
       InOrder repoOrder = inOrder(repoSpy);
       InOrder txOrder = inOrder(repoTransactionMock);
       InOrder upgraderOrder = inOrder(driverUpgraderMock);
-      InOrder validatorOrder = inOrder(validatorMock);
 
       repoOrder.verify(repoSpy, times(1)).findJobs();
       repoOrder.verify(repoSpy, times(1)).getTransaction();
@@ -362,9 +334,6 @@ public class TestJdbcRepository {
       txOrder.verifyNoMoreInteractions();
       upgraderOrder.verify(driverUpgraderMock, times(2)).upgradeJobConfig(any(MDriverConfig.class), any(MDriverConfig.class));
       upgraderOrder.verifyNoMoreInteractions();
-      // driver configs are per job.
-      validatorOrder.verify(validatorMock, times(2)).validateConfigForJob(anyObject());
-      validatorOrder.verifyNoMoreInteractions();
       return ;
     }
 
@@ -381,7 +350,6 @@ public class TestJdbcRepository {
     MConnector oldConnector = connector(1);
 
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
@@ -411,7 +379,6 @@ public class TestJdbcRepository {
     MConnector oldConnector = connector(1);
 
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
@@ -445,7 +412,6 @@ public class TestJdbcRepository {
     MConnector oldConnector = connector(1);
 
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
@@ -482,7 +448,6 @@ public class TestJdbcRepository {
     MConnector oldConnector = connector(1);
 
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
@@ -521,7 +486,6 @@ public class TestJdbcRepository {
     MConnector oldConnector = connector(1);
 
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
@@ -562,12 +526,9 @@ public class TestJdbcRepository {
     MConnector oldConnector = connector(1);
 
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(validatorMock.validateConfigForLink(any(MLink.class))).thenReturn(validRepoMock);
-    when(validatorMock.validateConfigForJob(any(MJob.class))).thenReturn(validRepoMock);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
-    when(sqconnector.getLinkConfigurationClass()).thenReturn(EmptyLinkConfiguration.class);
-    when(sqconnector.getJobConfigurationClass(any(Direction.class))).thenReturn(EmptyJobConfiguration.class);
+    when(sqconnector.getLinkConfigurationClass()).thenReturn(ValidConfiguration.class);
+    when(sqconnector.getJobConfigurationClass(any(Direction.class))).thenReturn(ValidConfiguration.class);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
     List<MLink> linkList = links(link(1,1), link(2,1));
@@ -611,12 +572,9 @@ public class TestJdbcRepository {
     MConnector oldConnector = connector(1);
 
     SqoopConnector sqconnector = mock(SqoopConnector.class);
-    when(validatorMock.validateConfigForLink(any(MLink.class))).thenReturn(validRepoMock);
-    when(validatorMock.validateConfigForJob(any(MJob.class))).thenReturn(validRepoMock);
-    when(sqconnector.getConfigValidator()).thenReturn(validatorMock);
     when(sqconnector.getConfigurableUpgrader()).thenReturn(connectorUpgraderMock);
-    when(sqconnector.getLinkConfigurationClass()).thenReturn(EmptyLinkConfiguration.class);
-    when(sqconnector.getJobConfigurationClass(any(Direction.class))).thenReturn(EmptyJobConfiguration.class);
+    when(sqconnector.getLinkConfigurationClass()).thenReturn(ValidConfiguration.class);
+    when(sqconnector.getJobConfigurationClass(any(Direction.class))).thenReturn(ValidConfiguration.class);
     when(connectorMgrMock.getSqoopConnector(anyString())).thenReturn(sqconnector);
 
     List<MLink> linkList = links(link(1,1), link(2,1));
@@ -662,7 +620,6 @@ public class TestJdbcRepository {
   public void testDriverConfigUpgradeHandlerWithFindJobsError() {
     MDriver newDriverConfig = driver();
 
-    when(driverMock.getValidator()).thenReturn(validatorMock);
     when(driverMock.getConfigurableUpgrader()).thenReturn(driverUpgraderMock);
 
     SqoopException exception = new SqoopException(RepositoryError.JDBCREPO_0000,
@@ -689,7 +646,6 @@ public class TestJdbcRepository {
   public void testDriverConfigUpgradeHandlerWithDeleteJobInputsError() {
     MDriver newDriverConfig = driver();
 
-    when(driverMock.getValidator()).thenReturn(validatorMock);
     when(driverMock.getConfigurableUpgrader()).thenReturn(driverUpgraderMock);
 
     List<MJob> jobList = jobs(job(1,1,1,1,1), job(2,1,1,2,1));
@@ -720,7 +676,6 @@ public class TestJdbcRepository {
   public void testDriverConfigUpgradeHandlerWithUpdateDriverConfigError() {
     MDriver newDriverConfig = driver();
 
-    when(driverMock.getValidator()).thenReturn(validatorMock);
     when(driverMock.getConfigurableUpgrader()).thenReturn(driverUpgraderMock);
 
     List<MJob> jobList = jobs(job(1,1,1,1,1), job(2,1,1,2,1));
@@ -755,11 +710,8 @@ public class TestJdbcRepository {
   public void testDriverConfigUpgradeHandlerWithUpdateJobError() {
     MDriver driverConfig = driver();
 
-    when(validatorMock.validateConfigForLink(any(MLink.class))).thenReturn(validRepoMock);
-    when(validatorMock.validateConfigForJob(any(MJob.class))).thenReturn(validRepoMock);
-    when(driverMock.getValidator()).thenReturn(validatorMock);
     when(driverMock.getConfigurableUpgrader()).thenReturn(driverUpgraderMock);
-    when(driverMock.getDriverJobConfigurationClass()).thenReturn(EmptyJobConfiguration.class);
+    when(driverMock.getDriverJobConfigurationClass()).thenReturn(ValidConfiguration.class);
     List<MJob> jobList = jobs(job(1,1,1,1,1), job(2,1,1,2,1));
     doReturn(jobList).when(repoHandlerMock).findJobs(any(Connection.class));
     doNothing().when(repoHandlerMock).deleteJobInputs(anyLong(), any(Connection.class));
@@ -789,8 +741,8 @@ public class TestJdbcRepository {
   private MConnector connector(long connectorId, String version) {
     MConnector connector = new MConnector("A" + connectorId, "A" + connectorId, version + connectorId,
         new MLinkConfig(new LinkedList<MConfig>()),
-        new MFromConfig(ConfigUtils.toConfigs(EmptyJobConfiguration.class)),
-        new MToConfig(ConfigUtils.toConfigs(EmptyJobConfiguration.class)));
+        new MFromConfig(ConfigUtils.toConfigs(ValidConfiguration.class)),
+        new MToConfig(ConfigUtils.toConfigs(ValidConfiguration.class)));
     connector.setPersistenceId(connectorId);
     return connector;
   }
@@ -840,9 +792,16 @@ public class TestJdbcRepository {
   }
 
   @ConfigurationClass
-  public static class EmptyLinkConfiguration {
+  public static class ValidConfiguration {
   }
-  @ConfigurationClass
-  public static class EmptyJobConfiguration {
+
+  @ConfigurationClass(validators = { @Validator(InvalidConfiguration.InternalValidator.class)})
+  public static class InvalidConfiguration {
+    public static class InternalValidator extends AbstractValidator {
+      @Override
+      public void validate(Object instance) {
+        addMessage(Status.UNACCEPTABLE, "Simply because.");
+      }
+    }
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sqoop/blob/96cb5ef1/server/src/main/java/org/apache/sqoop/handler/JobRequestHandler.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/handler/JobRequestHandler.java b/server/src/main/java/org/apache/sqoop/handler/JobRequestHandler.java
index 61b1610..fdb7c26 100644
--- a/server/src/main/java/org/apache/sqoop/handler/JobRequestHandler.java
+++ b/server/src/main/java/org/apache/sqoop/handler/JobRequestHandler.java
@@ -191,27 +191,24 @@ public class JobRequestHandler implements RequestHandler {
           + " does not support TO direction.");
     }
 
-    // We need translate configs
-    Object fromConfigObject = ClassUtils.instantiate(fromConnector.getJobConfigurationClass(Direction.FROM));
-    Object toConfigObject = ClassUtils.instantiate(toConnector.getJobConfigurationClass(Direction.TO));
-
-    Object driverConfigObject = ClassUtils.instantiate(Driver.getInstance().getDriverJobConfigurationClass());
-
-    ConfigUtils.fromConfigs(job.getJobConfig(Direction.FROM).getConfigs(), fromConfigObject);
-    ConfigUtils.fromConfigs(job.getJobConfig(Direction.TO).getConfigs(), toConfigObject);
-    ConfigUtils.fromConfigs(job.getDriverConfig().getConfigs(), driverConfigObject);
-
-    // Validate all configs
-    ConfigValidationRunner validationRunner = new ConfigValidationRunner();
-    ConfigValidationResult fromConfigvalidator = validationRunner.validate(fromConfigObject);
-    ConfigValidationResult toConfigValidator = validationRunner.validate(toConfigObject);
-    ConfigValidationResult driverConfigValidator = validationRunner.validate(driverConfigObject);
-
-
-    Status finalStatus = Status.getWorstStatus(fromConfigvalidator.getStatus(), toConfigValidator.getStatus(), driverConfigValidator.getStatus());
+    // Validate user supplied data
+    ConfigValidationResult fromConfigValidator = ConfigUtils.validateConfigs(
+      job.getJobConfig(Direction.FROM).getConfigs(),
+      fromConnector.getJobConfigurationClass(Direction.FROM)
+    );
+    ConfigValidationResult toConfigValidator = ConfigUtils.validateConfigs(
+      job.getJobConfig(Direction.TO).getConfigs(),
+      toConnector.getJobConfigurationClass(Direction.TO)
+    );
+    ConfigValidationResult driverConfigValidator = ConfigUtils.validateConfigs(
+      job.getDriverConfig().getConfigs(),
+      Driver.getInstance().getDriverJobConfigurationClass()
+    );
+
+    Status finalStatus = Status.getWorstStatus(fromConfigValidator.getStatus(), toConfigValidator.getStatus(), driverConfigValidator.getStatus());
 
     // Return back validations in all cases
-    ValidationResultBean validationResultBean = new ValidationResultBean(fromConfigvalidator, toConfigValidator);
+    ValidationResultBean validationResultBean = new ValidationResultBean(fromConfigValidator, toConfigValidator);
 
     // If we're good enough let's perform the action
     if(finalStatus.canProceed()) {

http://git-wip-us.apache.org/repos/asf/sqoop/blob/96cb5ef1/server/src/main/java/org/apache/sqoop/handler/LinkRequestHandler.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/handler/LinkRequestHandler.java b/server/src/main/java/org/apache/sqoop/handler/LinkRequestHandler.java
index b715ad3..823426a 100644
--- a/server/src/main/java/org/apache/sqoop/handler/LinkRequestHandler.java
+++ b/server/src/main/java/org/apache/sqoop/handler/LinkRequestHandler.java
@@ -168,22 +168,17 @@ public class LinkRequestHandler implements RequestHandler {
     // Responsible connector for this session
     SqoopConnector connector = ConnectorManager.getInstance().getSqoopConnector(link.getConnectorId());
 
-    // We need translate configs
-    Object connectorLinkConfig = ClassUtils.instantiate(connector.getLinkConfigurationClass());
-
-    ConfigUtils.fromConfigs(link.getConnectorLinkConfig().getConfigs(), connectorLinkConfig);
-
-    // Validate both parts
-    ConfigValidationRunner validationRunner = new ConfigValidationRunner();
-    ConfigValidationResult connectorLinkValidation = validationRunner.validate(connectorLinkConfig);
-
-    Status finalStatus = Status.getWorstStatus(connectorLinkValidation.getStatus());
+    // Validate user supplied data
+    ConfigValidationResult connectorLinkValidation = ConfigUtils.validateConfigs(
+      link.getConnectorLinkConfig().getConfigs(),
+      connector.getLinkConfigurationClass()
+    );
 
     // Return back validations in all cases
     ValidationResultBean outputBean = new ValidationResultBean(connectorLinkValidation);
 
     // If we're good enough let's perform the action
-    if(finalStatus.canProceed()) {
+    if(connectorLinkValidation.getStatus().canProceed()) {
       if(update) {
         AuditLoggerManager.getInstance()
             .logAuditEvent(ctx.getUserName(), ctx.getRequest().getRemoteAddr(),