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

ambari git commit: AMBARI-15821 Added ability to link optional short Urls to view instances. (Ashwin Rajeev via dipayanb)

Repository: ambari
Updated Branches:
  refs/heads/trunk 05d8743bc -> bf6a2c94b


AMBARI-15821 Added ability to link optional short Urls to view instances. (Ashwin Rajeev via dipayanb)


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

Branch: refs/heads/trunk
Commit: bf6a2c94b2cd265891a2140077ade430347ca29b
Parents: 05d8743
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Wed Apr 13 16:54:31 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Wed Apr 13 16:54:31 2016 +0530

----------------------------------------------------------------------
 .../controllers/ambariViews/ViewsEditCtrl.js    |   9 +-
 .../ui/admin-web/app/scripts/i18n.config.js     |   1 +
 .../ui/admin-web/app/scripts/services/View.js   |  10 +-
 .../admin-web/app/views/ambariViews/create.html |   9 ++
 .../admin-web/app/views/ambariViews/edit.html   |  13 +-
 .../internal/ViewInstanceResourceProvider.java  |  20 +++
 .../server/orm/entities/ViewInstanceEntity.java |  24 ++++
 .../server/upgrade/UpgradeCatalog240.java       |   9 ++
 .../ambari/server/view/ViewExtractor.java       |   1 -
 .../apache/ambari/server/view/ViewRegistry.java |  31 ++++-
 .../view/configuration/InstanceConfig.java      |  22 ++++
 .../main/resources/Ambari-DDL-Derby-CREATE.sql  |   1 +
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |   1 +
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |   1 +
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |   1 +
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |   3 +-
 .../resources/Ambari-DDL-SQLAnywhere-CREATE.sql |   1 +
 .../resources/Ambari-DDL-SQLServer-CREATE.sql   |   1 +
 .../ViewInstanceResourceProviderTest.java       | 121 +++++++++++++------
 .../ambari/view/ViewInstanceDefinition.java     |   6 +
 .../app/controllers/main/views_controller.js    |   6 +-
 ambari-web/app/routes/installer.js              |   2 +-
 ambari-web/app/routes/main.js                   |   4 +-
 ambari-web/app/routes/view.js                   |  95 +++++++++++++++
 ambari-web/app/routes/views.js                  |   4 +-
 25 files changed, 343 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
index 0d2bdf7..d46a30f 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
@@ -37,7 +37,8 @@ angular.module('ambariAdminConsole')
       $scope.settings = {
         'visible': $scope.instance.ViewInstanceInfo.visible,
         'label': $scope.instance.ViewInstanceInfo.label,
-        'description': $scope.instance.ViewInstanceInfo.description
+        'description': $scope.instance.ViewInstanceInfo.description,
+        'shortUrl': $scope.instance.ViewInstanceInfo.short_url
       };
       switch (section) {
         case "details" :
@@ -243,7 +244,8 @@ angular.module('ambariAdminConsole')
         'ViewInstanceInfo':{
           'visible': $scope.settings.visible,
           'label': $scope.settings.label,
-          'description': $scope.settings.description
+          'description': $scope.settings.description,
+          'short_url': $scope.settings.shortUrl
         }
       };
       return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data)
@@ -266,7 +268,8 @@ angular.module('ambariAdminConsole')
     $scope.settings = {
       'visible': $scope.instance.ViewInstanceInfo.visible,
       'label': $scope.instance.ViewInstanceInfo.label,
-      'description': $scope.instance.ViewInstanceInfo.description
+      'description': $scope.instance.ViewInstanceInfo.description,
+      'shortUrl': $scope.instance.ViewInstanceInfo.short_url
     };
     $scope.editDetailsSettingsDisabled = true;
     $scope.settingsForm.$setPristine();

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
index 2a31b39..e95ebdb 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -185,6 +185,7 @@ angular.module('ambariAdminConsole')
       'advanced': 'Advanced',
       'visible': 'Visible',
       'description': 'Description',
+      'shortUrl':'Short URL',
       'instanceDescription': 'Instance Description',
       'clusterConfiguration': 'Cluster Configuration',
       'localCluster': 'Local Ambari Managed Cluster',

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
index 7bf1672..cbe11e4 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
@@ -63,7 +63,7 @@ angular.module('ambariAdminConsole')
       if(version.ViewVersionInfo.status === 'DEPLOYED'){ // if atelast one version is deployed
         self.canCreateInstance = true;
       }
-      
+
       angular.forEach(version.instances, function(instance) {
         instance.label = instance.ViewInstanceInfo.label || version.ViewVersionInfo.label || instance.ViewInstanceInfo.view_name;
       });
@@ -137,7 +137,7 @@ angular.module('ambariAdminConsole')
     return deferred.promise;
   };
 
