| /** |
| * 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.view; |
| |
| import org.apache.ambari.server.controller.internal.AbstractResourceProvider; |
| import org.apache.ambari.server.controller.internal.RequestStatusImpl; |
| import org.apache.ambari.server.controller.internal.ResourceImpl; |
| 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.TemporalInfo; |
| import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; |
| import org.apache.ambari.server.controller.utilities.PropertyHelper; |
| import org.apache.ambari.server.orm.entities.ViewEntity; |
| import org.apache.ambari.server.orm.entities.ViewInstanceEntity; |
| import org.apache.ambari.view.ReadRequest; |
| |
| import java.beans.IntrospectionException; |
| import java.beans.Introspector; |
| import java.beans.PropertyDescriptor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * An SPI resource provider implementation used to adapt a |
| * view resource provider to the SPI interfaces for view |
| * sub-resources. |
| */ |
| public class ViewSubResourceProvider extends AbstractResourceProvider { |
| |
| private static final String VIEW_NAME_PROPERTY_ID = "view_name"; |
| private static final String VIEW_VERSION_PROPERTY_ID = "version"; |
| private static final String INSTANCE_NAME_PROPERTY_ID = "instance_name"; |
| |
| private final ViewEntity viewDefinition; |
| private final String pkField; |
| private final Resource.Type type; |
| private final Map<String, PropertyDescriptor> descriptorMap; |
| |
| private final Set<String> pkPropertyIds; |
| |
| |
| // ----- Constructors ------------------------------------------------------ |
| |
| /** |
| * Construct a view resource provider for the given resource type and bean class. |
| * |
| * @param type the resource type |
| * @param clazz the resource bean class |
| * @param pkField the primary key field name |
| * @param viewDefinition the associated view definition |
| * |
| * @throws IntrospectionException if an exception occurs during introspection of the resource bean class |
| */ |
| public ViewSubResourceProvider(Resource.Type type, Class<?> clazz, String pkField, ViewEntity viewDefinition) |
| throws IntrospectionException { |
| |
| super(discoverPropertyIds(clazz), getKeyPropertyIds(pkField, type)); |
| this.pkField = pkField; |
| this.viewDefinition = viewDefinition; |
| this.pkPropertyIds = new HashSet<String>(getKeyPropertyIds().values()); |
| this.type = type; |
| this.descriptorMap = getDescriptorMap(clazz); |
| } |
| |
| |
| // ----- ResourceProvider -------------------------------------------------- |
| |
| @Override |
| public RequestStatus createResources(Request request) |
| throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException { |
| |
| Set<Map<String, Object>> properties = request.getProperties(); |
| |
| for (Map<String, Object> propertyMap : properties) { |
| String resourceId = (String) propertyMap.get(pkField); |
| String instanceName = (String) propertyMap.get(INSTANCE_NAME_PROPERTY_ID); |
| |
| try { |
| getResourceProvider(instanceName).createResource(resourceId, propertyMap); |
| } catch (org.apache.ambari.view.NoSuchResourceException e) { |
| throw new NoSuchParentResourceException(e.getMessage(), e); |
| } catch (org.apache.ambari.view.UnsupportedPropertyException e) { |
| throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds()); |
| } catch (org.apache.ambari.view.ResourceAlreadyExistsException e) { |
| throw new ResourceAlreadyExistsException(e.getMessage()); |
| } catch (Exception e) { |
| LOG.error("Caught exception creating view sub resources.", e); |
| throw new SystemException(e.getMessage(), e); |
| } |
| } |
| return new RequestStatusImpl(null); |
| } |
| |
| @Override |
| public Set<Resource> getResources(Request request, Predicate predicate) |
| throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { |
| |
| Set<String> requestedIds = getRequestPropertyIds(request, predicate); |
| |
| Set<ViewInstanceEntity> instanceDefinitions = new HashSet<ViewInstanceEntity>(); |
| |
| try { |
| |
| Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate); |
| int size = propertyMaps.size(); |
| |
| Collection<ViewInstanceEntity> viewInstanceDefinitions = viewDefinition.getInstances(); |
| if (size == 0) { |
| instanceDefinitions.addAll(viewInstanceDefinitions); |
| } else { |
| for (Map<String, Object> propertyMap : propertyMaps) { |
| String instanceName = (String) propertyMap.get(INSTANCE_NAME_PROPERTY_ID); |
| if (size == 1 && instanceName != null) { |
| String resourceId = (String) propertyMap.get(pkField); |
| if (resourceId != null) { |
| Object bean = getResourceProvider(instanceName).getResource(resourceId, requestedIds); |
| return Collections.singleton(getResource(bean, viewDefinition.getCommonName(), |
| viewDefinition.getVersion(), instanceName, requestedIds)); |
| } |
| } |
| if (instanceName == null) { |
| instanceDefinitions.addAll(viewInstanceDefinitions); |
| break; |
| } else { |
| ViewInstanceEntity instanceDefinition = viewDefinition.getInstanceDefinition(instanceName); |
| if (instanceDefinition != null) { |
| instanceDefinitions.add(instanceDefinition); |
| } |
| } |
| } |
| } |
| |
| Set<Resource> results = new HashSet<Resource>(); |
| ReadRequest readRequest = new ViewReadRequest(request, requestedIds, predicate == null ? "" : predicate.toString()); |
| for (ViewInstanceEntity instanceDefinition : instanceDefinitions) { |
| |
| Set<?> beans = instanceDefinition.getResourceProvider(type).getResources(readRequest); |
| |
| for (Object bean : beans) { |
| Resource resource = getResource(bean, viewDefinition.getCommonName(), |
| viewDefinition.getVersion(), instanceDefinition.getName(), requestedIds); |
| if (predicate.evaluate(resource)) { |
| results.add(resource); |
| } |
| } |
| } |
| return results; |
| } catch (org.apache.ambari.view.NoSuchResourceException e) { |
| throw new NoSuchParentResourceException(e.getMessage(), e); |
| } catch (org.apache.ambari.view.UnsupportedPropertyException e) { |
| throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds()); |
| } catch (Exception e) { |
| LOG.error("Caught exception getting view sub resources.", e); |
| throw new SystemException(e.getMessage(), e); |
| } |
| } |
| |
| @Override |
| public RequestStatus updateResources(Request request, Predicate predicate) |
| throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { |
| Iterator<Map<String,Object>> iterator = request.getProperties().iterator(); |
| |
| if (iterator.hasNext()) { |
| Map<String,Object> propertyMap = iterator.next(); |
| Set<Resource> resources = getResources(request, predicate); |
| |
| for (Resource resource : resources) { |
| String resourceId = (String) resource.getPropertyValue(pkField); |
| String instanceName = (String) resource.getPropertyValue(INSTANCE_NAME_PROPERTY_ID); |
| |
| try { |
| getResourceProvider(instanceName).updateResource(resourceId, propertyMap); |
| } catch (org.apache.ambari.view.NoSuchResourceException e) { |
| throw new NoSuchParentResourceException(e.getMessage(), e); |
| } catch (org.apache.ambari.view.UnsupportedPropertyException e) { |
| throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds()); |
| } catch (Exception e) { |
| LOG.error("Caught exception updating view sub resources.", e); |
| throw new SystemException(e.getMessage(), e); |
| } |
| } |
| } |
| return new RequestStatusImpl(null); |
| } |
| |
| @Override |
| public RequestStatus deleteResources(Request request, Predicate predicate) |
| throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { |
| |
| Set<Resource> resources = getResources(PropertyHelper.getReadRequest(), predicate); |
| for (Resource resource : resources) { |
| String resourceId = (String) resource.getPropertyValue(pkField); |
| String instanceName = (String) resource.getPropertyValue(INSTANCE_NAME_PROPERTY_ID); |
| |
| try { |
| getResourceProvider(instanceName).deleteResource(resourceId); |
| } catch (org.apache.ambari.view.NoSuchResourceException e) { |
| throw new NoSuchParentResourceException(e.getMessage(), e); |
| } catch (org.apache.ambari.view.UnsupportedPropertyException e) { |
| throw new UnsupportedPropertyException(getResourceType(e), e.getPropertyIds()); |
| } catch (Exception e) { |
| LOG.error("Caught exception deleting view sub resources.", e); |
| throw new SystemException(e.getMessage(), e); |
| } |
| } |
| return new RequestStatusImpl(null); |
| } |
| |
| @Override |
| protected Set<String> getPKPropertyIds() { |
| return pkPropertyIds; |
| } |
| |
| |
| // ----- helper methods ---------------------------------------------------- |
| |
| // get a Resource from the bean |
| private Resource getResource(Object bean, String viewName, String viewVersion, |
| String instanceName, Set<String> requestedIds) |
| throws InvocationTargetException, IllegalAccessException { |
| |
| Resource resource = new ResourceImpl(type); |
| |
| resource.setProperty(VIEW_NAME_PROPERTY_ID, viewName); |
| resource.setProperty(VIEW_VERSION_PROPERTY_ID, viewVersion); |
| resource.setProperty(INSTANCE_NAME_PROPERTY_ID, instanceName); |
| |
| for (Map.Entry<String, PropertyDescriptor> entry : descriptorMap.entrySet()) { |
| Object value = entry.getValue().getReadMethod().invoke(bean); |
| |
| setResourceProperty(resource, entry.getKey(), value, requestedIds); |
| } |
| return resource; |
| } |
| |
| // get the resource provider associated with the given instance name for this resource type |
| private org.apache.ambari.view.ResourceProvider<?> getResourceProvider(String instanceName) { |
| return viewDefinition.getInstanceDefinition(instanceName).getResourceProvider(type); |
| } |
| |
| // get the resource type associated with the given UnsupportedPropertyException |
| private Resource.Type getResourceType(org.apache.ambari.view.UnsupportedPropertyException e) { |
| Resource.Type type = Resource.Type.valueOf(e.getType()); |
| return type == null ? this.type : type; |
| } |
| |
| // discover the property ids for the given bean class |
| private static Set<String> discoverPropertyIds(Class<?> clazz) throws IntrospectionException { |
| Set<String> propertyIds = new HashSet<String>(getDescriptorMap(clazz).keySet()); |
| propertyIds.add(INSTANCE_NAME_PROPERTY_ID); |
| propertyIds.add(VIEW_NAME_PROPERTY_ID); |
| propertyIds.add(VIEW_VERSION_PROPERTY_ID); |
| |
| return propertyIds; |
| } |
| |
| // get a descriptor map for the given bean class |
| private static Map<String, PropertyDescriptor> getDescriptorMap(Class<?> clazz) throws IntrospectionException { |
| Map<String, PropertyDescriptor> descriptorMap = new HashMap<String, PropertyDescriptor>(); |
| |
| for (PropertyDescriptor pd : Introspector.getBeanInfo(clazz).getPropertyDescriptors()) { |
| String name = pd.getName(); |
| if (pd.getReadMethod() != null && !name.equals("class")) { |
| descriptorMap.put(name, pd); |
| } |
| } |
| return descriptorMap; |
| } |
| |
| // get the key property ids for the resource |
| private static Map<Resource.Type, String> getKeyPropertyIds(String pkField, Resource.Type type) { |
| |
| Map<Resource.Type, String> keyPropertyIds = new HashMap<Resource.Type, String>(); |
| |
| keyPropertyIds.put(Resource.Type.View, VIEW_NAME_PROPERTY_ID); |
| keyPropertyIds.put(Resource.Type.ViewVersion, VIEW_VERSION_PROPERTY_ID); |
| keyPropertyIds.put(Resource.Type.ViewInstance, INSTANCE_NAME_PROPERTY_ID); |
| keyPropertyIds.put(type, pkField); |
| |
| return keyPropertyIds; |
| } |
| |
| |
| // ----- inner class : ViewReadRequest ------------------------------------- |
| |
| /** |
| * A read request to pass the the view resource provider. Serves |
| * as a bridge from the ambari-server API framework request to the |
| * view framework request. |
| */ |
| private static class ViewReadRequest implements ReadRequest { |
| |
| /** |
| * The original request. |
| */ |
| private final Request request; |
| |
| /** |
| * The property ids of the request. |
| */ |
| private final Set<String> propertyIds; |
| |
| /** |
| * The request predicate. |
| */ |
| private final String predicate; |
| |
| |
| // ----- Constructors ---------------------------------------------------- |
| |
| /** |
| * Construct a view read request. |
| * |
| * @param propertyIds the property ids |
| * @param predicate the predicate |
| */ |
| private ViewReadRequest(Request request, Set<String> propertyIds, String predicate) { |
| this.request = request; |
| this.propertyIds = propertyIds; |
| this.predicate = predicate; |
| } |
| |
| |
| // ----- ReadRequest ----------------------------------------------------- |
| |
| @Override |
| public Set<String> getPropertyIds() { |
| return propertyIds; |
| } |
| |
| @Override |
| public String getPredicate() { |
| return predicate; |
| } |
| |
| @Override |
| public TemporalInfo getTemporalInfo(String id) { |
| |
| org.apache.ambari.server.controller.spi.TemporalInfo temporalInfo = |
| request.getTemporalInfo(id); |
| |
| return temporalInfo == null ? null : new ViewReadRequestTemporalInfo(temporalInfo); |
| } |
| } |
| |
| /** |
| * Temporal information to pass to the view resource provider. Serves as a |
| * bridge from the ambari-server API framework temporal info object to the |
| * view framework temporal info object. |
| */ |
| private static class ViewReadRequestTemporalInfo implements ReadRequest.TemporalInfo { |
| |
| /** |
| * The original temporal information object. |
| */ |
| private final org.apache.ambari.server.controller.spi.TemporalInfo temporalInfo; |
| |
| |
| // ----- Constructors ---------------------------------------------------- |
| |
| private ViewReadRequestTemporalInfo(TemporalInfo temporalInfo) { |
| this.temporalInfo = temporalInfo; |
| } |
| |
| |
| // ----- TemporalInfo ---------------------------------------------------- |
| |
| @Override |
| public Long getStartTime() { |
| return temporalInfo.getStartTime(); |
| } |
| |
| @Override |
| public Long getEndTime() { |
| return temporalInfo.getEndTime(); |
| } |
| |
| @Override |
| public Long getStep() { |
| return temporalInfo.getStep(); |
| } |
| } |
| } |