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/26 09:03:44 UTC
[1/2] ambari git commit: AMBARI-15821 Ability to provide logical urls
to view instances,
Added URL wizard and other UI fixes(Ashwin Rajeev via dipayanb)
Repository: ambari
Updated Branches:
refs/heads/trunk 614b12fc3 -> f62a92770
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewURLResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewURLResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewURLResourceProvider.java
new file mode 100644
index 0000000..f3d6b11
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewURLResourceProvider.java
@@ -0,0 +1,358 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.controller.internal;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.StaticallyInject;
+import org.apache.ambari.server.controller.predicate.EqualsPredicate;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.Request;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
+import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.apache.ambari.server.orm.dao.ViewURLDAO;
+import org.apache.ambari.server.orm.entities.ViewEntity;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.server.orm.entities.ViewURLEntity;
+import org.apache.ambari.server.security.authorization.RoleAuthorization;
+import org.apache.ambari.server.view.ViewRegistry;
+import org.apache.ambari.server.view.validation.ValidationException;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Resource provider for view URLs.
+ */
+@SuppressWarnings("Duplicates")
+@StaticallyInject
+public class ViewURLResourceProvider extends AbstractAuthorizedResourceProvider {
+
+ /**
+ * view URL property id constants.
+ */
+ public static final String URL_NAME_PROPERTY_ID = "ViewUrlInfo/url_name";
+ public static final String URL_SUFFIX_PROPERTY_ID = "ViewUrlInfo/url_suffix";
+ public static final String VIEW_INSTANCE_VERSION_PROPERTY_ID = "ViewUrlInfo/view_instance_version";
+ public static final String VIEW_INSTANCE_NAME_PROPERTY_ID = "ViewUrlInfo/view_instance_name";
+ public static final String VIEW_INSTANCE_COMMON_NAME_PROPERTY_ID = "ViewUrlInfo/view_instance_common_name";
+
+ /**
+ * The key property ids for a view URL resource.
+ */
+ private static Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>();
+ static {
+ keyPropertyIds.put(Resource.Type.View, VIEW_INSTANCE_NAME_PROPERTY_ID);
+ keyPropertyIds.put(Resource.Type.ViewVersion, VIEW_INSTANCE_VERSION_PROPERTY_ID);
+ keyPropertyIds.put(Resource.Type.ViewInstance, VIEW_INSTANCE_COMMON_NAME_PROPERTY_ID);
+ keyPropertyIds.put(Resource.Type.ViewURL, URL_NAME_PROPERTY_ID);
+ }
+
+ /**
+ * The property ids for a view URL resource.
+ */
+ private static Set<String> propertyIds = new HashSet<String>();
+ static {
+ propertyIds.add(URL_NAME_PROPERTY_ID);
+ propertyIds.add(URL_SUFFIX_PROPERTY_ID);
+ propertyIds.add(VIEW_INSTANCE_VERSION_PROPERTY_ID);
+ propertyIds.add(VIEW_INSTANCE_NAME_PROPERTY_ID);
+ propertyIds.add(VIEW_INSTANCE_COMMON_NAME_PROPERTY_ID);
+ }
+
+ @Inject
+ private static ViewURLDAO viewURLDAO;
+
+
+ // ----- Constructors ------------------------------------------------------
+
+ /**
+ * Construct a view URL resource provider.
+ */
+ public ViewURLResourceProvider() {
+ super(propertyIds, keyPropertyIds);
+
+ EnumSet<RoleAuthorization> requiredAuthorizations = EnumSet.of(RoleAuthorization.AMBARI_MANAGE_VIEWS);
+ setRequiredCreateAuthorizations(requiredAuthorizations);
+ setRequiredDeleteAuthorizations(requiredAuthorizations);
+ setRequiredUpdateAuthorizations(requiredAuthorizations);
+ }
+
+
+ // ----- ResourceProvider --------------------------------------------------
+
+ @Override
+ protected RequestStatus createResourcesAuthorized(Request request)
+ throws SystemException, UnsupportedPropertyException,
+ ResourceAlreadyExistsException, NoSuchParentResourceException {
+ for (Map<String, Object> properties : request.getProperties()) {
+ createResources(getCreateCommand(properties));
+ }
+ notifyCreate(Resource.Type.ViewURL, request);
+
+ return getRequestStatus(null);
+ }
+
+ @Override
+ public Set<Resource> getResources(Request request, Predicate predicate)
+ throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+ Set<Resource> resources = Sets.newHashSet();
+ List<ViewURLEntity> urlEntities = viewURLDAO.findAll();
+ for (ViewURLEntity urlEntity : urlEntities) {
+ resources.add(toResource(urlEntity));
+ }
+
+ return resources;
+ }
+
+ @Override
+ protected RequestStatus updateResourcesAuthorized(Request request, Predicate predicate)
+ throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+ Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
+ if (iterator.hasNext()) {
+ for (Map<String, Object> propertyMap : getPropertyMaps(iterator.next(), predicate)) {
+ modifyResources(getUpdateCommand(propertyMap));
+ }
+ }
+ notifyUpdate(Resource.Type.ViewInstance, request, predicate);
+
+ return getRequestStatus(null);
+ }
+
+ @Override
+ protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate)
+ throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+ modifyResources(getDeleteCommand(predicate));
+ notifyDelete(Resource.Type.ViewInstance, predicate);
+ return getRequestStatus(null);
+
+ }
+
+ @Override
+ public Map<Resource.Type, String> getKeyPropertyIds() {
+ return keyPropertyIds;
+ }
+
+
+ // ----- AbstractResourceProvider ------------------------------------------
+
+ @Override
+ protected Set<String> getPKPropertyIds() {
+ return new HashSet<String>(keyPropertyIds.values());
+ }
+
+
+ // ----- helper methods ----------------------------------------------------
+
+ /**
+ * Converts a View URL entity into a Resource.
+ * @param viewURLEntity
+ * @return A resource object representing the URL
+ */
+ protected Resource toResource(ViewURLEntity viewURLEntity) {
+ Resource resource = new ResourceImpl(Resource.Type.ViewURL);
+
+ resource.setProperty(URL_NAME_PROPERTY_ID,viewURLEntity.getUrlName());
+ resource.setProperty(URL_SUFFIX_PROPERTY_ID,viewURLEntity.getUrlSuffix());
+ ViewInstanceEntity viewInstanceEntity = viewURLEntity.getViewInstanceEntity();
+ if(viewInstanceEntity == null)
+ return resource;
+ ViewEntity viewEntity = viewInstanceEntity.getViewEntity();
+ String viewName = viewEntity.getCommonName();
+ String version = viewEntity.getVersion();
+ String name = viewInstanceEntity.getName();
+ resource.setProperty(VIEW_INSTANCE_NAME_PROPERTY_ID,name);
+ resource.setProperty(VIEW_INSTANCE_VERSION_PROPERTY_ID,version);
+ resource.setProperty(VIEW_INSTANCE_COMMON_NAME_PROPERTY_ID,viewName);
+ return resource;
+ }
+
+ /**
+ * Converts the incoming request into a View URL
+ * @param properties The property map
+ * @return The view URL
+ * @throws AmbariException
+ */
+ private ViewURLEntity toEntity(Map<String, Object> properties) throws AmbariException {
+ String name = (String) properties.get(URL_NAME_PROPERTY_ID);
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException("The View URL is a required property.");
+ }
+
+ String suffix = (String) properties.get(URL_SUFFIX_PROPERTY_ID);
+ String commonName = (String) properties.get(VIEW_INSTANCE_COMMON_NAME_PROPERTY_ID);
+ String instanceName = (String) properties.get(VIEW_INSTANCE_NAME_PROPERTY_ID);
+ String instanceVersion = (String) properties.get(VIEW_INSTANCE_VERSION_PROPERTY_ID);
+ ViewRegistry viewRegistry = ViewRegistry.getInstance();
+ ViewInstanceEntity instanceEntity = viewRegistry.getInstanceDefinition(commonName, instanceVersion, instanceName);
+
+ ViewURLEntity urlEntity = new ViewURLEntity();
+ urlEntity.setUrlName(name);
+ urlEntity.setUrlSuffix(suffix);
+ urlEntity.setViewInstanceEntity(instanceEntity);
+
+ return urlEntity;
+
+ }
+
+ /**
+ * Get the command to create the View URL
+ * @param properties
+ * @return A command to create the View URL instance
+ */
+ private Command<Void> getCreateCommand(final Map<String, Object> properties) {
+ return new Command<Void>() {
+ @Transactional
+ @Override
+ public Void invoke() throws AmbariException {
+ ViewRegistry viewRegistry = ViewRegistry.getInstance();
+
+ ViewURLEntity urlEntity = toEntity(properties);
+
+ ViewInstanceEntity viewInstanceEntity = urlEntity.getViewInstanceEntity();
+ ViewEntity viewEntity = viewInstanceEntity.getViewEntity();
+ String viewName = viewEntity.getCommonName();
+ String version = viewEntity.getVersion();
+ ViewEntity view = viewRegistry.getDefinition(viewName, version);
+
+ if ( view == null ) {
+ throw new IllegalStateException("The view " + viewName + " is not registered.");
+ }
+
+ // the view must be in the DEPLOYED state to create an instance
+ if (!view.isDeployed()) {
+ throw new IllegalStateException("The view " + viewName + " is not loaded.");
+ }
+
+ ViewURLEntity viewUrl = viewInstanceEntity.getViewUrl();
+ Optional<ViewURLEntity> savedUrl = viewURLDAO.findByName(urlEntity.getUrlName());
+
+ if(savedUrl.isPresent()){
+ throw new AmbariException("This view URL name exists, URL names should be unique");
+ }
+
+ if(viewUrl != null) {
+ throw new AmbariException("The view instance selected already has a linked URL");
+ }
+
+ viewURLDAO.save(urlEntity);
+ // Update the view with the URL
+ viewInstanceEntity.setViewUrl(urlEntity);
+ try {
+ viewRegistry.updateViewInstance(viewInstanceEntity);
+ } catch (ValidationException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ } catch (org.apache.ambari.view.SystemException e) {
+ throw new AmbariException("Caught exception trying to update view URL.", e);
+ }
+ viewRegistry.updateView(viewInstanceEntity);
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Get the command to update the View URL
+ * @param properties
+ * @return The update command
+ */
+ private Command<Void> getUpdateCommand(final Map<String, Object> properties) {
+ return new Command<Void>() {
+ @Override
+ public Void invoke() throws AmbariException {
+ ViewRegistry registry = ViewRegistry.getInstance();
+ String name = (String) properties.get(URL_NAME_PROPERTY_ID);
+ String suffix = (String) properties.get(URL_SUFFIX_PROPERTY_ID);
+ Optional<ViewURLEntity> entity = viewURLDAO.findByName(name);
+ if(!entity.isPresent()){
+ throw new AmbariException("URL with name "+ name +"was not found");
+ }
+ entity.get().setUrlSuffix(suffix);
+ viewURLDAO.update(entity.get());
+ // update the instance to sync with the DB values
+ ViewInstanceEntity viewInstanceEntity = entity.get().getViewInstanceEntity();
+ try {
+ registry.updateViewInstance(viewInstanceEntity);
+ } catch (ValidationException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ } catch (org.apache.ambari.view.SystemException e) {
+ throw new AmbariException("Caught exception trying to update view URL.", e);
+ }
+ registry.updateView(viewInstanceEntity);
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Get the command to delete the View URL
+ * @param predicate
+ * @return The delete command
+ */
+ private Command<Void> getDeleteCommand(final Predicate predicate) {
+ return new Command<Void>() {
+ @Override
+ public Void invoke() throws AmbariException {
+ ViewRegistry viewRegistry = ViewRegistry.getInstance();
+ Comparable deletedUrl = ((EqualsPredicate) predicate).getValue();
+ String toDelete = deletedUrl.toString();
+ Optional<ViewURLEntity> urlEntity = viewURLDAO.findByName(toDelete);
+ if(!urlEntity.isPresent()){
+ throw new AmbariException("The URL "+ toDelete +"does not exist");
+ }
+ ViewInstanceEntity viewInstanceEntity = urlEntity.get().getViewInstanceEntity();
+ if(viewInstanceEntity != null) {
+ viewInstanceEntity.clearUrl();
+
+ try {
+ viewRegistry.updateViewInstance(viewInstanceEntity);
+ } catch (ValidationException e) {
+ throw new IllegalArgumentException(e.getMessage(), e);
+ } catch (org.apache.ambari.view.SystemException e) {
+ throw new AmbariException("Caught exception trying to update view URL.", e);
+ }
+
+ viewRegistry.updateView(viewInstanceEntity);
+ }
+ // Delete the url
+ urlEntity.get().clearEntity();
+ viewURLDAO.delete(urlEntity.get());
+ return null;
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
index 5a8476d..386e657 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/spi/Resource.java
@@ -109,6 +109,7 @@ public interface Resource {
RootServiceComponent,
RootServiceHostComponent,
View,
+ ViewURL,
ViewVersion,
ViewInstance,
Blueprint,
@@ -225,6 +226,7 @@ public interface Resource {
public static final Type RootServiceComponent = InternalType.RootServiceComponent.getType();
public static final Type RootServiceHostComponent = InternalType.RootServiceHostComponent.getType();
public static final Type View = InternalType.View.getType();
+ public static final Type ViewURL = InternalType.ViewURL.getType();
public static final Type ViewVersion = InternalType.ViewVersion.getType();
public static final Type ViewInstance = InternalType.ViewInstance.getType();
public static final Type Blueprint = InternalType.Blueprint.getType();
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ViewURLDAO.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ViewURLDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ViewURLDAO.java
new file mode 100644
index 0000000..6a03489
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ViewURLDAO.java
@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.dao;
+
+import com.google.common.base.Optional;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.orm.RequiresSession;
+import org.apache.ambari.server.orm.entities.ViewInstanceDataEntity;
+import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.server.orm.entities.ViewURLEntity;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import java.util.List;
+
+/**
+ * View Instance Data Access Object.
+ */
+@Singleton
+public class ViewURLDAO {
+ /**
+ * JPA entity manager
+ */
+ @Inject
+ private Provider<EntityManager> entityManagerProvider;
+ @Inject
+ private DaoUtils daoUtils;
+
+
+ /**
+ * Find all view instances.
+ *
+ * @return all views or an empty List
+ */
+ @RequiresSession
+ public List<ViewURLEntity> findAll() {
+ TypedQuery<ViewURLEntity> query = entityManagerProvider.get().
+ createNamedQuery("allViewUrls", ViewURLEntity.class);
+
+ return query.getResultList();
+ }
+
+ /**
+ * Find URL by name
+ * @param urlName
+ * @return
+ */
+ @RequiresSession
+ public Optional<ViewURLEntity> findByName(String urlName) {
+ TypedQuery<ViewURLEntity> query = entityManagerProvider.get().
+ createNamedQuery("viewUrlByName", ViewURLEntity.class);
+ query.setParameter("urlName", urlName);
+ try {
+ return Optional.of(query.getSingleResult());
+ } catch (Exception e){
+ return Optional.absent();
+ }
+ }
+
+ /**
+ * Save a URL entity
+ * @param urlEntity
+ */
+ @Transactional
+ public void save(ViewURLEntity urlEntity) {
+ entityManagerProvider.get().persist(urlEntity);
+ // Reverse mappings are not automatically flushed for some reason
+ entityManagerProvider.get().flush();
+ }
+
+ /**
+ * Update and merge a URL entity
+ * @param entity
+ */
+ @Transactional
+ public void update(ViewURLEntity entity) {
+ entityManagerProvider.get().merge(entity);
+ entityManagerProvider.get().flush();
+
+ }
+
+ /**
+ * Remove a URL entity
+ * @param urlEntity
+ */
+ @Transactional
+ public void delete(ViewURLEntity urlEntity) {
+ entityManagerProvider.get().remove(urlEntity);
+ entityManagerProvider.get().flush();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 772b384..2d6e5ba 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
@@ -136,9 +136,11 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
private String icon;
- @Column(name = "short_url")
- @Basic
- private String shortUrl;
+ @OneToOne(cascade = CascadeType.ALL)
+ @JoinColumns({
+ @JoinColumn(name = "short_url", referencedColumnName = "url_id", nullable = true)
+ })
+ private ViewURLEntity viewUrl;
/**
* The big icon path.
@@ -249,7 +251,6 @@ 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;
@@ -288,7 +289,6 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
this.visible = 'Y';
this.alterNames = 1;
this.label = label;
- this.shortUrl = null;
}
@@ -355,10 +355,6 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
}
- @Override
- public String getShortUrl() {
- return shortUrl;
- }
@@ -399,14 +395,6 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
/**
- * Set the short URL
- * @param shortUrl
- */
- public void setShortUrl(String shortUrl) {
- this.shortUrl = shortUrl;
- }
-
- /**
* Get the name of this instance.
*
* @return the instance name
@@ -956,6 +944,29 @@ public class ViewInstanceEntity implements ViewInstanceDefinition {
return result;
}
+ /**
+ * Get the view URL associated with the instance
+ * @return
+ */
+ public ViewURLEntity getViewUrl() {
+ return viewUrl;
+ }
+
+ /**
+ * Set the view URL associated with the instance
+ * @param viewUrl
+ */
+ public void setViewUrl(ViewURLEntity viewUrl) {
+ this.viewUrl = viewUrl;
+ }
+
+ /**
+ * Remove the URL associated with this entity
+ */
+ public void clearUrl() {
+ this.viewUrl = null;
+ }
+
//----- ViewInstanceVersionDTO inner class --------------------------------------------------
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewURLEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewURLEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewURLEntity.java
new file mode 100644
index 0000000..c0ed24f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewURLEntity.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.orm.entities;
+
+import javax.persistence.Basic;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+/**
+ * Represents an entity of a View.
+ */
+@Table(name = "viewurl")
+@TableGenerator(name = "viewurl_id_generator",
+ table = "ambari_sequences", pkColumnName = "sequence_name", valueColumnName = "sequence_value"
+ , pkColumnValue = "viewurl_id_seq"
+ , initialValue = 1
+)
+
+@NamedQueries({
+ @NamedQuery(name = "allViewUrls",
+ query = "SELECT viewUrl FROM ViewURLEntity viewUrl"),
+ @NamedQuery(name = "viewUrlByName", query =
+ "SELECT viewUrlEntity " +
+ "FROM ViewURLEntity viewUrlEntity " +
+ "WHERE viewUrlEntity.urlName=:urlName")})
+
+
+@Entity
+public class ViewURLEntity {
+
+ @Column(name = "url_id")
+ @Id
+ @GeneratedValue(strategy = GenerationType.TABLE, generator = "viewentity_id_generator")
+ private Long id;
+
+ /**
+ * The view name.
+ */
+ @Column(name = "url_name", nullable = false, insertable = true, updatable = false)
+ private String urlName;
+
+ @Column(name = "url_suffix", nullable = false, insertable = true, updatable = true)
+ private String urlSuffix;
+
+ @OneToOne(fetch= FetchType.LAZY, mappedBy="viewUrl")
+ private ViewInstanceEntity viewInstanceEntity;
+
+
+ /**
+ * Get the URL suffix
+ * @return URL suffix
+ */
+ public String getUrlSuffix() {
+ return urlSuffix;
+ }
+
+ /**
+ * Set the URL suffix
+ * @param URL suffix
+ */
+ public void setUrlSuffix(String urlSuffix) {
+ this.urlSuffix = urlSuffix;
+ }
+
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ /**
+ * Get the URL name.
+ *
+ * @return the URL name
+ */
+ public String getUrlName() {
+ return urlName;
+ }
+
+ /**
+ * Set the URL name
+ *
+ * @param urlName the URL name
+ */
+ public void setUrlName(String urlName) {
+ this.urlName = urlName;
+ }
+
+ /**
+ * Get the linked instance entity
+ * @return viewInstanceEntity
+ */
+ public ViewInstanceEntity getViewInstanceEntity() {
+ return viewInstanceEntity;
+ }
+
+ /**
+ * Set the URL instance entity
+ * @param viewInstanceEntity
+ */
+ public void setViewInstanceEntity(ViewInstanceEntity viewInstanceEntity) {
+ this.viewInstanceEntity = viewInstanceEntity;
+ }
+
+ /**
+ * Remove the Instance entity associated with this View URL
+ */
+ public void clearEntity() {
+ this.viewInstanceEntity = null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 e76bc5c..14cb42c 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
@@ -108,6 +108,8 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
private static final String HIVE_ENV_CONFIG = "hive-env";
private static final String AMS_SITE = "ams-site";
public static final String TIMELINE_METRICS_SINK_COLLECTION_PERIOD = "timeline.metrics.sink.collection.period";
+ public static final String VIEWURL_TABLE = "viewurl";
+ public static final String URL_ID_COLUMN = "url_id";
@Inject
@@ -173,13 +175,28 @@ public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
updateAlertCurrentTable();
createBlueprintSettingTable();
updateHostRoleCommandTableDDL();
+ createViewUrlTableDDL();
updateViewInstanceEntityTable();
+ }
+
+ private void createViewUrlTableDDL() throws SQLException {
+ List<DBColumnInfo> columns = new ArrayList<>();
+
+ // Add setting table
+ LOG.info("Creating " + VIEWURL_TABLE + " table");
+ columns.add(new DBColumnInfo(URL_ID_COLUMN, Long.class, null, null, false));
+ columns.add(new DBColumnInfo("url_name", String.class, 255, null, false));
+ columns.add(new DBColumnInfo("url_suffix", String.class, 255, null, false));
+ dbAccessor.createTable(VIEWURL_TABLE, columns, URL_ID_COLUMN);
+ addSequence("viewurl_id_seq", 1L, false);
}
private void updateViewInstanceEntityTable() throws SQLException {
dbAccessor.addColumn(VIEWINSTANCE_TABLE,
- new DBColumnInfo(SHORT_URL_COLUMN, String.class, 255, null, true));
+ new DBColumnInfo(SHORT_URL_COLUMN, Long.class, null, null, true));
+ dbAccessor.addFKConstraint(VIEWINSTANCE_TABLE, "FK_instance_url_id",
+ SHORT_URL_COLUMN, VIEWURL_TABLE, URL_ID_COLUMN, false);
}
private void updateClusterTableDDL() throws SQLException {
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 c29fe0e..d23fcad 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
@@ -496,25 +496,6 @@ 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.
*
@@ -1408,7 +1389,7 @@ public class ViewRegistry {
private void syncViewInstance(ViewInstanceEntity instance1, ViewInstanceEntity instance2) {
instance1.setLabel(instance2.getLabel());
instance1.setDescription(instance2.getDescription());
- instance1.setShortUrl(instance2.getShortUrl());
+ instance1.setViewUrl(instance2.getViewUrl());
instance1.setVisible(instance2.isVisible());
instance1.setResource(instance2.getResource());
instance1.setViewInstanceId(instance2.getViewInstanceId());
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 65b36df..764d697 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
@@ -138,19 +138,4 @@ public class InstanceConfig {
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/f62a9277/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 93576f7..319afa5 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Derby-CREATE.sql
@@ -545,6 +545,15 @@ CREATE TABLE viewmain (
CONSTRAINT PK_viewmain PRIMARY KEY (view_name),
CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id));
+
+CREATE table viewurl(
+ url_id BIGINT ,
+ url_name VARCHAR(255) NOT NULL ,
+ url_suffix VARCHAR(255) NOT NULL,
+ PRIMARY KEY(url_id)
+);
+
+
CREATE TABLE viewinstance (
view_instance_id BIGINT,
resource_id BIGINT NOT NULL,
@@ -558,8 +567,9 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names SMALLINT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
- short_url VARCHAR (255),
+ short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
+ CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
CONSTRAINT FK_viewinst_view_name FOREIGN KEY (view_name) REFERENCES viewmain(view_name),
CONSTRAINT FK_viewinstance_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id),
CONSTRAINT UQ_viewinstance_name UNIQUE (view_name, name),
@@ -575,6 +585,7 @@ CREATE TABLE viewinstancedata (
CONSTRAINT PK_viewinstancedata PRIMARY KEY (view_instance_id, name, user_name),
CONSTRAINT FK_viewinstdata_view_name FOREIGN KEY (view_instance_id, view_name, view_instance_name) REFERENCES viewinstance(view_instance_id, view_name, name));
+
CREATE TABLE viewinstanceproperty (
view_name VARCHAR(255) NOT NULL,
view_instance_name VARCHAR(255) NOT NULL,
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 b0264f2..bdbf461 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -553,6 +553,15 @@ CREATE TABLE viewmain (
CONSTRAINT PK_viewmain PRIMARY KEY (view_name),
CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id));
+
+CREATE table viewurl(
+ url_id BIGINT ,
+ url_name VARCHAR(255) NOT NULL ,
+ url_suffix VARCHAR(255) NOT NULL,
+ PRIMARY KEY(url_id)
+);
+
+
CREATE TABLE viewinstance (
view_instance_id BIGINT,
resource_id BIGINT NOT NULL,
@@ -566,8 +575,9 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names TINYINT(1) NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
- short_url VARCHAR (255),
+ short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
+ CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
CONSTRAINT FK_viewinst_view_name FOREIGN KEY (view_name) REFERENCES viewmain(view_name),
CONSTRAINT FK_viewinstance_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id),
CONSTRAINT UQ_viewinstance_name UNIQUE (view_name, name),
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 56a6616..e1da719 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -544,6 +544,15 @@ CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL,
CONSTRAINT PK_viewmain PRIMARY KEY (view_name),
CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id));
+
+CREATE table viewurl(
+ url_id NUMBER ,
+ url_name VARCHAR(255) NOT NULL ,
+ url_suffix VARCHAR(255) NOT NULL,
+ PRIMARY KEY(url_id)
+);
+
+
CREATE TABLE viewinstance (
view_instance_id NUMBER(19),
resource_id NUMBER(19) NOT NULL,
@@ -557,8 +566,9 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names NUMBER(1) DEFAULT 1 NOT NULL,
cluster_handle VARCHAR(255),
- short_url VARCHAR (255),
+ short_url NUMBER,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
+ CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
CONSTRAINT FK_viewinst_view_name FOREIGN KEY (view_name) REFERENCES viewmain(view_name),
CONSTRAINT FK_viewinstance_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id),
CONSTRAINT UQ_viewinstance_name UNIQUE (view_name, name),
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 f18cdec..ab1eec4 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -544,6 +544,16 @@ CREATE TABLE viewmain (
CONSTRAINT PK_viewmain PRIMARY KEY (view_name),
CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id));
+
+
+CREATE table viewurl(
+ url_id BIGINT ,
+ url_name VARCHAR(255) NOT NULL ,
+ url_suffix VARCHAR(255) NOT NULL,
+ PRIMARY KEY(url_id)
+);
+
+
CREATE TABLE viewinstance (
view_instance_id BIGINT,
resource_id BIGINT NOT NULL,
@@ -557,8 +567,9 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names SMALLINT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
- short_url VARCHAR (255),
+ short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
+ CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
CONSTRAINT FK_viewinst_view_name FOREIGN KEY (view_name) REFERENCES viewmain(view_name),
CONSTRAINT FK_viewinstance_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id),
CONSTRAINT UQ_viewinstance_name UNIQUE (view_name, name),
@@ -574,6 +585,7 @@ CREATE TABLE viewinstancedata (
CONSTRAINT PK_viewinstancedata PRIMARY KEY (view_instance_id, name, user_name),
CONSTRAINT FK_viewinstdata_view_name FOREIGN KEY (view_instance_id, view_name, view_instance_name) REFERENCES viewinstance(view_instance_id, view_name, name));
+
CREATE TABLE viewinstanceproperty (
view_name VARCHAR(255) NOT NULL,
view_instance_name VARCHAR(255) NOT NULL,
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 4584d5e..9d5f5df 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
@@ -645,6 +645,16 @@ CREATE TABLE ambari.viewmain (
CONSTRAINT PK_viewmain PRIMARY KEY (view_name),
CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES ambari.adminresourcetype(resource_type_id));
+
+
+CREATE table ambari.viewurl(
+ url_id BIGINT ,
+ url_name VARCHAR(255) NOT NULL ,
+ url_suffix VARCHAR(255) NOT NULL,
+ PRIMARY KEY(url_id)
+);
+
+
CREATE TABLE ambari.viewinstance (
view_instance_id BIGINT,
resource_id BIGINT NOT NULL,
@@ -658,8 +668,9 @@ CREATE TABLE ambari.viewinstance (
xml_driven CHAR(1),
alter_names SMALLINT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
- short_url VARCHAR (255),
+ short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
+ CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES ambari.viewurl(url_id),
CONSTRAINT FK_viewinst_view_name FOREIGN KEY (view_name) REFERENCES ambari.viewmain(view_name),
CONSTRAINT FK_viewinstance_resource_id FOREIGN KEY (resource_id) REFERENCES ambari.adminresource(resource_id),
CONSTRAINT UQ_viewinstance_name UNIQUE (view_name, name),
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 d2737d7..fdba489 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLAnywhere-CREATE.sql
@@ -542,6 +542,15 @@ CREATE TABLE viewmain (
CONSTRAINT PK_viewmain PRIMARY KEY (view_name),
CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id));
+
+CREATE table viewurl(
+ url_id NUMERIC ,
+ url_name VARCHAR(255) NOT NULL ,
+ url_suffix VARCHAR(255) NOT NULL,
+ PRIMARY KEY(url_id)
+);
+
+
CREATE TABLE viewinstance (
view_instance_id NUMERIC(19),
resource_id NUMERIC(19) NOT NULL,
@@ -555,8 +564,9 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names BIT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
- short_url VARCHAR (255),
+ short_url NUMERIC,
CONSTRAINT PK_viewinstance PRIMARY KEY (view_instance_id),
+ CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
CONSTRAINT FK_viewinst_view_name FOREIGN KEY (view_name) REFERENCES viewmain(view_name),
CONSTRAINT FK_viewinstance_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id),
CONSTRAINT UQ_viewinstance_name UNIQUE (view_name, name),
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 c85ae46..a1da8e5 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-SQLServer-CREATE.sql
@@ -552,6 +552,15 @@ CREATE TABLE viewmain (
CONSTRAINT PK_viewmain PRIMARY KEY CLUSTERED (view_name),
CONSTRAINT FK_view_resource_type_id FOREIGN KEY (resource_type_id) REFERENCES adminresourcetype(resource_type_id));
+
+CREATE table viewurl(
+ url_id BIGINT ,
+ url_name VARCHAR(255) NOT NULL ,
+ url_suffix VARCHAR(255) NOT NULL,
+ PRIMARY KEY CLUSTERED (url_id)
+);
+
+
CREATE TABLE viewinstance (
view_instance_id BIGINT,
resource_id BIGINT NOT NULL,
@@ -565,8 +574,9 @@ CREATE TABLE viewinstance (
xml_driven CHAR(1),
alter_names BIT NOT NULL DEFAULT 1,
cluster_handle VARCHAR(255),
- short_url VARCHAR (255),
+ short_url BIGINT,
CONSTRAINT PK_viewinstance PRIMARY KEY CLUSTERED (view_instance_id),
+ CONSTRAINT FK_instance_url_id FOREIGN KEY (short_url) REFERENCES viewurl(url_id),
CONSTRAINT FK_viewinst_view_name FOREIGN KEY (view_name) REFERENCES viewmain(view_name),
CONSTRAINT FK_viewinstance_resource_id FOREIGN KEY (resource_id) REFERENCES adminresource(resource_id),
CONSTRAINT UQ_viewinstance_name UNIQUE (view_name, name),
@@ -582,6 +592,7 @@ CREATE TABLE viewinstancedata (
CONSTRAINT PK_viewinstancedata PRIMARY KEY CLUSTERED (view_instance_id, NAME, user_name),
CONSTRAINT FK_viewinstdata_view_name FOREIGN KEY (view_instance_id, view_name, view_instance_name) REFERENCES viewinstance(view_instance_id, view_name, name));
+
CREATE TABLE viewinstanceproperty (
view_name VARCHAR(255) NOT NULL,
view_instance_name VARCHAR(255) NOT NULL,
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/resources/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/META-INF/persistence.xml b/ambari-server/src/main/resources/META-INF/persistence.xml
index 3eff96f..ce563cb 100644
--- a/ambari-server/src/main/resources/META-INF/persistence.xml
+++ b/ambari-server/src/main/resources/META-INF/persistence.xml
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- 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
+<!-- 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. -->
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
@@ -78,6 +78,7 @@
<class>org.apache.ambari.server.orm.entities.ViewEntityEntity</class>
<class>org.apache.ambari.server.orm.entities.ViewInstanceDataEntity</class>
<class>org.apache.ambari.server.orm.entities.ViewInstanceEntity</class>
+ <class>org.apache.ambari.server.orm.entities.ViewURLEntity</class>
<class>org.apache.ambari.server.orm.entities.ViewInstancePropertyEntity</class>
<class>org.apache.ambari.server.orm.entities.ViewParameterEntity</class>
<class>org.apache.ambari.server.orm.entities.ViewResourceEntity</class>
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 aedac18..1044570 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
@@ -281,55 +281,6 @@ public class ViewInstanceResourceProviderTest {
}
- @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 {
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
index ae69589..cdecc4d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog240Test.java
@@ -209,9 +209,17 @@ public class UpgradeCatalog240Test {
Capture<DBAccessor.DBColumnInfo> hostRoleCommandOriginalStartTimeColumnInfo = newCapture();
dbAccessor.addColumn(eq(UpgradeCatalog240.HOST_ROLE_COMMAND_TABLE), capture(hostRoleCommandOriginalStartTimeColumnInfo));
+ Capture<List<DBAccessor.DBColumnInfo>> capturedViewUrlColums = EasyMock.newCapture();
+ dbAccessor.createTable(eq(UpgradeCatalog240.VIEWURL_TABLE), capture(capturedViewUrlColums),eq("url_id"));
+ expect(dbAccessor.getConnection()).andReturn(connection);
+ expect(connection.createStatement()).andReturn(statement);
+
Capture<DBAccessor.DBColumnInfo> viewInstanceShortUrlInfo = newCapture();
dbAccessor.addColumn(eq(UpgradeCatalog240.VIEWINSTANCE_TABLE), capture(viewInstanceShortUrlInfo));
+ dbAccessor.addFKConstraint(UpgradeCatalog240.VIEWINSTANCE_TABLE, "FK_instance_url_id",
+ UpgradeCatalog240.SHORT_URL_COLUMN, UpgradeCatalog240.VIEWURL_TABLE, "url_id", false);
+
replay(dbAccessor, configuration, connection, statement, resultSet);
@@ -348,11 +356,14 @@ public class UpgradeCatalog240Test {
Assert.assertEquals(Long.class, originalStartTimeInfo.getType());
Assert.assertEquals(-1L, originalStartTimeInfo.getDefaultValue());
- // Verify host_role_command column
DBAccessor.DBColumnInfo viewInstanceEntityUrlColInfoValue = viewInstanceShortUrlInfo.getValue();
Assert.assertNotNull(viewInstanceEntityUrlColInfoValue);
Assert.assertEquals("short_url", viewInstanceEntityUrlColInfoValue.getName());
- Assert.assertEquals(String.class, viewInstanceEntityUrlColInfoValue.getType());
+ Assert.assertEquals(Long.class, viewInstanceEntityUrlColInfoValue.getType());
+
+ List<DBAccessor.DBColumnInfo> capturedViewUrlColumsValue = capturedViewUrlColums.getValue();
+ Assert.assertNotNull(capturedViewUrlColumsValue);
+ Assert.assertEquals(capturedViewUrlColumsValue.size(),3);
verify(dbAccessor);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 62f9657..0c3d3ce 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
@@ -61,11 +61,6 @@ public interface ViewInstanceDefinition {
*/
public String getClusterHandle();
- /**
- * Get the short URL
- * @return
- */
- public String getShortUrl();
/**
* Indicates whether or not the view instance should be visible.
[2/2] ambari git commit: AMBARI-15821 Ability to provide logical urls
to view instances,
Added URL wizard and other UI fixes(Ashwin Rajeev via dipayanb)
Posted by db...@apache.org.
AMBARI-15821 Ability to provide logical urls to view instances, Added URL wizard and other UI fixes(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/f62a9277
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f62a9277
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f62a9277
Branch: refs/heads/trunk
Commit: f62a927708bddb5f1dffe7342131cb307a550eee
Parents: 614b12f
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Tue Apr 26 12:33:26 2016 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Tue Apr 26 12:33:26 2016 +0530
----------------------------------------------------------------------
.../main/resources/ui/admin-web/app/index.html | 5 +-
.../ambariViews/CreateViewInstanceCtrl.js | 5 +
.../controllers/ambariViews/ViewUrlCtrl.js | 153 ++++++++
.../controllers/ambariViews/ViewUrlEditCtrl.js | 94 +++++
.../controllers/ambariViews/ViewsEditCtrl.js | 3 +-
.../controllers/ambariViews/ViewsListCtrl.js | 14 +-
.../ui/admin-web/app/scripts/i18n.config.js | 26 +-
.../ui/admin-web/app/scripts/routes.js | 20 ++
.../ui/admin-web/app/scripts/services/View.js | 136 ++++++-
.../resources/ui/admin-web/app/styles/main.css | 23 +-
.../admin-web/app/views/ambariViews/create.html | 8 -
.../admin-web/app/views/ambariViews/edit.html | 9 +-
.../app/views/ambariViews/listTable.html | 130 +++----
.../app/views/ambariViews/listUrls.html | 72 ++++
.../ui/admin-web/app/views/leftNavbar.html | 18 +-
.../ui/admin-web/app/views/urls/create.html | 51 +++
.../admin-web/app/views/urls/create_step_1.html | 36 ++
.../admin-web/app/views/urls/create_step_2.html | 44 +++
.../admin-web/app/views/urls/create_step_3.html | 60 ++++
.../ui/admin-web/app/views/urls/edit.html | 73 ++++
.../resources/ResourceInstanceFactoryImpl.java | 4 +
.../resources/ViewUrlResourceDefinition.java | 54 +++
.../server/api/services/ViewUrlsService.java | 144 ++++++++
.../internal/DefaultProviderModule.java | 2 +
.../internal/ViewInstanceResourceProvider.java | 23 +-
.../internal/ViewURLResourceProvider.java | 358 +++++++++++++++++++
.../ambari/server/controller/spi/Resource.java | 2 +
.../ambari/server/orm/dao/ViewURLDAO.java | 111 ++++++
.../server/orm/entities/ViewInstanceEntity.java | 45 ++-
.../server/orm/entities/ViewURLEntity.java | 144 ++++++++
.../server/upgrade/UpgradeCatalog240.java | 19 +-
.../apache/ambari/server/view/ViewRegistry.java | 21 +-
.../view/configuration/InstanceConfig.java | 15 -
.../main/resources/Ambari-DDL-Derby-CREATE.sql | 13 +-
.../main/resources/Ambari-DDL-MySQL-CREATE.sql | 12 +-
.../main/resources/Ambari-DDL-Oracle-CREATE.sql | 12 +-
.../resources/Ambari-DDL-Postgres-CREATE.sql | 14 +-
.../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql | 13 +-
.../resources/Ambari-DDL-SQLAnywhere-CREATE.sql | 12 +-
.../resources/Ambari-DDL-SQLServer-CREATE.sql | 13 +-
.../src/main/resources/META-INF/persistence.xml | 19 +-
.../ViewInstanceResourceProviderTest.java | 49 ---
.../server/upgrade/UpgradeCatalog240Test.java | 15 +-
.../ambari/view/ViewInstanceDefinition.java | 5 -
44 files changed, 1853 insertions(+), 246 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/index.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
index fa911a6..8d7e8e7 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
@@ -90,7 +90,7 @@
</div>
</div>
-
+
<!-- build:js scripts/vendor.js -->
<!-- bower:js -->
<script src="bower_components/jquery/dist/jquery.js"></script>
@@ -119,6 +119,7 @@
<script src="bower_components/bootstrap/js/scrollspy.js"></script>
<script src="bower_components/bootstrap/js/collapse.js"></script>
<script src="bower_components/bootstrap/js/tab.js"></script>
+
<!-- endbuild -->
<!-- build:js scripts/main.js -->
@@ -139,6 +140,8 @@
<script src="scripts/controllers/groups/GroupsEditCtrl.js"></script>
<script src="scripts/controllers/ambariViews/ViewsListCtrl.js"></script>
<script src="scripts/controllers/ambariViews/ViewsEditCtrl.js"></script>
+ <script src="scripts/controllers/ambariViews/ViewUrlCtrl.js"></script>
+ <script src="scripts/controllers/ambariViews/ViewUrlEditCtrl.js"></script>
<script src="scripts/controllers/ambariViews/CreateViewInstanceCtrl.js"></script>
<script src="scripts/controllers/clusters/ClustersManageAccessCtrl.js"></script>
<script src="scripts/controllers/clusters/UserAccessListCtrl.js"></script>
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
index 962b795..127bc74 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
@@ -198,4 +198,9 @@ angular.module('ambariAdminConsole')
}
});
+
+
+
+
+
}]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlCtrl.js
new file mode 100644
index 0000000..0cf8d03
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlCtrl.js
@@ -0,0 +1,153 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('ViewUrlCtrl',['$scope', 'View', 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', function($scope, View, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate) {
+ var $t = $translate.instant;
+ $scope.form = {};
+ $scope.constants = {
+ props: $t('views.properties')
+ };
+ var targetUrl = '/viewUrls';
+ $scope.url={};
+ $scope.formHolder = {};
+
+ View.getAllVisibleInstance().then(function(views) {
+ var names = [];
+ var instances=[];
+ views.map(function(view){
+ var nameVersion = view.view_name+" {"+view.version+"}";
+ names.push(nameVersion);
+ instances.push({nameV:nameVersion,instance:view.instance_name,cname:view.view_name,version:view.version});
+ });
+
+ var output = [],
+ keys = [];
+
+ angular.forEach(names, function(item) {
+ var key = item;
+ if(keys.indexOf(key) === -1) {
+ keys.push(key);
+ output.push(item);
+ }
+ });
+
+ $scope.viewsVersions = output;
+ $scope.viewInstances = instances;
+
+ if($routeParams.viewName && $routeParams.viewVersion && $routeParams.viewInstanceName){
+ var selectedView = $routeParams.viewName+" {"+$routeParams.viewVersion+"}";
+ $scope.url.selectedView = selectedView;
+ $scope.url.selectedInstance = instances.find(function(inst){
+ return inst.nameV === selectedView && inst.instance === $routeParams.viewInstanceName && inst.version === $routeParams.viewVersion && inst.cname === $routeParams.viewName;
+ });
+ }
+
+ }).catch(function(data) {
+ Alert.error($t('views.alerts.cannotLoadViews'), data.data.message);
+ });
+
+ $scope.filterByName = function(nameV){
+ return function (item) {
+ if (item.nameV === nameV)
+ {
+ return true;
+ }
+ return false;
+ };
+ };
+
+ $scope.chomp = function(viewNameVersion){
+ return viewNameVersion.substr(0,viewNameVersion.indexOf("{")).trim();
+ };
+
+
+ $scope.wizardController = function () {
+ var wizard = this;
+
+ //Model
+ wizard.currentStep = 1;
+ wizard.steps = [
+ {
+ step: 1,
+ name: $t('urls.step1'),
+ template: "views/urls/create_step_1.html"
+ },
+ {
+ step: 2,
+ name: $t('urls.step2'),
+ template: "views/urls/create_step_2.html"
+ },
+ {
+ step: 3,
+ name: $t('urls.step3'),
+ template: "views/urls/create_step_3.html"
+ }
+ ];
+ wizard.user = {};
+
+ //Functions
+ wizard.gotoStep = function(newStep) {
+ $scope.formHolder.form.submitted = true;
+ if (newStep < wizard.currentStep || $scope.formHolder.form.$valid) {
+ wizard.currentStep = newStep;
+ }
+ };
+
+ wizard.getStepTemplate = function(){
+ for (var i = 0; i < wizard.steps.length; i++) {
+ if (wizard.currentStep == wizard.steps[i].step) {
+ return wizard.steps[i].template;
+ }
+ }
+ };
+
+ wizard.save = function() {
+ $scope.formHolder.form.submitted = true;
+
+ if($scope.formHolder.form.$valid){
+
+ var payload = {ViewUrlInfo:{
+ url_name:$scope.url.urlName,
+ url_suffix:$scope.url.suffix,
+ view_instance_version:$scope.url.selectedInstance.version,
+ view_instance_name:$scope.url.selectedInstance.instance,
+ view_instance_common_name:$scope.url.selectedInstance.cname
+ }};
+
+ View.updateShortUrl(payload).then(function(urlStatus) {
+ Alert.success($t('urls.urlCreated', {
+ viewName:$scope.url.selectedInstance.cname ,
+ shortUrl:$scope.url.suffix,
+ urlName:$scope.url.urlName
+ }));
+ $scope.formHolder.form.$setPristine();
+ $location.path(targetUrl);
+ }).catch(function(data) {
+ Alert.error($t('views.alerts.cannotLoadViewUrls'), data.message);
+ });
+
+ }
+ };
+ }
+
+
+
+
+}]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlEditCtrl.js
new file mode 100644
index 0000000..93edc69
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewUrlEditCtrl.js
@@ -0,0 +1,94 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.controller('ViewUrlEditCtrl',['$scope', 'View', 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate','ConfirmationModal' ,function($scope, View, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate,ConfirmationModal) {
+ var $t = $translate.instant;
+ $scope.form = {};
+ $scope.constants = {
+ props: $t('views.properties')
+ };
+ var targetUrl = '/viewUrls';
+
+
+ function setUpEdit(){
+
+ View.getUrlInfo($routeParams.urlName).then(function(url) {
+ $scope.url = url.ViewUrlInfo;
+ $scope.nameVersion = url.ViewUrlInfo.view_instance_common_name +" {" + url.ViewUrlInfo.view_instance_version +"}"
+ }).catch(function(data) {
+ Alert.error($t('views.alerts.cannotLoadViewUrl'), data.data.message);
+ });
+ }
+
+ setUpEdit();
+
+
+ $scope.updateUrl = function() {
+ $scope.url_form.submitted = true;
+
+ if($scope.url_form.$valid){
+
+ var payload = {ViewUrlInfo:{
+ url_name:$scope.url.url_name,
+ url_suffix:$scope.url.url_suffix,
+ view_instance_version:'',
+ view_instance_name:'',
+ view_instance_common_name:''
+ }};
+
+ View.editShortUrl(payload).then(function(urlStatus) {
+ Alert.success($t('urls.urlUpdated', {
+ viewName:$scope.url.view_instance_common_name ,
+ shortUrl:$scope.url.suffix,
+ urlName:$scope.url.url_name
+ }));
+ $scope.url_form.$setPristine();
+ $location.path(targetUrl);
+ }).catch(function(data) {
+ Alert.error($t('views.alerts.cannotLoadViewUrls'), data.data.message);
+ });
+
+ }
+ };
+
+
+ $scope.deleteUrl = function() {
+
+ ConfirmationModal.show(
+ $t('common.delete', {
+ term: $t('urls.url')
+ }),
+ $t('common.deleteConfirmation', {
+ instanceType: $t('urls.url').toLowerCase(),
+ instanceName: '"' + $scope.url.url_name + '"'
+ })
+ ).then(function() {
+ View.deleteUrl($scope.url.url_name).then(function() {
+ $location.path(targetUrl);
+ });
+ });
+
+
+
+ };
+
+
+
+}]);
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 d46a30f..877e230 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
@@ -244,8 +244,7 @@ angular.module('ambariAdminConsole')
'ViewInstanceInfo':{
'visible': $scope.settings.visible,
'label': $scope.settings.label,
- 'description': $scope.settings.description,
- 'short_url': $scope.settings.shortUrl
+ 'description': $scope.settings.description
}
};
return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data)
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
index 6d1dc52..ed389e1 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js
@@ -18,7 +18,7 @@
'use strict';
angular.module('ambariAdminConsole')
-.controller('ViewsListCtrl',['$scope', 'View', '$modal', 'Alert', 'ConfirmationModal', '$location', '$translate', function($scope, View, $modal, Alert, ConfirmationModal, $location, $translate) {
+.controller('ViewsListCtrl',['$scope', 'View','$modal', 'Alert', 'ConfirmationModal', '$location', '$translate', function($scope, View, $modal, Alert, ConfirmationModal, $location, $translate) {
var deferredList = [],
$t = $translate.instant;
$scope.constants = {
@@ -128,6 +128,18 @@ angular.module('ambariAdminConsole')
$scope.reloadViews = function () {
loadViews();
+ };
+
+
+ $scope.listViewUrls = function(){
+ View.allUrls().then(function(urls) {
+ $scope.urls = urls;
+ $scope.ViewNameFilterOptions = urls.items.map(function(url){
+ return url.ViewUrlInfo.view_instance_common_name;
+ });
+ }).catch(function(data) {
+ Alert.error($t('views.alerts.cannotLoadViewUrls'), data.data.message);
+ });
}
}]);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 68a4bec..3e475d9 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
@@ -32,6 +32,7 @@ angular.module('ambariAdminConsole')
'signOut': 'Sign out',
'clusters': 'Clusters',
'views': 'Views',
+ 'viewUrls': 'View URL\'s',
'roles': 'Roles',
'users': 'Users',
'groups': 'Groups',
@@ -132,7 +133,9 @@ angular.module('ambariAdminConsole')
'cannotLoadClusterStatus': 'Cannot load cluster status',
'clusterRenamed': 'The cluster has been renamed to {{clusterName}}.',
'cannotRenameCluster': 'Cannot rename cluster to {{clusterName}}',
- 'unsavedChanges': 'You have unsaved changes. Save changes or discard?'
+ 'tooShort': 'URL is too short',
+ 'tooLong': 'URL is too long',
+ 'onlyText': 'You can add only text urls in the lower case'
}
},
@@ -202,6 +205,8 @@ angular.module('ambariAdminConsole')
'pending': 'Pending...',
'deploying': 'Deploying...',
'properties': 'properties',
+ 'urlCreate':'Create new URL',
+ 'urlDelete':'Delete URL',
'alerts': {
'noSpecialChars': 'Must not contain any special characters.',
@@ -222,10 +227,27 @@ angular.module('ambariAdminConsole')
'cannotSaveSettings': 'Cannot save settings',
'cannotSaveProperties': 'Cannot save properties',
'cannotDeleteInstance': 'Cannot delete instance',
- 'cannotLoadViews': 'Cannot load views'
+ 'cannotLoadViews': 'Cannot load views',
+ 'cannotLoadViewUrls': 'Cannot load view URL\'s',
+ 'cannotLoadViewUrl': 'Cannot load view URL'
}
},
+ 'urls':{
+ 'name':'Name',
+ 'url':'URL',
+ 'create':'Create',
+ 'edit':'Edit',
+ 'view':'View',
+ 'viewInstance':'Instance',
+ 'step1':'Create URL',
+ 'step2':'Select instance',
+ 'step3':'Assign URL',
+ 'noUrlsToDisplay':'No short URL\'s configured',
+ 'urlCreated':'Created short URL <a href="/#/main/view/{{viewName}}/{{shortUrl}}">{{urlName}}</a>',
+ 'urlUpdated':'Updated short URL <a href="/#/main/view/{{viewName}}/{{shortUrl}}">{{urlName}}</a>'
+ },
+
'clusters': {
'switchToList': 'Switch to list view',
'switchToBlock': 'Switch to block view',
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
index 4fc4ea6..0566969 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
@@ -88,6 +88,26 @@ angular.module('ambariAdminConsole')
templateUrl: 'views/ambariViews/listTable.html',
controller: 'ViewsListCtrl'
},
+ listViewUrls: {
+ url: '/viewUrls',
+ templateUrl: 'views/ambariViews/listUrls.html',
+ controller: 'ViewsListCtrl'
+ },
+ createViewUrl:{
+ url: '/urls/new',
+ templateUrl: 'views/urls/create.html',
+ controller: 'ViewUrlCtrl'
+ },
+ linkViewUrl:{
+ url: '/urls/link/:viewName/:viewVersion/:viewInstanceName',
+ templateUrl: 'views/urls/create.html',
+ controller: 'ViewUrlCtrl'
+ },
+ editViewUrl:{
+ url: '/urls/edit/:urlName',
+ templateUrl: 'views/urls/edit.html',
+ controller: 'ViewUrlEditCtrl'
+ },
edit: {
url: '/views/:viewId/versions/:version/instances/:instanceId/edit',
templateUrl: 'views/ambariViews/edit.html',
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 cbe11e4..36bd32d 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
@@ -24,6 +24,8 @@ angular.module('ambariAdminConsole')
angular.extend(this, item);
}
+
+
ViewInstance.find = function(viewName, version, instanceName) {
var deferred = $q.defer();
var fields = [
@@ -51,6 +53,114 @@ angular.module('ambariAdminConsole')
};
+ function ViewUrl(item) {
+ angular.extend(this, item);
+ }
+
+ function URLStatus(item){
+ angular.element(this,item);
+ }
+
+ ViewUrl.all = function() {
+ var deferred = $q.defer();
+
+ $http({
+ method: 'GET',
+ dataType: "json",
+ url: Settings.baseUrl + '/view/urls',
+
+ })
+ .success(function(data) {
+ deferred.resolve(new ViewUrl(data));
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+
+ return deferred.promise;
+ };
+
+
+ ViewUrl.updateShortUrl = function(payload){
+ var deferred = $q.defer();
+
+ $http({
+ method: 'POST',
+ dataType: "json",
+ url: Settings.baseUrl + '/view/urls/'+payload.ViewUrlInfo.url_name,
+ data:payload
+ })
+ .success(function(data) {
+ deferred.resolve(new URLStatus(data));
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+
+ return deferred.promise;
+ };
+
+ ViewUrl.deleteUrl = function(urlName){
+ var deferred = $q.defer();
+
+ $http({
+ method: 'DELETE',
+ dataType: "json",
+ url: Settings.baseUrl + '/view/urls/'+ urlName,
+ })
+ .success(function(data) {
+ deferred.resolve(new URLStatus(data));
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+
+ return deferred.promise;
+ };
+
+
+ ViewUrl.editShortUrl = function(payload){
+ var deferred = $q.defer();
+
+ $http({
+ method: 'PUT',
+ dataType: "json",
+ url: Settings.baseUrl + '/view/urls/'+payload.ViewUrlInfo.url_name,
+ data:payload
+ })
+ .success(function(data) {
+ deferred.resolve(new URLStatus(data));
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+
+ return deferred.promise;
+ };
+
+
+ ViewUrl.urlInfo = function(urlName){
+
+ var deferred = $q.defer();
+
+ $http({
+ method: 'GET',
+ dataType: "json",
+ url: Settings.baseUrl + '/view/urls/'+urlName,
+
+ })
+ .success(function(data) {
+ deferred.resolve(new ViewUrl(data));
+ })
+ .error(function(data) {
+ deferred.reject(data);
+ });
+
+ return deferred.promise;
+ };
+
+
+
function View(item){
var self = this;
self.view_name = item.ViewInfo.view_name;
@@ -79,6 +189,27 @@ angular.module('ambariAdminConsole')
return ViewInstance.find(viewName, version, instanceName);
};
+ View.allUrls = function(){
+ return ViewUrl.all()
+ };
+
+ View.getUrlInfo = function(urlName){
+ return ViewUrl.urlInfo(urlName);
+ };
+
+ View.deleteUrl = function(urlName){
+ return ViewUrl.deleteUrl(urlName);
+ };
+
+
+ View.updateShortUrl = function(payload){
+ return ViewUrl.updateShortUrl(payload);
+ };
+
+ View.editShortUrl = function(payload){
+ return ViewUrl.editShortUrl(payload);
+ };
+
View.deleteInstance = function(viewName, version, instanceName) {
return $http.delete(Settings.baseUrl +'/views/'+viewName+'/versions/'+version+'/instances/'+instanceName, {
headers: {
@@ -168,8 +299,7 @@ angular.module('ambariAdminConsole')
visible: instanceInfo.visible,
icon_path: instanceInfo.icon_path,
icon64_path: instanceInfo.icon64_path,
- description: instanceInfo.description,
- short_url:instanceInfo.shortUrl
+ description: instanceInfo.description
};
angular.forEach(instanceInfo.properties, function(property) {
@@ -308,7 +438,7 @@ angular.module('ambariAdminConsole')
url: Settings.baseUrl + '/views',
params:{
'fields': fields.join(','),
- 'versions/ViewVersionInfo/system': false
+ 'versions/ViewVersionInfo/system' : false
}
}).success(function(data) {
var views = [];
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
index edf8524..b55d89c 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -97,7 +97,7 @@
-webkit-transform: rotateX(0deg);
-ms-transform: rotateX(0deg);
-o-transform: rotateX(0deg);
- transform: rotateX(0deg);
+ transform: rotateX(0deg);
}
.editable-list-container .actions-panel.ng-hide{
-webkit-transform: rotateX(90deg);
@@ -215,6 +215,10 @@
display: inline-block;
}
+ .small-input{
+ max-width: 300px;
+ }
+
.paginator{
margin: 0;
}
@@ -471,7 +475,7 @@ a.gotoinstance{
display: block;
float: left;
text-decoration: none;
-
+
}
#top-nav .navbar.navbar-static-top .brand.cluster-name{
margin-left: 10px;
@@ -487,7 +491,7 @@ a.gotoinstance{
}
.create-view-form .description h4 span{
font-weight: normal;
-
+
}
.create-view-form .view-header{
}
@@ -553,7 +557,7 @@ a.gotoinstance{
top: 5px;
right: 50px;
z-index: 10;
-}
+}
.views-list-pane .search-container .close{
right: 50px;
top: 5px;
@@ -629,6 +633,9 @@ ul.nav li > a{
.padding-left-30{
padding-left: 30px;
}
+.padding-bottom-30{
+ padding-bottom: 30px;
+}
.no-margin-bottom{
margin-bottom: 0!important;
}
@@ -1136,7 +1143,7 @@ button.btn.btn-xs{
-ms-transform: translateX(1000px);
-o-transform: translateX(1000px);
transform: translateX(1000px);
-
+
padding: 0;
margin: 0;
max-height: 0;
@@ -1260,15 +1267,15 @@ button.btn.btn-xs{
}
@-webkit-keyframes stretchdelay {
- 0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
+ 0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
20% { -webkit-transform: scaleY(1.0) }
}
@keyframes stretchdelay {
- 0%, 40%, 100% {
+ 0%, 40%, 100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
- } 20% {
+ } 20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 20ccadb..eaff70b 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
@@ -77,14 +77,6 @@
</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/f62a9277/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 b41abc8..8eff030 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
@@ -78,14 +78,13 @@
</div>
</div>
-
- <div class="form-group" ng-class="{'has-error' : form.instanceCreateForm.submitted }">
+ <div class="form-group">
<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">
-
+ <p class="form-control-static"><a href="/#/main/view/{{instance.ViewInstanceInfo.view_name}}/{{settings.shortUrl}}" ng-if="settings.shortUrl">{{settings.shortUrl}}</a></p>
+ <a ng-if="!settings.shortUrl" href="#/urls/link/{{instance.ViewInstanceInfo.view_name}}/{{instance.ViewInstanceInfo.version}}/{{instance.ViewInstanceInfo.instance_name}}" class="btn btn-primary createuser-btn"><span class="glyphicon glyphicon-plus"></span> {{'views.urlCreate' | translate}}</a>
+ </div>
</div>
- </div>
<div class="form-group">
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html
index ae71d78..906eef5 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html
@@ -15,87 +15,87 @@
* See the License for the specific language governing permissions and
* limitations under the License.
-->
-
+
<div class="views-list-table">
- <div class="clearfix">
- <ol class="breadcrumb pull-left">
- <li class="active">{{'common.views' | translate}}</li>
- <button ng-click="reloadViews()"
- class="btn btn-xs">
- <i class="glyphicon glyphicon-refresh"></i>
- </button>
- </ol>
- <div class="pull-right col-sm-4">
- <div class="input-group search-container">
- <input type="text" class="form-control search-input" placeholder="{{'common.search' | translate}}" ng-model="viewsFilter" ng-change="getFilteredViews()">
- <button type="button" class="close clear-search" ng-show="viewsFilter" ng-click="viewsFilter=''; getFilteredViews()"><span aria-hidden="true">×</span><span class="sr-only">{{"common.controls.close" | translate}}</span></button>
+ <div class="clearfix">
+ <ol class="breadcrumb pull-left">
+ <li class="active">{{'common.views' | translate}}</li>
+ <button ng-click="reloadViews()"
+ class="btn btn-xs">
+ <i class="glyphicon glyphicon-refresh"></i>
+ </button>
+ </ol>
+ <div class="pull-right col-sm-4">
+ <div class="input-group search-container">
+ <input type="text" class="form-control search-input" placeholder="{{'common.search' | translate}}" ng-model="viewsFilter" ng-change="getFilteredViews()">
+ <button type="button" class="close clear-search" ng-show="viewsFilter" ng-click="viewsFilter=''; getFilteredViews()"><span aria-hidden="true">×</span><span class="sr-only">{{"common.controls.close" | translate}}</span></button>
<span class="input-group-addon">
<span class="glyphicon glyphicon-search"></span>
</span>
- </div>
+ </div>
+ </div>
</div>
- </div>
- <hr>
- <div class="row">
- <div class="col-sm-3 padding-left-30"><h4>{{'views.viewName' | translate}}</h4></div>
- <div class="col-sm-3"><h4>{{'views.instances' | translate}}</h4></div>
- <div class="col-sm-6"><h4></h4></div>
- </div>
- <accordion close-others="false">
- <accordion-group ng-repeat="view in filteredViews" is-open="view.isOpened">
- <accordion-heading>
- <div class="row">
- <div class="col-sm-3">
- <i class="glyphicon glyphicon-chevron-right" ng-class="{'opened': view.isOpened}"></i>
- {{view.view_name}}
- </div>
- <div class="col-sm-3">
+ <hr>
+ <div class="row">
+ <div class="col-sm-3 padding-left-30"><h4>{{'views.viewName' | translate}}</h4></div>
+ <div class="col-sm-3"><h4>{{'views.instances' | translate}}</h4></div>
+ <div class="col-sm-6"><h4></h4></div>
+ </div>
+ <accordion close-others="false">
+ <accordion-group ng-repeat="view in filteredViews" is-open="view.isOpened">
+ <accordion-heading>
+ <div class="row">
+ <div class="col-sm-3">
+ <i class="glyphicon glyphicon-chevron-right" ng-class="{'opened': view.isOpened}"></i>
+ {{view.view_name}}
+ </div>
+ <div class="col-sm-3">
<span ng-repeat="(version, vData) in view.versions">
{{version}}
<span ng-switch="vData.status">
<span ng-switch-when="PENDING" class="viewstatus pending" ng-switch-when="true" tooltip="{{'views.pending' | translate}}"></span>
<div class="viewstatus deploying" ng-switch-when="DEPLOYING" tooltip="{{'views.deploying' | translate}}">
- <div class="rect1"></div>
- <div class="rect2"></div>
- <div class="rect3"></div>
+ <div class="rect1"></div>
+ <div class="rect2"></div>
+ <div class="rect3"></div>
</div>
<span ng-switch-when="DEPLOYED">({{vData.count}})</span>
<span ng-switch-when="ERROR" tooltip="{{'views.alerts.deployError' | translate}}"><i class="fa fa-exclamation-triangle"></i></span>
</span>
{{$last ? '' : ', '}}
</span>
- </div>
- <div class="col-sm-6">{{view.description}}</div>
+ </div>
+ <div class="col-sm-6">{{view.description}}</div>
+ </div>
+ </accordion-heading>
+ <table class="table instances-table">
+ <tbody>
+ <tr ng-repeat="instance in view.instances">
+ <td class="col-sm-1"></td>
+ <td class="col-sm-5">
+ <a href="#/views/{{view.view_name}}/versions/{{instance.ViewInstanceInfo.version}}/instances/{{instance.ViewInstanceInfo.instance_name}}/edit" class="instance-link">{{instance.label}}</a>
+ </td>
+ <td class="col-sm-5">{{instance.ViewInstanceInfo.version}}</td>
+ <td class="col-sm-5 " ><div class="description-column" tooltip="{{instance.ViewInstanceInfo.description}}">{{instance.ViewInstanceInfo.description || 'No description'}}</div>
+ </td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td class="col-sm-3"></td>
+ <td class="col-sm-3">
+ <a tooltip="{{view.canCreateInstance ? '' : constants.unable}}" class="btn btn-default createisntance-btn {{view.canCreateInstance ? '' : 'disabled'}}" href ng-click="gotoCreate(view.view_name, view.canCreateInstance);"><span class="glyphicon glyphicon-plus"></span> {{'views.create' | translate}}</a>
+ </td>
+ <td class="col-sm-3"></td>
+ <td class="col-sm-3">
+ </td>
+ </tr>
+ </tfoot>
+ </table>
+ </accordion-group>
+ <div class="alert alert-info" ng-show="views && !filteredViews.length">
+ {{'common.alerts.nothingToDisplay' | translate: '{term: constants.views}'}}
</div>
- </accordion-heading>
- <table class="table instances-table">
- <tbody>
- <tr ng-repeat="instance in view.instances">
- <td class="col-sm-1"></td>
- <td class="col-sm-5">
- <a href="#/views/{{view.view_name}}/versions/{{instance.ViewInstanceInfo.version}}/instances/{{instance.ViewInstanceInfo.instance_name}}/edit" class="instance-link">{{instance.label}}</a>
- </td>
- <td class="col-sm-5">{{instance.ViewInstanceInfo.version}}</td>
- <td class="col-sm-5 " ><div class="description-column" tooltip="{{instance.ViewInstanceInfo.description}}">{{instance.ViewInstanceInfo.description || 'No description'}}</div>
- </td>
- </tr>
- </tbody>
- <tfoot>
- <tr>
- <td class="col-sm-3"></td>
- <td class="col-sm-3">
- <a tooltip="{{view.canCreateInstance ? '' : constants.unable}}" class="btn btn-default createisntance-btn {{view.canCreateInstance ? '' : 'disabled'}}" href ng-click="gotoCreate(view.view_name, view.canCreateInstance);"><span class="glyphicon glyphicon-plus"></span> {{'views.create' | translate}}</a>
- </td>
- <td class="col-sm-3"></td>
- <td class="col-sm-3">
- </td>
- </tr>
- </tfoot>
- </table>
- </accordion-group>
- <div class="alert alert-info" ng-show="views && !filteredViews.length">
- {{'common.alerts.nothingToDisplay' | translate: '{term: constants.views}'}}
- </div>
- </accordion>
+ </accordion>
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html
new file mode 100644
index 0000000..a2949f9
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html
@@ -0,0 +1,72 @@
+<!--
+* 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.
+-->
+
+<div class="views-list-table" data-ng-init="listViewUrls()">
+
+
+ <div class="clearfix">
+ <ol class="breadcrumb pull-left">
+ <li class="active">{{'common.viewUrls' | translate}}</li>
+ </ol>
+ <div class="pull-right top-margin-4">
+ <link-to route="views.createViewUrl" class="btn btn-primary createuser-btn"><span class="glyphicon glyphicon-plus"></span> {{'views.urlCreate' | translate}}</link-to>
+ </div>
+ </div>
+ <hr>
+ <table class="table table-striped table-hover">
+ <thead>
+ <tr>
+
+ <th>
+ <span class="padding-bottom-30">{{'urls.name' | translate}}</span>
+ </th>
+ <th>
+ <span class="padding-bottom-30">{{'urls.url' | translate}}</span>
+ </th>
+ <th>
+ <span class="padding-bottom-30">{{'urls.view' | translate}}</span>
+ </th>
+ <th>
+ <span class="padding-bottom-30">{{'urls.viewInstance' | translate}}</span>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="url in urls.items">
+
+ <td>
+ <a href="#/urls/edit/{{url.ViewUrlInfo.url_name}}">{{url.ViewUrlInfo.url_name}}</a>
+ </td>
+ <td>
+ <a href="/#/main/view/{{url.ViewUrlInfo.view_instance_common_name}}/{{url.ViewUrlInfo.url_suffix}}">/main/view/{{url.ViewUrlInfo.view_instance_common_name}}/{{url.ViewUrlInfo.url_suffix}}</a>
+ </td>
+ <td>
+ <span>{{url.ViewUrlInfo.view_instance_common_name}} {{"{"+url.ViewUrlInfo.view_instance_version+"}"}} </span>
+ </td>
+ <td>
+ <span>{{url.ViewUrlInfo.view_instance_name}}</span>
+ </td>
+
+ </tr>
+ </tbody>
+ </table>
+ <div class="alert alert-info col-sm-12" ng-show="!urls.items.length">
+ {{'urls.noUrlsToDisplay'| translate}}
+ </div>
+
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
index 9bc54ff..b155041 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
@@ -22,19 +22,19 @@
<div class="cluster-section" ng-show="cluster">
<div id="cluster-name" ng-switch on="editCluster.editingName">
<h5 ng-switch-when="false"><div title={{cluster.Clusters.cluster_name}} class="clusterDisplayName">{{clusterDisplayName()}}</div>
- <i ng-show="cluster.Clusters.provisioning_state == 'INSTALLED'"
- ng-click="toggleEditName()"
+ <i ng-show="cluster.Clusters.provisioning_state == 'INSTALLED'"
+ ng-click="toggleEditName()"
class="glyphicon glyphicon-edit pull-right edit-cluster-name renameCluster" tooltip="{{'common.renameCluster' | translate}}">
</i>
</h5>
- <form ng-keyup="toggleEditName($event)"
- tabindex="1"
- name="editClusterNameForm"
- class="editClusterNameForm"
+ <form ng-keyup="toggleEditName($event)"
+ tabindex="1"
+ name="editClusterNameForm"
+ class="editClusterNameForm"
ng-switch-when="true"
ng-submit="editCluster.name !== cluster.Clusters.cluster_name && editClusterNameForm.newClusterName.$valid && confirmClusterNameChange()">
- <div class="form-group"
+ <div class="form-group"
ng-class="{'has-error': editClusterNameForm.newClusterName.$invalid && !editClusterNameForm.newClusterName.$pristine }">
<input
autofocus
@@ -91,10 +91,12 @@
<div class="panel-body">
<ul class="nav nav-pills nav-stacked">
<li ng-class="{active: isActive('views.list')}"><link-to route="views.list" class="viewslist-link">{{'common.views' | translate}}</link-to></li>
+ <li ng-class="{active: isActive('views.listViewUrls')}"><link-to route="views.listViewUrls" class="viewsUrlList-link">{{'common.viewUrls' | translate}}</link-to></li>
</ul>
</div>
</div>
+
<div class="panel panel-default">
<div class="panel-heading"><span class="glyphicon glyphicon-user"></span> {{'common.userGroupManagement' | translate}}</div>
<div class="panel-body">
@@ -115,4 +117,4 @@
</div>
</div>
</div>
-
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
new file mode 100644
index 0000000..eb31b42
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
@@ -0,0 +1,51 @@
+<!--
+* 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.
+-->
+<ol class="breadcrumb">
+ <li><a href="#/users">{{'urls.url' | translate}}</a></li>
+ <li class="active">{{'urls.create' | translate}}</li>
+</ol>
+<hr>
+ <div class="row">
+ <div class="col-sm-10">
+
+ <div id="wizard-container" ng-controller="wizardController as wizard">
+
+ <div id="wizard-step-container" class="bottom-margin">
+ <ul class="nav nav-pills nav-justified">
+ <li ng-repeat="step in wizard.steps" ng-class="{'active':step.step == wizard.currentStep}"><a ng-click="wizard.gotoStep(step.step)" href="">{{step.name}}</a></li>
+ </ul>
+ </div>
+
+ <div id="wizard-content-container">
+ <ng-include src="wizard.getStepTemplate()"></ng-include>
+ </div>
+
+ <div id="wizard-navigation-container">
+ <div class="pull-right">
+ <span class="btn-group">
+ <button ng-disabled="wizard.currentStep <= 1" class="btn btn-default" name="previous" type="button" ng-click="wizard.gotoStep(wizard.currentStep - 1)"><i class="fa fa-arrow-left"></i> Previous step</button>
+ <button ng-disabled="wizard.currentStep >= wizard.steps.length" class="btn btn-primary" name="next" type="button" ng-click="wizard.gotoStep(wizard.currentStep + 1)">Next step <i class="fa fa-arrow-right"></i></button>
+ </span>
+ <button ng-disabled="wizard.currentStep != wizard.steps.length" class="btn btn-success" name="next" type="button" ng-click="wizard.save()"> <i class="fa fa-floppy-o"></i> Save</button>
+ </div>
+ </div>
+
+ </div>
+
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_1.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_1.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_1.html
new file mode 100644
index 0000000..e19313e
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_1.html
@@ -0,0 +1,36 @@
+<!--
+* 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.
+-->
+
+<form ng-controller="wizardController as wizard" class="form-horizontal create-user-form" role="form" novalidate name="formHolder.form" autocomplete="off">
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_name.$error.required && formHolder.form.submitted}">
+ <label for="urlname" class="col-sm-2 control-label">{{'urls.name' | translate}}</label>
+ <div class="col-sm-10">
+ <input type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'urls.name' | translate}}" ng-model="url.urlName" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_view_name.$error.required && formHolder.form.submitted}">
+ <label for="urlselect" class="col-sm-2 control-label">{{'urls.view' | translate}}</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="urlselect" name="url_view_name" ng-options="version for version in viewsVersions" ng-model="url.selectedView" required></select>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+</form>
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_2.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_2.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_2.html
new file mode 100644
index 0000000..36bce88
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_2.html
@@ -0,0 +1,44 @@
+<!--
+* 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.
+-->
+<form class="form-horizontal create-user-form" role="form" novalidate name="formHolder.form" autocomplete="off">
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_name.$error.required && formHolder.form.submitted}">
+ <label for="urlname" class="col-sm-2 control-label">{{'urls.name' | translate}}</label>
+ <div class="col-sm-10">
+ <input disabled type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'urls.name' | translate}}" ng-model="url.urlName" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_view_name.$error.required && formHolder.form.submitted}">
+ <label for="urlselect" class="col-sm-2 control-label">{{'urls.view' | translate}}</label>
+ <div class="col-sm-10">
+ <select class="form-control" disabled id="urlselect" name="url_view_name" ng-options="version for version in viewsVersions" ng-model="url.selectedView" required></select>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_view_instance_name.$error.required && formHolder.form.submitted}">
+ <label for="urlinstanceselect" class="col-sm-2 control-label">{{'urls.viewInstance' | translate}}</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="urlinstanceselect" name="url_view_instance_name" ng-options="instance.instance for instance in viewInstances | filter:filterByName(url.selectedView)" ng-model="url.selectedInstance" required></select>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_instance_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+</form>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_3.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_3.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_3.html
new file mode 100644
index 0000000..e6b3c1c
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create_step_3.html
@@ -0,0 +1,60 @@
+<!--
+* 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.
+-->
+<form class="form-horizontal create-user-form" role="form" novalidate name="formHolder.form" autocomplete="off">
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_name.$error.required && formHolder.form.submitted}">
+ <label for="urlname" class="col-sm-2 control-label">{{'urls.name' | translate}}</label>
+ <div class="col-sm-10">
+ <input disabled type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'urls.name' | translate}}" ng-model="url.urlName" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_view_name.$error.required && formHolder.form.submitted}">
+ <label for="urlselect" class="col-sm-2 control-label">{{'urls.view' | translate}}</label>
+ <div class="col-sm-10">
+ <select class="form-control" disabled id="urlselect" name="url_view_name" ng-options="version for version in viewsVersions" ng-model="url.selectedView" required></select>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_view_instance_name.$error.required && formHolder.form.submitted}">
+ <label for="urlinstanceselect" class="col-sm-2 control-label">{{'urls.viewInstance' | translate}}</label>
+ <div class="col-sm-10">
+ <select class="form-control" disabled id="urlinstanceselect" name="url_view_instance_name" ng-options="instance.instance for instance in viewInstances | filter:filterByName(url.selectedView)" ng-model="url.selectedInstance" required></select>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_instance_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+
+
+ <div class="form-group" ng-class="{'has-error' : formHolder.form.url_view_suffix.$error.required && formHolder.form.submitted}">
+ <label for="urlsuffixin" class="col-sm-2 control-label">{{'views.shortUrl' | translate}}</label>
+ <div class="col-sm-10">
+ <div class="input-group">
+ <span id="basic-addon1" class="input-group-addon">/main/view/{{chomp(url.selectedView)}}/</span><input aria-describedby="basic-addon1" type="text" class="form-control" id="urlsuffixin" name="url_view_suffix" placeholder="{{'views.shortUrl' | translate}}" ng-model="url.suffix" ng-pattern="/[a-z]+/" ng-minlength="3" ng-maxlength="10" required autocomplete="off">
+ </div>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_suffix.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_suffix.$error.minlength && formHolder.form.submitted">{{'common.alerts.tooShort' | translate}}</div>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_suffix.$error.maxlength && formHolder.form.submitted">{{'common.alerts.tooLong' | translate}}</div>
+ <div class="alert alert-danger top-margin" ng-show="formHolder.form.url_view_suffix.$error.pattern && formHolder.form.submitted">{{'common.alerts.onlyText' | translate}}</div>
+
+ </div>
+ </div>
+
+</form>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
new file mode 100644
index 0000000..de7722e
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
@@ -0,0 +1,73 @@
+<!--
+* 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.
+-->
+<ol class="breadcrumb">
+ <li><a href="#/users">{{'urls.url' | translate}}</a></li>
+ <li class="active">{{'urls.edit' | translate}}</li>
+ <div class="pull-right top-margin-4">
+ <button class="btn deleteuser-btn btn-danger" ng-click="deleteUrl()">{{'views.urlDelete' | translate}}</button>
+ </div>
+</ol>
+<hr>
+
+
+<form class="form-horizontal create-user-form" role="form" novalidate name="url_form" autocomplete="off">
+ <div class="form-group" ng-class="{'has-error' : url_form.url_name.$error.required && url_form.submitted}">
+ <label for="urlname" class="col-sm-2 control-label">{{'urls.name' | translate}}</label>
+ <div class="col-sm-10">
+ <input disabled type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'urls.name' | translate}}" ng-model="url.url_name" required autocomplete="off">
+ <div class="alert alert-danger top-margin" ng-show="url_form.url_name.$error.required && url_form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+
+ <div class="form-group" ng-class="{'has-error' : url_form.url_view_name.$error.required && url_form.submitted}">
+ <label for="urlselect" class="col-sm-2 control-label">{{'urls.view' | translate}}</label>
+ <div class="col-sm-10">
+ <input class="form-control" disabled id="urlselect" name="url_view_name" ng-model="nameVersion" required>
+ <div class="alert alert-danger top-margin" ng-show="url_form.url_view_name.$error.required && url_form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+ <div class="form-group" ng-class="{'has-error' : url_form.url_view_instance_name.$error.required && url_form.submitted}">
+ <label for="urlinstanceselect" class="col-sm-2 control-label">{{'urls.viewInstance' | translate}}</label>
+ <div class="col-sm-10">
+ <input class="form-control" disabled id="urlinstanceselect" name="url_view_instance_name" ng-model="url.view_instance_name" required>
+ <div class="alert alert-danger top-margin" ng-show="url_form.url_view_instance_name.$error.required && url_form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ </div>
+ </div>
+
+
+
+ <div class="form-group" ng-class="{'has-error' : url_form.url_view_suffix.$error.required && url_form.submitted}">
+ <label for="urlsuffixin" class="col-sm-2 control-label">{{'views.shortUrl' | translate}}</label>
+ <div class="col-sm-10">
+ <div class="input-group">
+ <span id="basic-addon1" class="input-group-addon">/main/view/{{url.view_instance_common_name}}/</span><input aria-describedby="basic-addon1" type="text" class="form-control" id="urlsuffixin" name="url_view_suffix" placeholder="{{'views.shortUrl' | translate}}" ng-model="url.url_suffix" ng-pattern="/[a-z]+/" ng-minlength="3" ng-maxlength="10" required autocomplete="off">
+ </div>
+ <div class="alert alert-danger top-margin" ng-show="url_form.url_view_suffix.$error.required && url_form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
+ <div class="alert alert-danger top-margin" ng-show="url_form.url_view_suffix.$error.minlength && url_form.submitted">{{'common.alerts.tooShort' | translate}}</div>
+ <div class="alert alert-danger top-margin" ng-show="url_form.url_view_suffix.$error.maxlength && url_form.submitted">{{'common.alerts.tooLong' | translate}}</div>
+ <div class="alert alert-danger top-margin" ng-show="url_form.url_view_suffix.$error.pattern && url_form.submitted">{{'common.alerts.onlyText' | translate}}</div>
+
+ </div>
+ </div>
+ <div class="pull-right">
+ <button ng-disabled="wizard.currentStep != wizard.steps.length" class="btn btn-success" name="update_url_button" type="button" ng-click="updateUrl()"> <i class="fa fa-edit"></i> Update</button>
+ </div>
+
+</form>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
index eed2703..0b77511 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceFactoryImpl.java
@@ -237,6 +237,10 @@ public class ResourceInstanceFactoryImpl implements ResourceInstanceFactory {
resourceDefinition = new ViewInstanceResourceDefinition(subResourceDefinitions);
break;
+ case ViewURL:
+ resourceDefinition = new ViewUrlResourceDefinition();
+ break;
+
case Blueprint:
resourceDefinition = new BlueprintResourceDefinition();
break;
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewUrlResourceDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewUrlResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewUrlResourceDefinition.java
new file mode 100644
index 0000000..d2c7b62
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ViewUrlResourceDefinition.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.resources;
+
+import org.apache.ambari.server.controller.spi.Resource;
+
+import java.util.Collections;
+import java.util.Set;
+
+
+/**
+ * View resource definition.
+ */
+public class ViewUrlResourceDefinition extends BaseResourceDefinition {
+
+ // ----- Constructors ------------------------------------------------------
+
+ /**
+ * Construct a view resource definition.
+ */
+ public ViewUrlResourceDefinition() {
+ super(Resource.Type.ViewURL);
+ }
+
+
+ // ----- ResourceDefinition ------------------------------------------------
+
+ @Override
+ public String getPluralName() {
+ return "view_urls";
+ }
+
+ @Override
+ public String getSingularName() {
+ return "view_url";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java
new file mode 100644
index 0000000..3827c18
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ViewUrlsService.java
@@ -0,0 +1,144 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import com.google.common.base.Optional;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+
+
+/**
+ * Service responsible for view resource requests.
+ */
+@Path("/view/urls")
+public class ViewUrlsService extends BaseService {
+
+ /**
+ * Get the list of all registered view URLs
+ * @param headers
+ * @param ui
+
+ * @return collections of all view urls and any instances registered against them
+ */
+ @GET
+ @Produces("text/plain")
+ public Response getViewUrls(@Context HttpHeaders headers, @Context UriInfo ui) {
+ return handleRequest(headers, null, ui, Request.Type.GET, createViewUrlResource(Optional.<String>absent()));
+ }
+
+
+ /**
+ * Create a new View URL
+ * @param body
+ * @param headers
+ * @param ui
+ * @param urlName
+ * @return
+ * @throws AuthorizationException
+ */
+ @POST
+ @Path("{urlName}")
+ @Produces("text/plain")
+ public Response createUrl(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("urlName") String urlName) throws AuthorizationException {
+ return handleRequest(headers, body, ui, Request.Type.POST, createViewUrlResource(Optional.of(urlName)));
+ }
+
+
+ /**
+ * Update a view URL
+ * @param body
+ * @param headers
+ * @param ui
+ * @param urlName
+ * @return
+ * @throws AuthorizationException
+ */
+ @PUT
+ @Path("{urlName}")
+ @Produces("text/plain")
+ public Response updateUrl(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("urlName") String urlName) throws AuthorizationException {
+ return handleRequest(headers, body, ui, Request.Type.PUT, createViewUrlResource(Optional.of(urlName)));
+ }
+
+ /**
+ * Remove a view URL
+ * @param body
+ * @param headers
+ * @param ui
+ * @param urlName
+ * @return
+ * @throws AuthorizationException
+ */
+ @DELETE
+ @Path("{urlName}")
+ @Produces("text/plain")
+ public Response deleteUrl(String body, @Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("urlName") String urlName) throws AuthorizationException {
+ return handleRequest(headers, body, ui, Request.Type.DELETE, createViewUrlResource(Optional.of(urlName)));
+ }
+
+
+ /**
+ * Get information about a single view URL
+ * @param headers
+ * @param ui
+ * @param urlName
+ * @return
+ * @throws AuthorizationException
+ */
+ @GET
+ @Path("{urlName}")
+ @Produces("text/plain")
+ public Response getUrl(@Context HttpHeaders headers, @Context UriInfo ui,
+ @PathParam("urlName") String urlName) throws AuthorizationException {
+ return handleRequest(headers, null, ui, Request.Type.GET, createViewUrlResource(Optional.of(urlName)));
+ }
+
+
+
+
+ // ----- helper methods ----------------------------------------------------
+
+ /**
+ * Create a view URL resource.
+ *
+ * @param urlName Name of the URL
+ *
+ * @return a view URL resource instance
+ */
+ private ResourceInstance createViewUrlResource(Optional<String> urlName) {
+ return createResource(Resource.Type.ViewURL,Collections.singletonMap(Resource.Type.ViewURL, urlName.isPresent()?urlName.get().toString():null));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
index c7dc117..4e7a032 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
@@ -68,6 +68,8 @@ public class DefaultProviderModule extends AbstractProviderModule {
return new ViewVersionResourceProvider();
case ViewInstance:
return new ViewInstanceResourceProvider();
+ case ViewURL:
+ return new ViewURLResourceProvider();
case StackServiceComponentDependency:
return new StackDependencyResourceProvider(propertyIds, keyPropertyIds);
case Permission:
http://git-wip-us.apache.org/repos/asf/ambari/blob/f62a9277/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 6523962..2a9eee7 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
@@ -35,6 +35,7 @@ import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.orm.entities.ViewEntity;
import org.apache.ambari.server.orm.entities.ViewInstanceDataEntity;
import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
+import org.apache.ambari.server.orm.entities.ViewURLEntity;
import org.apache.ambari.server.security.authorization.RoleAuthorization;
import org.apache.ambari.server.view.ViewRegistry;
import org.apache.ambari.server.view.validation.InstanceValidationResultImpl;
@@ -242,7 +243,10 @@ 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);
+ ViewURLEntity viewUrl = viewInstanceEntity.getViewUrl();
+ if(viewUrl != null) {
+ setResourceProperty(resource, SHORT_URL_PROPERTY_ID, viewUrl.getUrlSuffix(), requestedIds);
+ }
// only allow an admin to access the view properties
if (ViewRegistry.getInstance().checkAdmin()) {
@@ -344,11 +348,6 @@ 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();
@@ -402,11 +401,6 @@ 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.");
}
@@ -428,16 +422,9 @@ 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);