-  
+
 
   View.getVersions = function(viewName) {
     var deferred = $q.defer();
@@ -168,7 +168,8 @@ angular.module('ambariAdminConsole')
         visible: instanceInfo.visible,
         icon_path: instanceInfo.icon_path,
         icon64_path: instanceInfo.icon64_path,
-        description: instanceInfo.description
+        description: instanceInfo.description,
+        short_url:instanceInfo.shortUrl
       };
 
     angular.forEach(instanceInfo.properties, function(property) {
@@ -189,7 +190,8 @@ angular.module('ambariAdminConsole')
 
     $http({
       method: 'POST',
-      url: Settings.baseUrl + '/views/' + instanceInfo.view_name +'/versions/'+instanceInfo.version + '/instances/'+instanceInfo.instance_name,
+      url: Settings.baseUrl + '/views/' + instanceInfo.view_name
+      +'/versions/'+instanceInfo.version + '/instances/'+instanceInfo.instance_name,
       data:{
         'ViewInstanceInfo' : data
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
index b9bd609..20ccadb 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
@@ -76,6 +76,15 @@
           </div>
         </div>
       </div>
+
+      <div class="form-group" ng-class="{'has-error' : form.instanceCreateForm.submitted }">
+        <label for="" class="control-label col-sm-3">{{'views.shortUrl' | translate}}</label>
+        <div class="col-sm-9">
+          <input type="text" class="form-control" name="short_url" ng-model="instance.shortUrl" maxlength="200">
+        </div>
+      </div>
+
+
       <div class="form-group">
         <div class="col-sm-10 col-sm-offset-3">
           <div class="checkbox">

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
index 85e4e44..b41abc8 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
@@ -77,6 +77,17 @@
             </div>
           </div>
         </div>
+
+
+        <div class="form-group" ng-class="{'has-error' : form.instanceCreateForm.submitted }">
+          <label for="" class="control-label col-sm-3">{{'views.shortUrl' | translate}}</label>
+          <div class="col-sm-9">
+            <input type="text" class="form-control" name="short_url" ng-model="settings.shortUrl" maxlength="200">
+
+          </div>
+        </div>
+
+
         <div class="form-group">
           <div class="col-sm-offset-3 col-sm-10">
             <div class="checkbox">
@@ -198,7 +209,7 @@
     <p>&nbsp</p>
     <div class="checkbox">
       <label>
-        <input type="radio" 
+        <input type="radio"
          ng-model="$parent.isLocalCluster"
          ng-disabled="editConfigurationDisabled"
          ng-value="false"

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
index 750a347..abdda7f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProvider.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import com.google.common.base.Strings;
 import com.google.inject.persist.Transactional;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.DuplicateResourceException;
@@ -70,6 +71,7 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
   public static final String CONTEXT_PATH_PROPERTY_ID   = "ViewInstanceInfo/context_path";
   public static final String STATIC_PROPERTY_ID         = "ViewInstanceInfo/static";
   public static final String CLUSTER_HANDLE_PROPERTY_ID = "ViewInstanceInfo/cluster_handle";
+  public static final String SHORT_URL_PROPERTY_ID      = "ViewInstanceInfo/short_url";
 
   // validation properties
   public static final String VALIDATION_RESULT_PROPERTY_ID           = "ViewInstanceInfo/validation_result";
@@ -109,6 +111,7 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
     propertyIds.add(CONTEXT_PATH_PROPERTY_ID);
     propertyIds.add(STATIC_PROPERTY_ID);
     propertyIds.add(CLUSTER_HANDLE_PROPERTY_ID);
+    propertyIds.add(SHORT_URL_PROPERTY_ID);
     propertyIds.add(VALIDATION_RESULT_PROPERTY_ID);
     propertyIds.add(PROPERTY_VALIDATION_RESULTS_PROPERTY_ID);
   }
@@ -239,6 +242,7 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
     setResourceProperty(resource, VISIBLE_PROPERTY_ID, viewInstanceEntity.isVisible(), requestedIds);
     setResourceProperty(resource, STATIC_PROPERTY_ID, viewInstanceEntity.isXmlDriven(), requestedIds);
     setResourceProperty(resource, CLUSTER_HANDLE_PROPERTY_ID, viewInstanceEntity.getClusterHandle(), requestedIds);
+    setResourceProperty(resource, SHORT_URL_PROPERTY_ID, viewInstanceEntity.getShortUrl(), requestedIds);
 
     // only allow an admin to access the view properties
     if (ViewRegistry.getInstance().checkAdmin()) {
@@ -340,6 +344,11 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
       viewInstanceEntity.setClusterHandle((String) properties.get(CLUSTER_HANDLE_PROPERTY_ID));
     }
 
+    if (properties.containsKey(SHORT_URL_PROPERTY_ID)) {
+      viewInstanceEntity.setShortUrl((String) properties.get(SHORT_URL_PROPERTY_ID));
+    }
+
+
     Map<String, String> instanceProperties = new HashMap<String, String>();
 
     boolean isUserAdmin = viewRegistry.checkAdmin();
@@ -393,6 +402,11 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
             throw new IllegalStateException("The view " + viewName + " is not loaded.");
           }
 
+          if(!Strings.isNullOrEmpty(instanceEntity.getShortUrl()) && viewRegistry.duplicatedShortUrl(instanceEntity)){
+            throw new DuplicateResourceException("The short url " + instanceEntity.getShortUrl() + " already exists for "+ instanceEntity.getViewEntity().getCommonName() +
+                    " and version "+instanceEntity.getViewEntity().getVersion());
+          }
+
           if (viewRegistry.instanceExists(instanceEntity)) {
             throw new DuplicateResourceException("The instance " + instanceEntity.getName() + " already exists.");
           }
@@ -414,10 +428,16 @@ public class ViewInstanceResourceProvider extends AbstractAuthorizedResourceProv
       @Transactional
       @Override
       public Void invoke() throws AmbariException {
+        ViewRegistry       viewRegistry   = ViewRegistry.getInstance();
 
         ViewInstanceEntity instance = toEntity(properties, true);
         ViewEntity         view     = instance.getViewEntity();
 
+        if(!Strings.isNullOrEmpty(instance.getShortUrl()) && viewRegistry.duplicatedShortUrl(instance)){
+          throw new DuplicateResourceException("The short url " + instance.getShortUrl() + " already exists for "+ instance.getViewEntity().getCommonName() +
+                  " and version "+instance.getViewEntity().getVersion());
+        }
+
         if (includeInstance(view.getCommonName(), view.getVersion(), instance.getInstanceName(), false)) {
           try {
             ViewRegistry.getInstance().updateViewInstance(instance);

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
index 5044267..2555f93 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewInstanceEntity.java
@@ -130,6 +130,11 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
   @Basic
   private String icon;
 
+
+  @Column(name = "short_url")
+  @Basic
+  private String shortUrl;
+
   /**
    * The big icon path.
    */
@@ -234,6 +239,7 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
     this.clusterHandle = null;
     this.visible = instanceConfig.isVisible() ? 'Y' : 'N';
     this.alterNames = 1;
+    this.shortUrl = instanceConfig.getShortUrl();
 
     String label = instanceConfig.getLabel();
     this.label = (label == null || label.length() == 0) ? view.getLabel() : label;
@@ -272,6 +278,7 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
     this.visible = 'Y';
     this.alterNames = 1;
     this.label = label;
+    this.shortUrl = null;
   }
 
 
@@ -337,6 +344,14 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
     return clusterHandle;
   }
 
+
+  @Override
+  public String getShortUrl() {
+    return shortUrl;
+  }
+
+
+
   @Override
   public boolean isVisible() {
     return visible == 'y' || visible == 'Y';
@@ -372,6 +387,15 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
     this.viewName = viewName;
   }
 
+
+  /**
+   *  Set the short URL
+   * @param shortUrl
+   */
+  public void setShortUrl(String shortUrl) {
+    this.shortUrl = shortUrl;
+  }
+
   /**
    * Get the name of this instance.
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
index 31af5e3..d4cd784 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog240.java
@@ -96,6 +96,8 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
   public static final String SETTING_DATA_COL = "setting_data";
   public static final String ID = "id";
   public static final String BLUEPRINT_TABLE = "blueprint";
+  public static final String VIEWINSTANCEENTITY_TABLE = "viewinstanceentity";
+  public static final String SHORT_URL_COLUMN = "short_url";
 
   @Inject
   PermissionDAO permissionDAO;
@@ -160,6 +162,13 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
     updateAlertCurrentTable();
     createBlueprintSettingTable();
     updateHostRoleCommandTableDDL();
+    updateViewInstanceEntityTable();
+
+  }
+
+  private void updateViewInstanceEntityTable() throws SQLException {
+    dbAccessor.addColumn(VIEWINSTANCEENTITY_TABLE,
+            new DBColumnInfo(SHORT_URL_COLUMN, String.class, 255, null, true));
   }
 
   private void updateClusterTableDDL() throws SQLException {

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
index 3350726..3550f98 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewExtractor.java
@@ -15,7 +15,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.ambari.server.view;
 
 import org.apache.ambari.server.orm.entities.ViewEntity;

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index 037d1e5..7379f37 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.view;
 
+import com.google.common.base.Strings;
 import com.google.common.collect.Sets;
 import com.google.common.eventbus.AllowConcurrentEvents;
 import com.google.common.eventbus.Subscribe;
@@ -25,7 +26,6 @@ import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.persist.Transactional;
-
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
 import org.apache.ambari.server.api.resources.SubResourceDefinition;
@@ -80,17 +80,17 @@ import org.apache.ambari.server.view.configuration.PropertyConfig;
 import org.apache.ambari.server.view.configuration.ResourceConfig;
 import org.apache.ambari.server.view.configuration.ViewConfig;
 import org.apache.ambari.server.view.validation.ValidationException;
-import org.apache.ambari.view.ViewInstanceDefinition;
-import org.apache.ambari.view.cluster.Cluster;
-import org.apache.ambari.view.validation.Validator;
 import org.apache.ambari.view.Masker;
 import org.apache.ambari.view.SystemException;
 import org.apache.ambari.view.View;
 import org.apache.ambari.view.ViewContext;
 import org.apache.ambari.view.ViewDefinition;
+import org.apache.ambari.view.ViewInstanceDefinition;
 import org.apache.ambari.view.ViewResourceHandler;
+import org.apache.ambari.view.cluster.Cluster;
 import org.apache.ambari.view.events.Event;
 import org.apache.ambari.view.events.Listener;
+import org.apache.ambari.view.validation.Validator;
 import org.apache.log4j.PropertyConfigurator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -98,7 +98,6 @@ import org.slf4j.LoggerFactory;
 import javax.inject.Inject;
 import javax.inject.Provider;
 import javax.inject.Singleton;
-
 import java.beans.IntrospectionException;
 import java.io.File;
 import java.net.URL;
@@ -461,6 +460,7 @@ public class ViewRegistry {
   public Set<SubResourceDefinition> getSubResourceDefinitions(
       String viewName, String version) {
 
+
     viewName = ViewEntity.getViewName(viewName, version);
 
     return subResourceDefinitionsMap.get(viewName);
@@ -496,6 +496,25 @@ public class ViewRegistry {
         (getInstanceDefinition(viewEntity.getCommonName(), viewEntity.getVersion(), instanceEntity.getName()) != null);
   }
 
+
+  public boolean duplicatedShortUrl(ViewInstanceEntity instanceEntity) {
+    ViewEntity viewEntity = getDefinition(instanceEntity.getViewName());
+    Map<String, ViewInstanceEntity> viewInstanceDefinitionMap =
+            viewInstanceDefinitions.get(getDefinition(viewEntity.getCommonName(), viewEntity.getVersion()));
+
+    if(viewInstanceDefinitionMap != null){
+      for (ViewInstanceEntity viewInstanceEntity : viewInstanceDefinitionMap.values()) {
+        String shortUrl = viewInstanceEntity.getShortUrl();
+        // check if there is a view for the same version with the same shortUrl
+        if (!Strings.isNullOrEmpty(shortUrl) && shortUrl.equals(instanceEntity.getShortUrl()))
+          return true;
+      }
+    }
+
+    return false;
+  }
+
+
   /**
    * Install the given view instance with its associated view.
    *
@@ -1360,6 +1379,7 @@ public class ViewRegistry {
   private void syncViewInstance(ViewInstanceEntity instance1, ViewInstanceEntity instance2) {
     instance1.setLabel(instance2.getLabel());
     instance1.setDescription(instance2.getDescription());
+    instance1.setShortUrl(instance2.getShortUrl());
     instance1.setVisible(instance2.isVisible());
     instance1.setResource(instance2.getResource());
     instance1.setViewInstanceId(instance2.getViewInstanceId());
@@ -1801,6 +1821,7 @@ public class ViewRegistry {
 
 
 
+
   /**
    * Module for stand alone view registry.
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/InstanceConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/InstanceConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/InstanceConfig.java
index 0087446..65b36df 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/InstanceConfig.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/InstanceConfig.java
@@ -45,6 +45,12 @@ public class InstanceConfig {
   private String description;
 
   /**
+   * An optional short url for this instance
+   */
+  private String shortUrl;
+
+
+  /**
    * Indicates whether or not the instance should be visible.
    */
   private boolean visible = true;
@@ -131,4 +137,20 @@ public class InstanceConfig {
   public List<PropertyConfig> getProperties() {
     return properties == null ? Collections.<PropertyConfig>emptyList() : properties;
   }
+
+  /**
+   * Get the short URL
+   * @return short URL
+   */
+  public String getShortUrl() {
+    return shortUrl;
+  }
+
+  /**
+   * Set the short URL
+   * @param shortUrl
+   */
+  public void setShortUrl(String shortUrl) {
+    this.shortUrl = shortUrl;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
index 81b97bb..f90ac96 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -474,6 +474,7 @@ CREATE TABLE viewinstance (
   xml_driven CHAR(1),
   alter_names SMALLINT NOT NULL DEFAULT 1,
   cluster_handle VARCHAR(255),
+  short_url VARCHAR (255),
   PRIMARY KEY(view_instance_id));
 
 CREATE TABLE viewinstanceproperty (

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index 021d2b8..2b214c4 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -483,6 +483,7 @@ CREATE TABLE viewinstance (
   xml_driven CHAR(1),
   alter_names TINYINT(1) NOT NULL DEFAULT 1,
   cluster_handle VARCHAR(255),
+  short_url VARCHAR (255),
   PRIMARY KEY(view_instance_id));
 
 CREATE TABLE viewinstanceproperty (

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index 0320178..fc93372 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -473,6 +473,7 @@ CREATE TABLE viewinstance (
   xml_driven CHAR(1),
   alter_names NUMBER(1) DEFAULT 1 NOT NULL,
   cluster_handle VARCHAR(255),
+  short_url VARCHAR (255),
   PRIMARY KEY(view_instance_id));
 
 CREATE TABLE viewinstanceproperty (

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index 585cdce..870a8e8 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -475,6 +475,7 @@ CREATE TABLE viewinstance (
   xml_driven CHAR(1),
   alter_names SMALLINT NOT NULL DEFAULT 1,
   cluster_handle VARCHAR(255),
+  short_url VARCHAR (255),
   PRIMARY KEY(view_instance_id));
 
 CREATE TABLE viewinstanceproperty (

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index b546865..71d4813 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -473,7 +473,7 @@ CREATE TABLE ambari.blueprint_setting (
   id BIGINT NOT NULL,
   blueprint_name varchar(255) NOT NULL,
   setting_name varchar(255) NOT NULL,
-  setting_data TEXT NOT NULL, 
+  setting_data TEXT NOT NULL,
   CONSTRAINT PK_blueprint_setting PRIMARY KEY (id),
   CONSTRAINT UQ_blueprint_setting_name UNIQUE(blueprint_name,setting_name),
   CONSTRAINT FK_blueprint_setting_name FOREIGN KEY (blueprint_name) REFERENCES ambari.blueprint(blueprint_name));
@@ -529,6 +529,7 @@ CREATE TABLE ambari.viewinstance (
   xml_driven CHAR(1),
   alter_names SMALLINT NOT NULL DEFAULT 1,
   cluster_handle VARCHAR(255),
+  short_url VARCHAR (255),
   PRIMARY KEY(view_instance_id));
 
 CREATE TABLE ambari.viewinstanceproperty (

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
index 8bfd9dd..6e600c7 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -472,6 +472,7 @@ CREATE TABLE viewinstance (
   xml_driven CHAR(1),
   alter_names BIT NOT NULL DEFAULT 1,
   cluster_handle VARCHAR(255),
+  short_url VARCHAR (255),
   PRIMARY KEY(view_instance_id));
 
 CREATE TABLE viewinstanceproperty (

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
index 57ab922..a3ea10d 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -548,6 +548,7 @@ CREATE TABLE viewinstance (
   xml_driven CHAR(1),
   alter_names BIT NOT NULL DEFAULT 1,
   cluster_handle VARCHAR(255),
+  short_url VARCHAR (255),
   PRIMARY KEY CLUSTERED (view_instance_id)
   );
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
index 4b6700d..b384b8a 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ViewInstanceResourceProviderTest.java
@@ -18,6 +18,8 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.DuplicateResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
@@ -51,15 +53,15 @@ import static org.junit.Assert.assertEquals;
 
 public class ViewInstanceResourceProviderTest {
 
-  private static final ViewRegistry singleton = createMock(ViewRegistry.class);
+  private static final ViewRegistry viewregistry = createMock(ViewRegistry.class);
 
   static {
-    ViewRegistry.initInstance(singleton);
+    ViewRegistry.initInstance(viewregistry);
   }
 
   @Before
   public void before() {
-    reset(singleton);
+    reset(viewregistry);
   }
 
   @After
@@ -86,12 +88,12 @@ public class ViewInstanceResourceProviderTest {
 
     expect(viewInstanceEntity.getData()).andReturn(Collections.<ViewInstanceDataEntity>emptyList()).anyTimes();
 
-    expect(singleton.checkAdmin()).andReturn(true);
-    expect(singleton.checkAdmin()).andReturn(false);
+    expect(viewregistry.checkAdmin()).andReturn(true);
+    expect(viewregistry.checkAdmin()).andReturn(false);
 
     expect(viewInstanceEntity.getClusterHandle()).andReturn("c1");
 
-    replay(singleton, viewEntity, viewInstanceEntity);
+    replay(viewregistry, viewEntity, viewInstanceEntity);
 
     // as admin
     Resource resource = provider.toResource(viewInstanceEntity, propertyIds);
@@ -114,7 +116,7 @@ public class ViewInstanceResourceProviderTest {
     props = properties.get("ViewInstanceInfo/properties");
     assertNull(props);
 
-    verify(singleton, viewEntity, viewInstanceEntity);
+    verify(viewregistry, viewEntity, viewInstanceEntity);
   }
 
   @Test
@@ -156,24 +158,24 @@ public class ViewInstanceResourceProviderTest {
     viewInstanceEntity.setViewEntity(viewEntity);
     viewInstanceEntity2.setViewEntity(viewEntity);
 
-    expect(singleton.instanceExists(viewInstanceEntity)).andReturn(false);
-    expect(singleton.instanceExists(viewInstanceEntity2)).andReturn(false);
-    expect(singleton.getDefinition("V1", "1.0.0")).andReturn(viewEntity).anyTimes();
-    expect(singleton.getDefinition("V1", null)).andReturn(viewEntity).anyTimes();
+    expect(viewregistry.instanceExists(viewInstanceEntity)).andReturn(false);
+    expect(viewregistry.instanceExists(viewInstanceEntity2)).andReturn(false);
+    expect(viewregistry.getDefinition("V1", "1.0.0")).andReturn(viewEntity).anyTimes();
+    expect(viewregistry.getDefinition("V1", null)).andReturn(viewEntity).anyTimes();
 
     Capture<Map<String, String>> captureProperties = new Capture<Map<String, String>>();
 
-    singleton.setViewInstanceProperties(eq(viewInstanceEntity), capture(captureProperties),
+    viewregistry.setViewInstanceProperties(eq(viewInstanceEntity), capture(captureProperties),
         anyObject(ViewConfig.class), anyObject(ClassLoader.class));
 
     Capture<ViewInstanceEntity> instanceEntityCapture = new Capture<ViewInstanceEntity>();
-    singleton.installViewInstance(capture(instanceEntityCapture));
+    viewregistry.installViewInstance(capture(instanceEntityCapture));
     expectLastCall().anyTimes();
 
-    expect(singleton.checkAdmin()).andReturn(true);
-    expect(singleton.checkAdmin()).andReturn(false);
+    expect(viewregistry.checkAdmin()).andReturn(true);
+    expect(viewregistry.checkAdmin()).andReturn(false);
 
-    replay(singleton);
+    replay(viewregistry);
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
 
@@ -190,7 +192,7 @@ public class ViewInstanceResourceProviderTest {
     props = viewInstanceEntity2.getPropertyMap();
     assertTrue(props.isEmpty());
 
-    verify(singleton);
+    verify(viewregistry);
   }
 
   @Test
@@ -217,13 +219,13 @@ public class ViewInstanceResourceProviderTest {
 
     viewInstanceEntity.setViewEntity(viewEntity);
 
-    expect(singleton.instanceExists(viewInstanceEntity)).andReturn(true);
-    expect(singleton.getDefinition("V1", "1.0.0")).andReturn(viewEntity).anyTimes();
-    expect(singleton.getDefinition("V1", null)).andReturn(viewEntity);
+    expect(viewregistry.instanceExists(viewInstanceEntity)).andReturn(true);
+    expect(viewregistry.getDefinition("V1", "1.0.0")).andReturn(viewEntity).anyTimes();
+    expect(viewregistry.getDefinition("V1", null)).andReturn(viewEntity);
 
-    expect(singleton.checkAdmin()).andReturn(true);
+    expect(viewregistry.checkAdmin()).andReturn(true);
 
-    replay(singleton);
+    replay(viewregistry);
 
     SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createAdministrator());
 
@@ -234,7 +236,7 @@ public class ViewInstanceResourceProviderTest {
       // expected
     }
 
-    verify(singleton);
+    verify(viewregistry);
   }
 
   @Test
@@ -259,12 +261,12 @@ public class ViewInstanceResourceProviderTest {
     viewInstanceEntity.setName("I1");
     viewInstanceEntity.setViewEntity(viewEntity);
 
-    expect(singleton.getDefinition("V1", "1.0.0")).andReturn(viewEntity).anyTimes();
-    expect(singleton.getDefinition("V1", null)).andReturn(viewEntity);
+    expect(viewregistry.getDefinition("V1", "1.0.0")).andReturn(viewEntity).anyTimes();
+    expect(viewregistry.getDefinition("V1", null)).andReturn(viewEntity);
 
-    expect(singleton.checkAdmin()).andReturn(true);
+    expect(viewregistry.checkAdmin()).andReturn(true);
 
-    replay(singleton);
+    replay(viewregistry);
 
     SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createAdministrator());
 
@@ -275,9 +277,60 @@ public class ViewInstanceResourceProviderTest {
       // expected
     }
 
-    verify(singleton);
+    verify(viewregistry);
   }
 
+
+  @Test
+  public void testCreateWithShortUrlValidations() throws Exception {
+
+    ViewInstanceResourceProvider provider = new ViewInstanceResourceProvider();
+
+    Set<Map<String, Object>> properties = new HashSet<Map<String, Object>>();
+
+    Map<String, Object> propertyMap = new HashMap<String, Object>();
+
+    propertyMap.put(ViewInstanceResourceProvider.VIEW_NAME_PROPERTY_ID, "V1");
+    propertyMap.put(ViewInstanceResourceProvider.VIEW_VERSION_PROPERTY_ID, "1.0.0");
+    propertyMap.put(ViewInstanceResourceProvider.INSTANCE_NAME_PROPERTY_ID, "I1");
+    propertyMap.put(ViewInstanceResourceProvider.SHORT_URL_PROPERTY_ID, "testUrl");
+
+    properties.add(propertyMap);
+
+    ViewInstanceEntity viewInstanceEntity = new ViewInstanceEntity();
+    viewInstanceEntity.setViewName("V1{1.0.0}");
+    viewInstanceEntity.setName("I1");
+    viewInstanceEntity.setShortUrl("testUrl");
+
+    ViewEntity viewEntity = new ViewEntity();
+    viewEntity.setStatus(ViewDefinition.ViewStatus.DEPLOYED);
+    viewEntity.setName("V1{1.0.0}");
+
+    viewInstanceEntity.setViewEntity(viewEntity);
+
+    expect(viewregistry.duplicatedShortUrl(viewInstanceEntity)).andReturn(true);
+    expect(viewregistry.getDefinition("V1", "1.0.0")).andReturn(viewEntity).anyTimes();
+    expect(viewregistry.getDefinition("V1", null)).andReturn(viewEntity);
+
+    expect(viewregistry.checkAdmin()).andReturn(true);
+
+    replay(viewregistry);
+
+    SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createAdministrator());
+
+    try {
+      provider.createResources(PropertyHelper.getCreateRequest(properties, null));
+      fail("Expected ResourceAlreadyExistsException.");
+    } catch (ResourceAlreadyExistsException e) {
+      // expected
+    }
+
+    verify(viewregistry);
+
+
+  }
+
+
   @Test
   public void testUpdateResources_viewNotLoaded() throws Exception {
     ViewInstanceResourceProvider provider = new ViewInstanceResourceProvider();
@@ -301,9 +354,9 @@ public class ViewInstanceResourceProviderTest {
     viewInstanceEntity.setName("I1");
     viewInstanceEntity.setViewEntity(viewEntity);
 
-    expect(singleton.getDefinitions()).andReturn(Collections.singleton(viewEntity));
+    expect(viewregistry.getDefinitions()).andReturn(Collections.singleton(viewEntity));
 
-    replay(singleton);
+    replay(viewregistry);
 
     SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createAdministrator());
 
@@ -311,7 +364,7 @@ public class ViewInstanceResourceProviderTest {
 
     Assert.assertNull(viewInstanceEntity.getIcon());
 
-    verify(singleton);
+    verify(viewregistry);
   }
 
   @Test
@@ -339,13 +392,13 @@ public class ViewInstanceResourceProviderTest {
     viewInstanceEntity.setName("I1");
     viewInstanceEntity.setViewEntity(viewEntity);
 
-    expect(singleton.getDefinitions()).andReturn(Collections.singleton(viewEntity));
+    expect(viewregistry.getDefinitions()).andReturn(Collections.singleton(viewEntity));
 
-    replay(singleton);
+    replay(viewregistry);
 
     SecurityContextHolder.getContext().setAuthentication(authentication);
     provider.deleteResources(predicate);
 
-    verify(singleton);
+    verify(viewregistry);
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java b/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
index d694459..62f9657 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewInstanceDefinition.java
@@ -62,6 +62,12 @@ public interface ViewInstanceDefinition {
   public String getClusterHandle();
 
   /**
+   * Get the short URL
+   * @return
+     */
+  public String getShortUrl();
+
+  /**
    * Indicates whether or not the view instance should be visible.
    *
    * @return true if the view instance should be visible; false otherwise

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-web/app/controllers/main/views_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/views_controller.js b/ambari-web/app/controllers/main/views_controller.js
index ed7cc23..e2e9281 100644
--- a/ambari-web/app/controllers/main/views_controller.js
+++ b/ambari-web/app/controllers/main/views_controller.js
@@ -85,6 +85,7 @@ App.MainViewsController = Em.Controller.extend({
             version: instance.ViewInstanceInfo.version,
             description: instance.ViewInstanceInfo.description || Em.I18n.t('views.main.instance.noDescription'),
             viewName: instance.ViewInstanceInfo.view_name,
+            shortUrl:instance.ViewInstanceInfo.short_url,
             instanceName: instance.ViewInstanceInfo.instance_name,
             href: instance.ViewInstanceInfo.context_path + "/"
           });
@@ -105,7 +106,10 @@ App.MainViewsController = Em.Controller.extend({
 
   setView: function (event) {
     if (event.context) {
+      if(event.context.shortUrl){
+        App.router.route('main/view/' + event.context.viewName + '/' + event.context.shortUrl);
+      } else {
       App.router.route('main/views/' + event.context.viewName + '/' + event.context.version + '/' + event.context.instanceName);
-    }
+    }}
   }
 });
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-web/app/routes/installer.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/installer.js b/ambari-web/app/routes/installer.js
index 4c89e4c..f280049 100644
--- a/ambari-web/app/routes/installer.js
+++ b/ambari-web/app/routes/installer.js
@@ -463,7 +463,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     unroutePath: function (router, context) {
       // exclusion for transition to Admin view or Views view
       if (context === '/adminView' ||
-          context === '/main/views.index') {
+          context === '/main/views.index' || context === '/main/view.index') {
         this._super(router, context);
       } else {
         return false;

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index 9e4bde4..c9f8590 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -52,7 +52,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
                   Em.run.next(function () {
                     App.clusterStatus.updateFromServer().complete(function () {
                       var currentClusterStatus = App.clusterStatus.get('value');
-                      if (router.get('currentState.parentState.name') !== 'views'
+                      if (router.get('currentState.parentState.name') !== 'views' && router.get('currentState.parentState.name') !== 'view'
                           && currentClusterStatus && self.get('installerStatuses').contains(currentClusterStatus.clusterState)) {
                         if (App.isAuthorized('AMBARI.ADD_DELETE_CLUSTERS')) {
                           self.redirectToInstaller(router, currentClusterStatus, false);
@@ -185,6 +185,8 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
   }),
 
   views: require('routes/views'),
+  view: require('routes/view'),
+
 
   hosts: Em.Route.extend({
     route: '/hosts',

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-web/app/routes/view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/view.js b/ambari-web/app/routes/view.js
new file mode 100644
index 0000000..752f14d
--- /dev/null
+++ b/ambari-web/app/routes/view.js
@@ -0,0 +1,95 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+module.exports = Em.Route.extend({
+  route: '/view',
+  enter: function (router) {
+    router.get('mainViewsController').loadAmbariViews();
+  },
+  index: Em.Route.extend({
+    route: '/',
+    connectOutlets: function (router) {
+      router.get('mainViewsController').dataLoading().done(function() {
+        router.get('mainController').connectOutlet('mainViews');
+      });
+    }
+  }),
+
+  shortViewDetails: Em.Route.extend({
+    route: '/:viewName/:shortName',
+    connectOutlets: function (router, params) {
+      var viewPath = this.parseViewPath(window.location.href.slice(window.location.href.indexOf('?')));
+      var slicedShortName = params.shortName;
+      if (viewPath) {
+        slicedShortName = this._getSlicedShortName(params.shortName);
+        if (slicedShortName === params.shortName) {
+          viewPath = '';
+        }
+
+        if (viewPath.charAt(0) === '/') viewPath = viewPath.slice(1);
+      }
+
+      router.get('mainViewsController').dataLoading().done(function() {
+        var content = App.router.get('mainViewsController.ambariViews').filterProperty('viewName', params.viewName).findProperty('shortUrl', slicedShortName)
+        if (content) content.set('viewPath', viewPath);
+        router.get('mainController').connectOutlet('mainViewsDetails', content);
+      });
+
+    },
+
+    /**
+     * parse the short name and slice if needed
+     *
+     * @param {string}
+     * @returns {string}
+     * @private
+     */
+    _getSlicedShortName: function (instanceName) {
+      if (instanceName.lastIndexOf('?') > -1) {
+        return instanceName.slice(0, instanceName.lastIndexOf('?'));
+      }
+
+      return instanceName;
+    },
+
+    /**
+     * parse internal view path
+     * "viewPath" - used as a key of additional path
+     * Example:
+     *   origin URL: viewName?viewPath=%2Fuser%2Fadmin%2Faddress&foo=bar&count=1
+     * should be translated to
+     *   view path: /user/admin/address?foo=bar&count=1
+     *
+     * @param {string} instanceName
+     * @returns {string}
+     */
+    parseViewPath: function (instanceName) {
+      var path = '';
+      if (instanceName.contains('?')) {
+        path = instanceName.slice(instanceName.indexOf('?'));
+        if (path.contains('viewPath')) {
+          path = decodeURIComponent(path.slice((path.lastIndexOf('?viewPath=') + 10))).replace('&', '?');
+        }
+      }
+      return path;
+    }
+
+  })
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/bf6a2c94/ambari-web/app/routes/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/views.js b/ambari-web/app/routes/views.js
index 08396eb..c50690c 100644
--- a/ambari-web/app/routes/views.js
+++ b/ambari-web/app/routes/views.js
@@ -31,11 +31,13 @@ module.exports = Em.Route.extend({
       });
     }
   }),
+
+
   viewDetails: Em.Route.extend({
+
     route: '/:viewName/:version/:instanceName',
     connectOutlets: function (router, params) {
       // find and set content for `mainViewsDetails` and associated controller
-
       var href = ['/views', params.viewName, params.version, params.instanceName + "/"].join('/');
       var viewPath = this.parseViewPath(window.location.href.slice(window.location.href.indexOf('?')));
       if (viewPath) {