/** * 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 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; 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.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 com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.Sets; import com.google.inject.Inject; /** * 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<>(); static { keyPropertyIds.put(Resource.Type.ViewURL, URL_NAME_PROPERTY_ID); } /** * The property ids for a view URL resource. */ private static Set<String> propertyIds = new HashSet<>(); 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(); Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate); for (Map<String, Object> propertyMap : propertyMaps) { String urlNameProperty = (String) propertyMap.get(URL_NAME_PROPERTY_ID); if (!Strings.isNullOrEmpty(urlNameProperty)) { Optional<ViewURLEntity> urlEntity = viewURLDAO.findByName(urlNameProperty); if(urlEntity.isPresent()){ resources.add(toResource(urlEntity.get())); } } else { 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<>(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>() { @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; } }; } }