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 06:15:43 UTC

git commit: SQOOP-1513: Sqoop2: Refactor LinkRequestHandler

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


SQOOP-1513: Sqoop2: Refactor LinkRequestHandler

(Veena Basavaraj 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/eed2b3f5
Tree: http://git-wip-us.apache.org/repos/asf/sqoop/tree/eed2b3f5
Diff: http://git-wip-us.apache.org/repos/asf/sqoop/diff/eed2b3f5

Branch: refs/heads/sqoop2
Commit: eed2b3f50a1d0568cc20d5667aa35de0be3f629f
Parents: 96cb5ef
Author: Abraham Elmahrek <ab...@elmahrek.com>
Authored: Mon Oct 27 22:14:44 2014 -0700
Committer: Abraham Elmahrek <ab...@elmahrek.com>
Committed: Mon Oct 27 22:14:44 2014 -0700

----------------------------------------------------------------------
 .../client/request/LinkResourceRequest.java     |  35 +--
 .../java/org/apache/sqoop/json/LinkBean.java    |  33 ++-
 .../java/org/apache/sqoop/json/LinksBean.java   |  59 ++++
 .../org/apache/sqoop/json/TestLinkBean.java     |   6 +-
 .../apache/sqoop/repository/JdbcRepository.java |  28 +-
 .../sqoop/repository/JdbcRepositoryHandler.java |  25 +-
 .../org/apache/sqoop/repository/Repository.java |  18 +-
 .../derby/DerbyRepositoryHandler.java           | 112 +++++---
 ...erbySchemaInsertUpdateDeleteSelectQuery.java |  15 +
 .../repository/derby/TestLinkHandling.java      |  34 ++-
 .../apache/sqoop/handler/JobRequestHandler.java |   2 -
 .../sqoop/handler/LinkRequestHandler.java       | 283 ++++++++++---------
 .../org/apache/sqoop/server/RequestContext.java |   8 +
 .../apache/sqoop/server/common/ServerError.java |   3 +
 .../sqoop/server/v1/ConnectorServlet.java       |   2 +-
 .../apache/sqoop/server/v1/DriverServlet.java   |   2 +-
 .../org/apache/sqoop/server/v1/LinkServlet.java |  27 ++
 .../apache/sqoop/server/v1/LinksServlet.java    |  48 ++++
 server/src/main/webapp/WEB-INF/web.xml          |  12 +
 .../apache/sqoop/shell/UpdateLinkFunction.java  |   1 +
 20 files changed, 504 insertions(+), 249 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/client/src/main/java/org/apache/sqoop/client/request/LinkResourceRequest.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/sqoop/client/request/LinkResourceRequest.java b/client/src/main/java/org/apache/sqoop/client/request/LinkResourceRequest.java
index 64e5cb1..f03acb4 100644
--- a/client/src/main/java/org/apache/sqoop/client/request/LinkResourceRequest.java
+++ b/client/src/main/java/org/apache/sqoop/client/request/LinkResourceRequest.java
@@ -18,6 +18,7 @@
 package org.apache.sqoop.client.request;
 
 import org.apache.sqoop.json.LinkBean;
+import org.apache.sqoop.json.LinksBean;
 import org.apache.sqoop.json.ValidationResultBean;
 import org.apache.sqoop.model.MLink;
 import org.json.simple.JSONObject;
@@ -29,30 +30,33 @@ import org.json.simple.JSONValue;
  */
 public class LinkResourceRequest extends ResourceRequest {
 
-  public static final String RESOURCE = "v1/link/";
+  public static final String LINK_RESOURCE = "v1/link/";
 
   private static final String ENABLE = "/enable";
   private static final String DISABLE = "/disable";
 
-  public LinkBean read(String serverUrl, Long xid) {
+  public LinkBean read(String serverUrl, Long linkId) {
     String response;
-    if (xid == null) {
-      response = super.get(serverUrl + RESOURCE + "all");
+    if (linkId == null) {
+      response = super.get(serverUrl + LINK_RESOURCE + "all");
     } else {
-      response = super.get(serverUrl + RESOURCE + xid);
+      response = super.get(serverUrl + LINK_RESOURCE + linkId);
     }
-    JSONObject jsonObject = (JSONObject)JSONValue.parse(response);
-    LinkBean linkBean = new LinkBean();
-    linkBean.restore(jsonObject);
-    return linkBean;
+    JSONObject jsonObject = (JSONObject) JSONValue.parse(response);
+    // defaults to all
+    LinkBean bean = new LinksBean();
+    if (linkId != null) {
+      bean = new LinkBean();
+    }
+    bean.restore(jsonObject);
+    return bean;
   }
 
   public ValidationResultBean create(String serverUrl, MLink link) {
     LinkBean linkBean = new LinkBean(link);
-
     // Extract all config inputs including sensitive inputs
     JSONObject linkJson = linkBean.extract(false);
-    String response = super.post(serverUrl + RESOURCE, linkJson.toJSONString());
+    String response = super.post(serverUrl + LINK_RESOURCE, linkJson.toJSONString());
     ValidationResultBean validationBean = new ValidationResultBean();
     validationBean.restore((JSONObject) JSONValue.parse(response));
     return validationBean;
@@ -60,24 +64,23 @@ public class LinkResourceRequest extends ResourceRequest {
 
   public ValidationResultBean update(String serverUrl, MLink link) {
     LinkBean linkBean = new LinkBean(link);
-
     // Extract all config inputs including sensitive inputs
     JSONObject linkJson = linkBean.extract(false);
-    String response = super.put(serverUrl + RESOURCE + link.getPersistenceId(), linkJson.toJSONString());
+    String response = super.put(serverUrl + LINK_RESOURCE + link.getPersistenceId(), linkJson.toJSONString());
     ValidationResultBean validationBean = new ValidationResultBean();
     validationBean.restore((JSONObject) JSONValue.parse(response));
     return validationBean;
   }
 
   public void delete(String serverUrl, Long id) {
-     super.delete(serverUrl + RESOURCE + id);
+     super.delete(serverUrl + LINK_RESOURCE + id);
   }
 
   public void enable(String serverUrl, Long id, Boolean enabled) {
     if (enabled) {
-      super.put(serverUrl + RESOURCE + id + ENABLE, null);
+      super.put(serverUrl + LINK_RESOURCE + id + ENABLE, null);
     } else {
-      super.put(serverUrl + RESOURCE + id + DISABLE, null);
+      super.put(serverUrl + LINK_RESOURCE + id + DISABLE, null);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/common/src/main/java/org/apache/sqoop/json/LinkBean.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/json/LinkBean.java b/common/src/main/java/org/apache/sqoop/json/LinkBean.java
index 2762500..bc59352 100644
--- a/common/src/main/java/org/apache/sqoop/json/LinkBean.java
+++ b/common/src/main/java/org/apache/sqoop/json/LinkBean.java
@@ -19,8 +19,6 @@ package org.apache.sqoop.json;
 
 import static org.apache.sqoop.json.util.ConfigInputSerialization.extractConfigList;
 import static org.apache.sqoop.json.util.ConfigInputSerialization.restoreConfigList;
-import static org.apache.sqoop.json.util.ConfigBundleSerialization.extractConfigParamBundle;
-import static org.apache.sqoop.json.util.ConfigBundleSerialization.restoreConfigParamBundle;
 
 import java.util.ArrayList;
 import java.util.Date;
@@ -45,8 +43,11 @@ public class LinkBean implements JsonBean {
 
   static final String CONNECTOR_ID = "connector-id";
   static final String LINK_CONFIG = "link-config";
+  static final String LINK = "link";
+
 
   // Required
+  // Stores all links for a given connector
   private List<MLink> links;
 
   // Optional
@@ -85,14 +86,20 @@ public class LinkBean implements JsonBean {
     return linkConfigBundles.get(id);
   }
 
-  @Override
   @SuppressWarnings("unchecked")
+  @Override
   public JSONObject extract(boolean skipSensitive) {
     JSONArray linkArray = new JSONArray();
+    extractLinks(skipSensitive, linkArray);
+    JSONObject all = new JSONObject();
+    all.put(LINK, linkArray);
+    return all;
+  }
 
+  @SuppressWarnings("unchecked")
+  protected void extractLinks(boolean skipSensitive, JSONArray linkArray) {
     for(MLink link : links) {
       JSONObject linkJsonObject = new JSONObject();
-
       linkJsonObject.put(ID, link.getPersistenceId());
       linkJsonObject.put(NAME, link.getName());
       linkJsonObject.put(ENABLED, link.getEnabled());
@@ -103,31 +110,24 @@ public class LinkBean implements JsonBean {
       linkJsonObject.put(CONNECTOR_ID, link.getConnectorId());
       linkJsonObject.put(LINK_CONFIG,
         extractConfigList(link.getConnectorLinkConfig().getConfigs(), link.getConnectorLinkConfig().getType(), skipSensitive));
-
       linkArray.add(linkJsonObject);
     }
-
-    JSONObject all = new JSONObject();
-    all.put(ALL, linkArray);
-    return all;
   }
 
   @Override
   public void restore(JSONObject jsonObject) {
-    links = new ArrayList<MLink>();
-
-    JSONArray array = (JSONArray) jsonObject.get(ALL);
+    JSONArray array = (JSONArray) jsonObject.get(LINK);
+    restoreLinks(array);
+  }
 
+  protected void restoreLinks(JSONArray array) {
+    links = new ArrayList<MLink>();
     for (Object obj : array) {
       JSONObject object = (JSONObject) obj;
-
       long connectorId = (Long) object.get(CONNECTOR_ID);
       JSONArray connectorLinkConfig = (JSONArray) object.get(LINK_CONFIG);
-
       List<MConfig> linkConfig = restoreConfigList(connectorLinkConfig);
-
       MLink link = new MLink(connectorId, new MLinkConfig(linkConfig));
-
       link.setPersistenceId((Long) object.get(ID));
       link.setName((String) object.get(NAME));
       link.setEnabled((Boolean) object.get(ENABLED));
@@ -135,7 +135,6 @@ public class LinkBean implements JsonBean {
       link.setCreationDate(new Date((Long) object.get(CREATION_DATE)));
       link.setLastUpdateUser((String) object.get(UPDATE_USER));
       link.setLastUpdateDate(new Date((Long) object.get(UPDATE_DATE)));
-
       links.add(link);
     }
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/common/src/main/java/org/apache/sqoop/json/LinksBean.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/sqoop/json/LinksBean.java b/common/src/main/java/org/apache/sqoop/json/LinksBean.java
new file mode 100644
index 0000000..5858a18
--- /dev/null
+++ b/common/src/main/java/org/apache/sqoop/json/LinksBean.java
@@ -0,0 +1,59 @@
+/**
+ * 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.sqoop.json;
+
+import java.util.List;
+
+import org.apache.sqoop.model.MLink;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+public class LinksBean extends LinkBean {
+
+  static final String LINKS = "links";
+
+  public LinksBean(MLink link) {
+    super(link);
+  }
+
+  public LinksBean(List<MLink> links) {
+    super(links);
+  }
+
+  // For "restore"
+  public LinksBean() {
+
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public JSONObject extract(boolean skipSensitive) {
+    JSONArray linkArray = new JSONArray();
+    super.extractLinks(skipSensitive, linkArray);
+    JSONObject links = new JSONObject();
+    links.put(LINKS, linkArray);
+    return links;
+  }
+
+  @Override
+  public void restore(JSONObject jsonObject) {
+
+    JSONArray array = (JSONArray) jsonObject.get(LINKS);
+    super.restoreLinks(array);
+  }
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/common/src/test/java/org/apache/sqoop/json/TestLinkBean.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/sqoop/json/TestLinkBean.java b/common/src/test/java/org/apache/sqoop/json/TestLinkBean.java
index 526ec52..811cbf0 100644
--- a/common/src/test/java/org/apache/sqoop/json/TestLinkBean.java
+++ b/common/src/test/java/org/apache/sqoop/json/TestLinkBean.java
@@ -59,7 +59,7 @@ public class TestLinkBean {
     JSONObject json = linkBean.extract(false);
 
     // Check for sensitivity
-    JSONArray all = (JSONArray)json.get(JsonBean.ALL);
+    JSONArray all = (JSONArray)json.get(LinkBean.LINK);
     JSONObject allItem = (JSONObject)all.get(0);
     JSONArray connectors = (JSONArray)allItem.get(LinkBean.LINK_CONFIG);
     JSONObject connector = (JSONObject)connectors.get(0);
@@ -116,7 +116,7 @@ public class TestLinkBean {
     JSONObject jsonFiltered = bean.extract(true);
 
     // Sensitive values should exist
-    JSONArray all = (JSONArray)json.get(JsonBean.ALL);
+    JSONArray all = (JSONArray)json.get(LinkBean.LINK);
     JSONObject allItem = (JSONObject)all.get(0);
     JSONArray connectors = (JSONArray)allItem.get(LinkBean.LINK_CONFIG);
     JSONObject connector = (JSONObject)connectors.get(0);
@@ -127,7 +127,7 @@ public class TestLinkBean {
     assertTrue(password.containsKey(ConfigInputConstants.CONFIG_INPUT_VALUE));
 
     // Sensitive values should not exist
-    all = (JSONArray)jsonFiltered.get(JsonBean.ALL);
+    all = (JSONArray)jsonFiltered.get(LinkBean.LINK);
     allItem = (JSONObject)all.get(0);
     connectors = (JSONArray)allItem.get(LinkBean.LINK_CONFIG);
     connector = (JSONObject)connectors.get(0);

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/core/src/main/java/org/apache/sqoop/repository/JdbcRepository.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/sqoop/repository/JdbcRepository.java b/core/src/main/java/org/apache/sqoop/repository/JdbcRepository.java
index 254ba9e..2aeb07e 100644
--- a/core/src/main/java/org/apache/sqoop/repository/JdbcRepository.java
+++ b/core/src/main/java/org/apache/sqoop/repository/JdbcRepository.java
@@ -349,11 +349,24 @@ public class JdbcRepository extends Repository {
    * {@inheritDoc}
    */
   @Override
-  public MLink findLink(final long connectionId) {
+  public MLink findLink(final long id) {
     return (MLink) doWithConnection(new DoWithConnection() {
       @Override
       public Object doIt(Connection conn) {
-        return handler.findLink(connectionId, conn);
+        return handler.findLink(id, conn);
+      }
+    });
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public MLink findLink(final String name) {
+    return (MLink) doWithConnection(new DoWithConnection() {
+      @Override
+      public Object doIt(Connection conn) {
+        return handler.findLink(name, conn);
       }
     });
   }
@@ -609,13 +622,13 @@ public class JdbcRepository extends Repository {
   /**
    * {@inheritDoc}
    */
+  @SuppressWarnings("unchecked")
   @Override
-  public List<MLink> findLinksForConnector(final long
-    connectorID) {
+  public List<MLink> findLinksForConnector(final long connectorId) {
     return (List<MLink>) doWithConnection(new DoWithConnection() {
       @Override
       public Object doIt(Connection conn) throws Exception {
-        return handler.findLinksForConnector(connectorID, conn);
+        return handler.findLinksForConnector(connectorId, conn);
       }
     });
   }
@@ -623,12 +636,13 @@ public class JdbcRepository extends Repository {
   /**
    * {@inheritDoc}
    */
+  @SuppressWarnings("unchecked")
   @Override
-  public List<MJob> findJobsForConnector(final long connectorID) {
+  public List<MJob> findJobsForConnector(final long connectorId) {
     return (List<MJob>) doWithConnection(new DoWithConnection() {
       @Override
       public Object doIt(Connection conn) throws Exception {
-        return handler.findJobsForConnector(connectorID, conn);
+        return handler.findJobsForConnector(connectorId, conn);
       }
     });
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/core/src/main/java/org/apache/sqoop/repository/JdbcRepositoryHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/sqoop/repository/JdbcRepositoryHandler.java b/core/src/main/java/org/apache/sqoop/repository/JdbcRepositoryHandler.java
index 7d78826..ad380d3 100644
--- a/core/src/main/java/org/apache/sqoop/repository/JdbcRepositoryHandler.java
+++ b/core/src/main/java/org/apache/sqoop/repository/JdbcRepositoryHandler.java
@@ -71,22 +71,20 @@ public abstract class JdbcRepositoryHandler {
 
   /**
    * Retrieve links which use the given connector.
-   * @param connectorID Connector ID whose links should be fetched
+   * @param connectorId Connector ID whose links should be fetched
    * @param conn JDBC link for querying repository
    * @return List of MLinks that use <code>connectorID</code>.
    */
-  public abstract List<MLink> findLinksForConnector(long
-    connectorID, Connection conn);
+  public abstract List<MLink> findLinksForConnector(long connectorId, Connection conn);
 
   /**
    * Retrieve jobs which use the given link.
    *
-   * @param connectorID Connector ID whose jobs should be fetched
+   * @param connectorId Connector ID whose jobs should be fetched
    * @param conn JDBC link for querying repository
    * @return List of MJobs that use <code>linkID</code>.
    */
-  public abstract List<MJob> findJobsForConnector(long connectorID,
-    Connection conn);
+  public abstract List<MJob> findJobsForConnector(long c, Connection conn);
 
   /**
    * Upgrade the connector with the new data supplied in the <tt>newConnector</tt>.
@@ -234,20 +232,29 @@ public abstract class JdbcRepositoryHandler {
   /**
    * Delete the input values for the link with given id from the
    * repository.
-   * @param id Link object whose inputs should be removed from repository
+   * @param linkId Link object whose inputs should be removed from repository
    * @param conn Connection to the repository
    */
-  public abstract void deleteLinkInputs(long id, Connection conn);
+  public abstract void deleteLinkInputs(long linkId, Connection conn);
   /**
    * Find link with given id in repository.
    *
    * @param linkId Link id
    * @param conn Connection to the repository
-   * @return Deserialized config of the link that is saved in repository
+   * @return  the link that is saved in repository
    */
   public abstract MLink findLink(long linkId, Connection conn);
 
   /**
+   * Find link with given name in repository.
+   *
+   * @param linkName unique link name
+   * @param conn Connection to the repository
+   * @return the link that is saved in repository or returns null if not found
+   */
+  public abstract MLink findLink(String linkName, Connection conn);
+
+  /**
    * Get all link objects.
    *
    * @param conn Connection to the repository

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/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 fcee48b..79742b9 100644
--- a/core/src/main/java/org/apache/sqoop/repository/Repository.java
+++ b/core/src/main/java/org/apache/sqoop/repository/Repository.java
@@ -176,11 +176,19 @@ public abstract class Repository {
    * Find link with given id in repository.
    *
    * @param id Link id
-   * @return Deserialized config of the link that is saved in repository
+   * @return link that is saved in repository
    */
   public abstract MLink findLink(long id);
 
   /**
+   * Find link with given id in repository.
+   *
+   * @param name unique link name
+   * @return link that is saved in repository or null if it does not exists
+   */
+  public abstract MLink findLink(String name);
+
+  /**
    * Get all Link objects.
    *
    * @return List will all saved link objects
@@ -297,18 +305,18 @@ public abstract class Repository {
 
   /**
    * Retrieve links which use the given connector.
-   * @param connectorID Connector ID whose links should be fetched
+   * @param connectorId Connector ID whose links should be fetched
    * @return List of MLink that use <code>connectorID</code>.
    */
-  public abstract List<MLink> findLinksForConnector(long connectorID);
+  public abstract List<MLink> findLinksForConnector(long connectorId);
 
   /**
    * Retrieve jobs which use the given link.
    *
-   * @param connectorID Connector ID whose jobs should be fetched
+   * @param connectorId Connector ID whose jobs should be fetched
    * @return List of MJobs that use <code>linkID</code>.
    */
-  public abstract List<MJob> findJobsForConnector(long connectorID);
+  public abstract List<MJob> findJobsForConnector(long connectorId);
 
   /**
    * Update the connector with the new data supplied in the

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbyRepositoryHandler.java
----------------------------------------------------------------------
diff --git a/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbyRepositoryHandler.java b/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbyRepositoryHandler.java
index 7f19c28..e584a19 100644
--- a/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbyRepositoryHandler.java
+++ b/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbyRepositoryHandler.java
@@ -17,11 +17,9 @@
  */
 package org.apache.sqoop.repository.derby;
 
-import static org.apache.sqoop.repository.derby.DerbySchemaUpgradeQuery.*;
 import static org.apache.sqoop.repository.derby.DerbySchemaCreateQuery.*;
 import static org.apache.sqoop.repository.derby.DerbySchemaInsertUpdateDeleteSelectQuery.*;
-
-
+import static org.apache.sqoop.repository.derby.DerbySchemaUpgradeQuery.*;
 import java.net.URL;
 import java.sql.Connection;
 import java.sql.DriverManager;
@@ -158,7 +156,7 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
 
       // Register link type config
       registerConfigs(connectorId, null /* No direction for LINK type config*/, mc.getLinkConfig().getConfigs(),
-        MConfigType.LINK.name(), baseConfigStmt, baseInputStmt, conn);
+      MConfigType.LINK.name(), baseConfigStmt, baseInputStmt, conn);
 
       // Register both from/to job type config for connector
       if (mc.getSupportedDirections().isDirectionSupported(Direction.FROM)) {
@@ -1196,27 +1194,51 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
    * {@inheritDoc}
    */
   @Override
-  public MLink findLink(long id, Connection conn) {
-    PreparedStatement stmt = null;
+  public MLink findLink(long linkId, Connection conn) {
+    PreparedStatement linkFetchStmt = null;
     try {
-      stmt = conn.prepareStatement(STMT_SELECT_LINK_SINGLE);
-      stmt.setLong(1, id);
+      linkFetchStmt = conn.prepareStatement(STMT_SELECT_LINK_SINGLE);
+      linkFetchStmt.setLong(1, linkId);
 
-      List<MLink> connections = loadLinks(stmt, conn);
+      List<MLink> links = loadLinks(linkFetchStmt, conn);
 
-      if(connections.size() != 1) {
+      if(links.size() != 1) {
         throw new SqoopException(DerbyRepoError.DERBYREPO_0024, "Couldn't find"
-          + " link with id " + id);
+          + " link with id " + linkId);
       }
 
-      // Return the first and only one link object
-      return connections.get(0);
+      // Return the first and only one link object with the given id
+      return links.get(0);
 
     } catch (SQLException ex) {
-      logException(ex, id);
+      logException(ex, linkId);
       throw new SqoopException(DerbyRepoError.DERBYREPO_0023, ex);
     } finally {
-      closeStatements(stmt);
+      closeStatements(linkFetchStmt);
+    }
+  }
+
+  @Override
+  public MLink findLink(String linkName, Connection conn) {
+    PreparedStatement linkFetchStmt = null;
+    try {
+      linkFetchStmt = conn.prepareStatement(STMT_SELECT_LINK_SINGLE_BY_NAME);
+      linkFetchStmt.setString(1, linkName);
+
+      List<MLink> links = loadLinks(linkFetchStmt, conn);
+
+      if (links.size() != 1) {
+        return null;
+      }
+
+      // Return the first and only one link object with the given name
+      return links.get(0);
+
+    } catch (SQLException ex) {
+      logException(ex, linkName);
+      throw new SqoopException(DerbyRepoError.DERBYREPO_0023, ex);
+    } finally {
+      closeStatements(linkFetchStmt);
     }
   }
 
@@ -1225,17 +1247,17 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
    */
   @Override
   public List<MLink> findLinks(Connection conn) {
-    PreparedStatement stmt = null;
+    PreparedStatement linksFetchStmt = null;
     try {
-      stmt = conn.prepareStatement(STMT_SELECT_LINK_ALL);
+      linksFetchStmt = conn.prepareStatement(STMT_SELECT_LINK_ALL);
 
-      return loadLinks(stmt, conn);
+      return loadLinks(linksFetchStmt, conn);
 
     } catch (SQLException ex) {
       logException(ex);
       throw new SqoopException(DerbyRepoError.DERBYREPO_0023, ex);
     } finally {
-      closeStatements(stmt);
+      closeStatements(linksFetchStmt);
     }
   }
 
@@ -1246,17 +1268,17 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
    *
    */
   @Override
-  public List<MLink> findLinksForConnector(long connectorID, Connection conn) {
-    PreparedStatement stmt = null;
+  public List<MLink> findLinksForConnector(long connectorId, Connection conn) {
+    PreparedStatement linkByConnectorFetchStmt = null;
     try {
-      stmt = conn.prepareStatement(STMT_SELECT_LINK_FOR_CONNECTOR_CONFIGURABLE);
-      stmt.setLong(1, connectorID);
-      return loadLinks(stmt, conn);
+      linkByConnectorFetchStmt = conn.prepareStatement(STMT_SELECT_LINK_FOR_CONNECTOR_CONFIGURABLE);
+      linkByConnectorFetchStmt.setLong(1, connectorId);
+      return loadLinks(linkByConnectorFetchStmt, conn);
     } catch (SQLException ex) {
-      logException(ex, connectorID);
+      logException(ex, connectorId);
       throw new SqoopException(DerbyRepoError.DERBYREPO_0023, ex);
     } finally {
-      closeStatements(stmt);
+      closeStatements(linkByConnectorFetchStmt);
     }
   }
 
@@ -2128,7 +2150,7 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
         List<MConfig> fromConfig = new ArrayList<MConfig>();
         List<MConfig> toConfig = new ArrayList<MConfig>();
 
-        loadConfigTypes(linkConfig, fromConfig, toConfig, connectorConfigFetchStmt,
+        loadConnectorConfigTypes(linkConfig, fromConfig, toConfig, connectorConfigFetchStmt,
             connectorConfigInputFetchStmt, 1, conn);
 
         SupportedDirections supportedDirections
@@ -2154,20 +2176,16 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
     return connectors;
   }
 
-  private List<MLink> loadLinks(PreparedStatement stmt,
-                                            Connection conn)
-                                            throws SQLException {
+  private List<MLink> loadLinks(PreparedStatement linkFetchStmt, Connection conn) throws SQLException {
     List<MLink> links = new ArrayList<MLink>();
     ResultSet rsConnection = null;
-    PreparedStatement connectorConfigFetchStatement = null;
-    PreparedStatement connectorConfigInputStatement = null;
+    PreparedStatement connectorLinkConfigFetchStatement = null;
+    PreparedStatement connectorLinkConfigInputStatement = null;
 
     try {
-      rsConnection = stmt.executeQuery();
-
-      //
-      connectorConfigFetchStatement = conn.prepareStatement(STMT_SELECT_CONFIG_FOR_CONFIGURABLE);
-      connectorConfigInputStatement = conn.prepareStatement(STMT_FETCH_LINK_INPUT);
+      rsConnection = linkFetchStmt.executeQuery();
+      connectorLinkConfigFetchStatement = conn.prepareStatement(STMT_SELECT_CONFIG_FOR_CONFIGURABLE);
+      connectorLinkConfigInputStatement = conn.prepareStatement(STMT_FETCH_LINK_INPUT);
 
       while(rsConnection.next()) {
         long id = rsConnection.getLong(1);
@@ -2179,16 +2197,16 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
         String updateUser = rsConnection.getString(7);
         Date lastUpdateDate = rsConnection.getTimestamp(8);
 
-        connectorConfigFetchStatement.setLong(1, connectorId);
-        connectorConfigInputStatement.setLong(1, id);
-        connectorConfigInputStatement.setLong(3, id);
+        connectorLinkConfigFetchStatement.setLong(1, connectorId);
+        connectorLinkConfigInputStatement.setLong(1, id);
+        connectorLinkConfigInputStatement.setLong(3, id);
 
         List<MConfig> connectorLinkConfig = new ArrayList<MConfig>();
         List<MConfig> fromConfig = new ArrayList<MConfig>();
         List<MConfig> toConfig = new ArrayList<MConfig>();
 
-        loadConfigTypes(connectorLinkConfig, fromConfig, toConfig, connectorConfigFetchStatement,
-            connectorConfigInputStatement, 2, conn);
+        loadConnectorConfigTypes(connectorLinkConfig, fromConfig, toConfig, connectorLinkConfigFetchStatement,
+            connectorLinkConfigInputStatement, 2, conn);
         MLink link = new MLink(connectorId, new MLinkConfig(connectorLinkConfig));
 
         link.setPersistenceId(id);
@@ -2203,7 +2221,7 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
       }
     } finally {
       closeResultSets(rsConnection);
-      closeStatements(connectorConfigFetchStatement, connectorConfigInputStatement);
+      closeStatements(connectorLinkConfigFetchStatement, connectorLinkConfigInputStatement);
     }
 
     return links;
@@ -2254,7 +2272,7 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
         List<MConfig> fromConnectorFromJobConfig = new ArrayList<MConfig>();
         List<MConfig> fromConnectorToJobConfig = new ArrayList<MConfig>();
 
-        loadConfigTypes(fromConnectorLinkConfig, fromConnectorFromJobConfig, fromConnectorToJobConfig,
+        loadConnectorConfigTypes(fromConnectorLinkConfig, fromConnectorFromJobConfig, fromConnectorToJobConfig,
             fromConfigFetchStmt, jobInputFetchStmt, 2, conn);
 
         // TO entity configs
@@ -2265,7 +2283,7 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
         // ?? dont we need 2 different driver configs for the from/to?
         List<MConfig> driverConfig = new ArrayList<MConfig>();
 
-        loadConfigTypes(toConnectorLinkConfig, toConnectorFromJobConfig, toConnectorToJobConfig,
+        loadConnectorConfigTypes(toConnectorLinkConfig, toConnectorFromJobConfig, toConnectorToJobConfig,
             toConfigFetchStmt, jobInputFetchStmt, 2, conn);
 
         loadDriverConfigs(driverConfig, driverConfigfetchStmt, jobInputFetchStmt, 2);
@@ -2592,7 +2610,7 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
   }
 
   /**
-   * Load configs and corresponding inputs from Derby database.
+   * Load configs and corresponding inputs related to a connector
    *
    * Use given prepared statements to load all configs and corresponding inputs
    * from Derby.
@@ -2605,7 +2623,7 @@ public class DerbyRepositoryHandler extends JdbcRepositoryHandler {
    * @param conn Connection object that is used to find config direction.
    * @throws SQLException In case of any failure on Derby side
    */
-  public void loadConfigTypes(List<MConfig> linkConfig, List<MConfig> fromConfig,
+  public void loadConnectorConfigTypes(List<MConfig> linkConfig, List<MConfig> fromConfig,
       List<MConfig> toConfig, PreparedStatement configFetchStmt, PreparedStatement inputFetchStmt,
       int configPosition, Connection conn) throws SQLException {
 

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbySchemaInsertUpdateDeleteSelectQuery.java
----------------------------------------------------------------------
diff --git a/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbySchemaInsertUpdateDeleteSelectQuery.java b/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbySchemaInsertUpdateDeleteSelectQuery.java
index 02b11fc..c894d06 100644
--- a/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbySchemaInsertUpdateDeleteSelectQuery.java
+++ b/repository/repository-derby/src/main/java/org/apache/sqoop/repository/derby/DerbySchemaInsertUpdateDeleteSelectQuery.java
@@ -304,6 +304,21 @@ public final class DerbySchemaInsertUpdateDeleteSelectQuery {
      + " FROM " + TABLE_SQ_LINK
      + " WHERE " + COLUMN_SQ_LNK_ID + " = ?";
 
+
+   // DML: Select one specific link by name
+   public static final String STMT_SELECT_LINK_SINGLE_BY_NAME =
+     "SELECT "
+     + COLUMN_SQ_LNK_ID + ", "
+     + COLUMN_SQ_LNK_NAME + ", "
+     + COLUMN_SQ_LNK_CONFIGURABLE + ", "
+     + COLUMN_SQ_LNK_ENABLED + ", "
+     + COLUMN_SQ_LNK_CREATION_USER + ", "
+     + COLUMN_SQ_LNK_CREATION_DATE + ", "
+     + COLUMN_SQ_LNK_UPDATE_USER + ", "
+     + COLUMN_SQ_LNK_UPDATE_DATE
+     + " FROM " + TABLE_SQ_LINK
+     + " WHERE " + COLUMN_SQ_LNK_NAME + " = ?";
+
    // DML: Select all links
    public static final String STMT_SELECT_LINK_ALL =
      "SELECT "

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/repository/repository-derby/src/test/java/org/apache/sqoop/repository/derby/TestLinkHandling.java
----------------------------------------------------------------------
diff --git a/repository/repository-derby/src/test/java/org/apache/sqoop/repository/derby/TestLinkHandling.java b/repository/repository-derby/src/test/java/org/apache/sqoop/repository/derby/TestLinkHandling.java
index 37343d3..dabb08b 100644
--- a/repository/repository-derby/src/test/java/org/apache/sqoop/repository/derby/TestLinkHandling.java
+++ b/repository/repository-derby/src/test/java/org/apache/sqoop/repository/derby/TestLinkHandling.java
@@ -58,7 +58,7 @@ public class TestLinkHandling extends DerbyTestCase {
     try {
       handler.findLink(1, getDerbyDatabaseConnection());
       fail();
-    } catch(SqoopException ex) {
+    } catch (SqoopException ex) {
       assertEquals(DerbyRepoError.DERBYREPO_0024, ex.getErrorCode());
     }
 
@@ -81,6 +81,28 @@ public class TestLinkHandling extends DerbyTestCase {
   }
 
   @Test
+  public void testFindLinkByName() throws Exception {
+    // Let's try to find non existing link
+    assertNull(handler.findLink("non-existing", getDerbyDatabaseConnection()));
+    // Load prepared connections into database
+    loadLinksForLatestVersion();
+
+    MLink linkA = handler.findLink("CA", getDerbyDatabaseConnection());
+    assertNotNull(linkA);
+    assertEquals(1, linkA.getPersistenceId());
+    assertEquals("CA", linkA.getName());
+
+    List<MConfig> configs;
+
+    // Check connector link config
+    configs = linkA.getConnectorLinkConfig().getConfigs();
+    assertEquals("Value1", configs.get(0).getInputs().get(0).getValue());
+    assertNull(configs.get(0).getInputs().get(1).getValue());
+    assertEquals("Value3", configs.get(1).getInputs().get(0).getValue());
+    assertNull(configs.get(1).getInputs().get(1).getValue());
+  }
+
+  @Test
   public void testFindLinks() throws Exception {
     List<MLink> list;
 
@@ -146,7 +168,7 @@ public class TestLinkHandling extends DerbyTestCase {
     assertCountForTable("SQOOP.SQ_LINK_INPUT", 4);
   }
 
-  @Test(expected=SqoopException.class)
+  @Test(expected = SqoopException.class)
   public void testCreateDuplicateLink() throws Exception {
     MLink link = getLink();
     fillLink(link);
@@ -178,10 +200,10 @@ public class TestLinkHandling extends DerbyTestCase {
     List<MConfig> configs;
 
     configs = link.getConnectorLinkConfig().getConfigs();
-    ((MStringInput)configs.get(0).getInputs().get(0)).setValue("Updated");
-    ((MMapInput)configs.get(0).getInputs().get(1)).setValue(null);
-    ((MStringInput)configs.get(1).getInputs().get(0)).setValue("Updated");
-    ((MMapInput)configs.get(1).getInputs().get(1)).setValue(null);
+    ((MStringInput) configs.get(0).getInputs().get(0)).setValue("Updated");
+    ((MMapInput) configs.get(0).getInputs().get(1)).setValue(null);
+    ((MStringInput) configs.get(1).getInputs().get(0)).setValue("Updated");
+    ((MMapInput) configs.get(1).getInputs().get(1)).setValue(null);
 
     link.setName("name");
 

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/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 fdb7c26..5547988 100644
--- a/server/src/main/java/org/apache/sqoop/handler/JobRequestHandler.java
+++ b/server/src/main/java/org/apache/sqoop/handler/JobRequestHandler.java
@@ -41,9 +41,7 @@ import org.apache.sqoop.repository.RepositoryManager;
 import org.apache.sqoop.server.RequestContext;
 import org.apache.sqoop.server.RequestHandler;
 import org.apache.sqoop.server.common.ServerError;
-import org.apache.sqoop.utils.ClassUtils;
 import org.apache.sqoop.validation.ConfigValidationResult;
-import org.apache.sqoop.validation.ConfigValidationRunner;
 import org.apache.sqoop.validation.Status;
 import org.json.simple.JSONObject;
 import org.json.simple.JSONValue;

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/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 823426a..35a9635 100644
--- a/server/src/main/java/org/apache/sqoop/handler/LinkRequestHandler.java
+++ b/server/src/main/java/org/apache/sqoop/handler/LinkRequestHandler.java
@@ -18,6 +18,7 @@
 package org.apache.sqoop.handler;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
@@ -28,6 +29,7 @@ import org.apache.sqoop.connector.ConnectorManager;
 import org.apache.sqoop.connector.spi.SqoopConnector;
 import org.apache.sqoop.json.JsonBean;
 import org.apache.sqoop.json.LinkBean;
+import org.apache.sqoop.json.LinksBean;
 import org.apache.sqoop.json.ValidationResultBean;
 import org.apache.sqoop.model.ConfigUtils;
 import org.apache.sqoop.model.MLink;
@@ -37,48 +39,19 @@ import org.apache.sqoop.repository.RepositoryManager;
 import org.apache.sqoop.server.RequestContext;
 import org.apache.sqoop.server.RequestHandler;
 import org.apache.sqoop.server.common.ServerError;
-import org.apache.sqoop.utils.ClassUtils;
-import org.apache.sqoop.validation.Status;
 import org.apache.sqoop.validation.ConfigValidationResult;
-import org.apache.sqoop.validation.ConfigValidationRunner;
 import org.json.simple.JSONObject;
 import org.json.simple.JSONValue;
 
-/**
- * Connection request handler is supporting following resources:
- *
- * GET /v1/link/:xid
- * Return details about one particular link with id :xid or about all of
- * them if :xid equals to "all".
- *
- * POST /v1/link
- * Create new link
- *
- * PUT /v1/link/:xid
- * Update link with id :xid.
- *
- * PUT /v1/link/:xid/enable
- * Enable link with id :xid
- *
- * PUT /v1/link/:xid/disable
- * Disable link with id :xid
- *
- * DELETE /v1/link/:xid
- * Remove link with id :xid
- *
- * Planned resources:
- *
- * GET /v1/link
- * Get brief list of all links present in the system.
- *
- */
 public class LinkRequestHandler implements RequestHandler {
 
-  private static final Logger LOG =
-      Logger.getLogger(LinkRequestHandler.class);
+  private static final Logger LOG = Logger.getLogger(LinkRequestHandler.class);
 
-  private static final String ENABLE = "enable";
-  private static final String DISABLE = "disable";
+  static final String ENABLE = "enable";
+  static final String DISABLE = "disable";
+  static final String LINKS_PATH = "links";
+  static final String LINK_PATH = "link";
+  static final String CONNECTOR_NAME_QUERY_PARAM = "cname";
 
   public LinkRequestHandler() {
     LOG.info("LinkRequestHandler initialized");
@@ -87,163 +60,203 @@ public class LinkRequestHandler implements RequestHandler {
   @Override
   public JsonBean handleEvent(RequestContext ctx) {
     switch (ctx.getMethod()) {
-      case GET:
-        return getLink(ctx);
-      case POST:
-          return createUpdateLink(ctx, false);
-      case PUT:
-        if (ctx.getLastURLElement().equals(ENABLE)) {
-          return enableLink(ctx, true);
-        } else if (ctx.getLastURLElement().equals(DISABLE)) {
-          return enableLink(ctx, false);
-        } else {
-          return createUpdateLink(ctx, true);
-        }
-      case DELETE:
-        return deleteLink(ctx);
+    case GET:
+      return getLinks(ctx);
+    case POST:
+      return createUpdateLink(ctx, true);
+    case PUT:
+      if (ctx.getLastURLElement().equals(ENABLE)) {
+        return enableLink(ctx, true);
+      } else if (ctx.getLastURLElement().equals(DISABLE)) {
+        return enableLink(ctx, false);
+      } else {
+        return createUpdateLink(ctx, false);
+      }
+    case DELETE:
+      return deleteLink(ctx);
     }
 
     return null;
   }
 
   /**
-   * Delete link from thes repository.
+   * Delete link in the repository.
    *
    * @param ctx Context object
    * @return Empty bean
    */
   private JsonBean deleteLink(RequestContext ctx) {
-    String sxid = ctx.getLastURLElement();
-    long xid = Long.valueOf(sxid);
-
-    AuditLoggerManager.getInstance()
-        .logAuditEvent(ctx.getUserName(), ctx.getRequest().getRemoteAddr(),
-        "delete", "link", sxid);
-
     Repository repository = RepositoryManager.getInstance().getRepository();
-    repository.deleteLink(xid);
+    String linkIdentifier = ctx.getLastURLElement();
+    // support linkName or linkId for the api
+    long linkId = getLinkIdFromIdentifier(linkIdentifier, repository);
+
+    AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
+        ctx.getRequest().getRemoteAddr(), "delete", "link", linkIdentifier);
 
+    repository.deleteLink(linkId);
     return JsonBean.EMPTY_BEAN;
   }
 
   /**
-   * Update or create link in repository.
+   * Create or Update link in repository.
    *
    * @param ctx Context object
    * @return Validation bean object
    */
-  private JsonBean createUpdateLink(RequestContext ctx, boolean update) {
+  private JsonBean createUpdateLink(RequestContext ctx, boolean create) {
+
+    Repository repository = RepositoryManager.getInstance().getRepository();
 
     String username = ctx.getUserName();
-    LinkBean bean = new LinkBean();
+    LinkBean linkBean = new LinkBean();
     try {
-      JSONObject json =
-        (JSONObject) JSONValue.parse(ctx.getRequest().getReader());
-
-      bean.restore(json);
+      JSONObject postData = (JSONObject) JSONValue.parse(ctx.getRequest().getReader());
+      linkBean.restore(postData);
     } catch (IOException e) {
-      throw new SqoopException(ServerError.SERVER_0003,
-        "Can't read request content", e);
+      throw new SqoopException(ServerError.SERVER_0003, "Can't read request content", e);
     }
 
     // Get link object
-    List<MLink> links = bean.getLinks();
-
-    if(links.size() != 1) {
+    List<MLink> links = linkBean.getLinks();
+    if (links.size() != 1) {
       throw new SqoopException(ServerError.SERVER_0003,
-        "Expected one link but got " + links.size());
+          "Expected one link while parsing JSON request but got " + links.size());
     }
 
     MLink link = links.get(0);
-
-    // Verify that user is not trying to spoof us
-    MLinkConfig linkConfig =
-      ConnectorManager.getInstance().getConnectorConfigurable(link.getConnectorId())
-      .getLinkConfig();
-    if(!linkConfig.equals(link.getConnectorLinkConfig())) {
-      throw new SqoopException(ServerError.SERVER_0003,
-        "Detected incorrect config structure");
+    MLinkConfig linkConfig = ConnectorManager.getInstance()
+        .getConnectorConfigurable(link.getConnectorId()).getLinkConfig();
+    if (!linkConfig.equals(link.getConnectorLinkConfig())) {
+      throw new SqoopException(ServerError.SERVER_0003, "Detected incorrect link config structure");
     }
+    // if update get the link id from the request URI
+    if (!create) {
+      String linkIdentifier = ctx.getLastURLElement();
+      // support linkName or linkId for the api
+      long linkId = getLinkIdFromIdentifier(linkIdentifier, repository);
+      MLink existingLink = repository.findLink(linkId);
+      link.setConnectorId(existingLink.getConnectorId());
+    }
+    // Associated connector for this link
+    SqoopConnector connector = ConnectorManager.getInstance().getSqoopConnector(
+        link.getConnectorId());
 
-    // Responsible connector for this session
-    SqoopConnector connector = ConnectorManager.getInstance().getSqoopConnector(link.getConnectorId());
-
-    // Validate user supplied data
-    ConfigValidationResult connectorLinkValidation = ConfigUtils.validateConfigs(
-      link.getConnectorLinkConfig().getConfigs(),
-      connector.getLinkConfigurationClass()
-    );
-
-    // Return back validations in all cases
-    ValidationResultBean outputBean = new ValidationResultBean(connectorLinkValidation);
+    // Validate user supplied config data
+    ConfigValidationResult connectorLinkConfigValidation = ConfigUtils.validateConfigs(link
+        .getConnectorLinkConfig().getConfigs(), connector.getLinkConfigurationClass());
+    // Return back link validation result bean
+    ValidationResultBean linkValidationBean = new ValidationResultBean(
+        connectorLinkConfigValidation);
 
     // If we're good enough let's perform the action
-    if(connectorLinkValidation.getStatus().canProceed()) {
-      if(update) {
-        AuditLoggerManager.getInstance()
-            .logAuditEvent(ctx.getUserName(), ctx.getRequest().getRemoteAddr(),
-            "update", "link", String.valueOf(link.getPersistenceId()));
-
+    if (connectorLinkConfigValidation.getStatus().canProceed()) {
+      if (create) {
+        AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
+            ctx.getRequest().getRemoteAddr(), "create", "link",
+            String.valueOf(link.getPersistenceId()));
+        link.setCreationUser(username);
         link.setLastUpdateUser(username);
-        RepositoryManager.getInstance().getRepository().updateLink(link);
+        repository.createLink(link);
+        linkValidationBean.setId(link.getPersistenceId());
       } else {
-        link.setCreationUser(username);
+        AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
+            ctx.getRequest().getRemoteAddr(), "update", "link",
+            String.valueOf(link.getPersistenceId()));
         link.setLastUpdateUser(username);
-        RepositoryManager.getInstance().getRepository().createLink(link);
-        outputBean.setId(link.getPersistenceId());
-
-        AuditLoggerManager.getInstance()
-            .logAuditEvent(ctx.getUserName(), ctx.getRequest().getRemoteAddr(),
-            "create", "link", String.valueOf(link.getPersistenceId()));
+        repository.updateLink(link);
       }
     }
 
-    return outputBean;
+    return linkValidationBean;
   }
 
-  private JsonBean getLink(RequestContext ctx) {
-    String sxid = ctx.getLastURLElement();
-    LinkBean bean;
-
-    AuditLoggerManager.getInstance()
-        .logAuditEvent(ctx.getUserName(), ctx.getRequest().getRemoteAddr(),
-        "get", "link", sxid);
-
+  private JsonBean getLinks(RequestContext ctx) {
+    String identifier = ctx.getLastURLElement();
+    LinkBean linkBean;
     Locale locale = ctx.getAcceptLanguageHeader();
     Repository repository = RepositoryManager.getInstance().getRepository();
 
-    if (sxid.equals("all")) {
-
-      List<MLink> links = repository.findLinks();
-      bean = new LinkBean(links);
-
-      // Add associated resources into the bean
-      for( MLink link : links) {
-        long connectorId = link.getConnectorId();
-        if(!bean.hasConnectorConfigBundle(connectorId)) {
-          bean.addConnectorConfigBundle(connectorId,
-            ConnectorManager.getInstance().getResourceBundle(connectorId, locale));
-        }
+    // links by connector
+    if (ctx.getParameterValue(CONNECTOR_NAME_QUERY_PARAM) != null) {
+      identifier = ctx.getParameterValue(CONNECTOR_NAME_QUERY_PARAM);
+      AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
+          ctx.getRequest().getRemoteAddr(), "get", "linksByConnector", identifier);
+      if (repository.findConnector(identifier) != null) {
+        long connectorId = repository.findConnector(identifier).getPersistenceId();
+        linkBean = createLinksBean(repository.findLinksForConnector(connectorId), locale);
+      } else {
+        // this means name nor Id existed
+        throw new SqoopException(ServerError.SERVER_0005, "Invalid connector: " + identifier
+            + " name for links given");
       }
+    } else
+    // all links in the system
+    if (ctx.getPath().contains(LINKS_PATH)
+        || (ctx.getPath().contains(LINK_PATH) && identifier.equals("all"))) {
+      AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
+          ctx.getRequest().getRemoteAddr(), "get", "links", "all");
+      linkBean = createLinksBean(repository.findLinks(), locale);
+    }
+    // link by Id
+    else {
+      AuditLoggerManager.getInstance().logAuditEvent(ctx.getUserName(),
+          ctx.getRequest().getRemoteAddr(), "get", "link", identifier);
+
+      long linkId = getLinkIdFromIdentifier(identifier, repository);
+      List<MLink> linkList = new ArrayList<MLink>();
+      // a list of single element
+      linkList.add(repository.findLink(linkId));
+      linkBean = createLinkBean(linkList, locale);
+    }
+    return linkBean;
+  }
+
+  private long getLinkIdFromIdentifier(String identifier, Repository repository) {
+    // support linkName or linkId for the api
+    long linkId;
+    if (repository.findLink(identifier) != null) {
+      linkId = repository.findLink(identifier).getPersistenceId();
     } else {
-      long xid = Long.valueOf(sxid);
+      try {
+        linkId = Long.valueOf(identifier);
+      } catch (NumberFormatException ex) {
+        // this means name nor Id existed
+        throw new SqoopException(ServerError.SERVER_0005, "Invalid link: " + identifier
+            + " requested");
+      }
+    }
+    return linkId;
+  }
 
-      MLink link = repository.findLink(xid);
-      long connectorId = link.getConnectorId();
+  private LinkBean createLinkBean(List<MLink> links, Locale locale) {
+    LinkBean linkBean = new LinkBean(links);
+    addLink(links, locale, linkBean);
+    return linkBean;
+  }
 
-      bean = new LinkBean(link);
+  private LinksBean createLinksBean(List<MLink> links, Locale locale) {
+    LinksBean linksBean = new LinksBean(links);
+    addLink(links, locale, linksBean);
+    return linksBean;
+  }
 
-      bean.addConnectorConfigBundle(connectorId,
-        ConnectorManager.getInstance().getResourceBundle(connectorId, locale));
+  private void addLink(List<MLink> links, Locale locale, LinkBean bean) {
+    // Add associated resources into the bean
+    for (MLink link : links) {
+      long connectorId = link.getConnectorId();
+      if (!bean.hasConnectorConfigBundle(connectorId)) {
+        bean.addConnectorConfigBundle(connectorId, ConnectorManager.getInstance()
+            .getResourceBundle(connectorId, locale));
+      }
     }
-    return bean;
   }
 
   private JsonBean enableLink(RequestContext ctx, boolean enabled) {
-    String[] elements = ctx.getUrlElements();
-    String sLinkId = elements[elements.length - 2];
-    long linkId = Long.valueOf(sLinkId);
     Repository repository = RepositoryManager.getInstance().getRepository();
+    String[] elements = ctx.getUrlElements();
+    String linkIdentifier = elements[elements.length - 2];
+    long linkId = getLinkIdFromIdentifier(linkIdentifier, repository);
     repository.enableLink(linkId, enabled);
     return JsonBean.EMPTY_BEAN;
   }

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/server/src/main/java/org/apache/sqoop/server/RequestContext.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/server/RequestContext.java b/server/src/main/java/org/apache/sqoop/server/RequestContext.java
index b1a74fc..54e9cca 100644
--- a/server/src/main/java/org/apache/sqoop/server/RequestContext.java
+++ b/server/src/main/java/org/apache/sqoop/server/RequestContext.java
@@ -93,6 +93,14 @@ public class RequestContext {
   }
 
   /**
+   * Return a value for given query parameter name
+   */
+  public String getParameterValue(String name) {
+    String[] values = getRequest().getParameterValues(name);
+    return values != null ? values[0] : null;
+  }
+
+  /**
    * Get locale specified in accept-language HTTP header.
    *
    * @return First specified locale

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/server/src/main/java/org/apache/sqoop/server/common/ServerError.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/server/common/ServerError.java b/server/src/main/java/org/apache/sqoop/server/common/ServerError.java
index 02d9174..c68ab57 100644
--- a/server/src/main/java/org/apache/sqoop/server/common/ServerError.java
+++ b/server/src/main/java/org/apache/sqoop/server/common/ServerError.java
@@ -36,6 +36,9 @@ public enum ServerError implements ErrorCode {
   /** Invalid argument in HTTP request */
   SERVER_0004("Invalid argument in HTTP request"),
 
+  /** Invalid entity requested */
+  SERVER_0005("Invalid entity requested"),
+
   ;
 
   private final String message;

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/server/src/main/java/org/apache/sqoop/server/v1/ConnectorServlet.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/server/v1/ConnectorServlet.java b/server/src/main/java/org/apache/sqoop/server/v1/ConnectorServlet.java
index 781abc3..2bc06ac 100644
--- a/server/src/main/java/org/apache/sqoop/server/v1/ConnectorServlet.java
+++ b/server/src/main/java/org/apache/sqoop/server/v1/ConnectorServlet.java
@@ -25,7 +25,7 @@ import org.apache.sqoop.server.SqoopProtocolServlet;
 
 
 /**
- * Connector request handler is supporting following resources:
+ * Displays connector(s) registered in sqoop
  *
  * GET v1/connector/all (remains for backward compatibility)
  *  Return all connectors registered in the sqoop system with their corresponding config params

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/server/src/main/java/org/apache/sqoop/server/v1/DriverServlet.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/server/v1/DriverServlet.java b/server/src/main/java/org/apache/sqoop/server/v1/DriverServlet.java
index 43454fd..192d866 100644
--- a/server/src/main/java/org/apache/sqoop/server/v1/DriverServlet.java
+++ b/server/src/main/java/org/apache/sqoop/server/v1/DriverServlet.java
@@ -24,7 +24,7 @@ import org.apache.sqoop.server.RequestHandler;
 import org.apache.sqoop.server.SqoopProtocolServlet;
 
 /**
- * Driver request handler is supporting following resources:
+ * Displays driver registered in sqoop
  *
  * GET /v1/driver/
  *  Return details about the registered driver and its configs

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/server/src/main/java/org/apache/sqoop/server/v1/LinkServlet.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/server/v1/LinkServlet.java b/server/src/main/java/org/apache/sqoop/server/v1/LinkServlet.java
index 20e5009..127903a 100644
--- a/server/src/main/java/org/apache/sqoop/server/v1/LinkServlet.java
+++ b/server/src/main/java/org/apache/sqoop/server/v1/LinkServlet.java
@@ -24,6 +24,33 @@ import org.apache.sqoop.server.RequestHandler;
 import org.apache.sqoop.server.SqoopProtocolServlet;
 
 /**
+ * Provides operations for link resource
+ *
+ * GET /v1/link/{lid}
+ *  Return details about one particular link with id :lid
+ * GET /v1/link/{lname}
+ *  Return details about one particular link with name :lname
+ *
+ * POST /v1/link/ with {connector-id} and {link-config-id} in the post data
+ *  Create link for connector with id connector-id
+ * PUT /v1/link/ with {connector-id} and {link-config-id} in the post data
+ *  Edit/Update link for connector with id connector-id
+
+ * PUT /v1/link/{lid}
+ *  Edit/Update details about one particular link with id :lid
+ * PUT /v1/link/{lname}
+ *  Edit/Update details about one particular link with name :lname
+ *
+ * DELETE /v1/link/{lid}
+ *  Delete/Remove one particular link with id :lid
+ * DELETE /v1/link/{lname}
+ *  Delete/Remove one particular link with name :lname
+ *
+ * PUT /v1/link/{lname}/enable
+ * Enable link with id :lname
+ *
+ * PUT /v1/link/{lname}/disable
+ * Disable link with id :lname
  *
  */
 @SuppressWarnings("serial")

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/server/src/main/java/org/apache/sqoop/server/v1/LinksServlet.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/sqoop/server/v1/LinksServlet.java b/server/src/main/java/org/apache/sqoop/server/v1/LinksServlet.java
new file mode 100644
index 0000000..d249d6c
--- /dev/null
+++ b/server/src/main/java/org/apache/sqoop/server/v1/LinksServlet.java
@@ -0,0 +1,48 @@
+/**
+ * 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.sqoop.server.v1;
+
+import org.apache.sqoop.handler.LinkRequestHandler;
+import org.apache.sqoop.json.JsonBean;
+import org.apache.sqoop.server.RequestContext;
+import org.apache.sqoop.server.RequestHandler;
+import org.apache.sqoop.server.SqoopProtocolServlet;
+
+/**
+ * Displays all or links per connector in sqoop
+ *
+ * GET /v1/links
+ *  Return details about every link that exists in the sqoop system
+ * GET /v1/links?cname=
+ *  Return details about link(s) for a given connector name {cname}
+*/
+@SuppressWarnings("serial")
+public class LinksServlet extends SqoopProtocolServlet {
+
+  private RequestHandler linkRequestHandler;
+
+  public LinksServlet() {
+    linkRequestHandler = new LinkRequestHandler();
+  }
+
+  @Override
+  protected JsonBean handleGetRequest(RequestContext ctx) throws Exception {
+    return linkRequestHandler.handleEvent(ctx);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/server/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/server/src/main/webapp/WEB-INF/web.xml b/server/src/main/webapp/WEB-INF/web.xml
index a6f7b0d..6ad90d2 100644
--- a/server/src/main/webapp/WEB-INF/web.xml
+++ b/server/src/main/webapp/WEB-INF/web.xml
@@ -99,6 +99,18 @@ limitations under the License.
     <url-pattern>/v1/link/*</url-pattern>
   </servlet-mapping>
 
+ <!-- Links servlet -->
+  <servlet>
+    <servlet-name>v1.LinksServlet</servlet-name>
+    <servlet-class>org.apache.sqoop.server.v1.LinksServlet</servlet-class>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>v1.LinksServlet</servlet-name>
+    <url-pattern>/v1/links/*</url-pattern>
+  </servlet-mapping>
+
   <!-- Job servlet -->
   <servlet>
     <servlet-name>v1.JobServlet</servlet-name>

http://git-wip-us.apache.org/repos/asf/sqoop/blob/eed2b3f5/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
----------------------------------------------------------------------
diff --git a/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java b/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
index d5ead38..176833a 100644
--- a/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
+++ b/shell/src/main/java/org/apache/sqoop/shell/UpdateLinkFunction.java
@@ -60,6 +60,7 @@ public class UpdateLinkFunction extends SqoopFunction {
 
     ConsoleReader reader = new ConsoleReader();
 
+    // TODO: why do we need 2 http calls for update?
     MLink link = client.getLink(linkId);
 
     ResourceBundle connectorLinkConfigBundle = client.getConnectorConfigBundle(link.getConnectorId());