/**
* 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.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.ObjectNotFoundException;
import org.apache.ambari.server.api.resources.OperatingSystemResourceDefinition;
import org.apache.ambari.server.api.resources.RepositoryResourceDefinition;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
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.Resource.Type;
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.ClusterVersionDAO;
import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
import org.apache.ambari.server.orm.dao.StackDAO;
import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
import org.apache.ambari.server.orm.entities.RepositoryEntity;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.orm.entities.StackEntity;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.security.authorization.AuthorizationHelper;
import org.apache.ambari.server.security.authorization.ResourceType;
import org.apache.ambari.server.security.authorization.RoleAuthorization;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.OperatingSystemInfo;
import org.apache.ambari.server.state.RepositoryVersionState;
import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.repository.ManifestServiceInfo;
import org.apache.ambari.server.state.repository.VersionDefinitionXml;
import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.persist.Transactional;
/**
* Resource provider for repository versions resources.
*/
public class RepositoryVersionResourceProvider extends AbstractAuthorizedResourceProvider {
// ----- Property ID constants ---------------------------------------------
public static final String REPOSITORY_VERSION = "RepositoryVersions";
public static final String REPOSITORY_VERSION_ID_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "id");
public static final String REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "stack_name");
public static final String REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "stack_version");
public static final String REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "repository_version");
public static final String REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("RepositoryVersions", "display_name");
public static final String SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID = new OperatingSystemResourceDefinition().getPluralName();
public static final String SUBRESOURCE_REPOSITORIES_PROPERTY_ID = new RepositoryResourceDefinition().getPluralName();
public static final String REPOSITORY_VERSION_TYPE_PROPERTY_ID = "RepositoryVersions/type";
public static final String REPOSITORY_VERSION_RELEASE_VERSION = "RepositoryVersions/release/version";
public static final String REPOSITORY_VERSION_RELEASE_BUILD = "RepositoryVersions/release/build";
public static final String REPOSITORY_VERSION_RELEASE_NOTES = "RepositoryVersions/release/notes";
public static final String REPOSITORY_VERSION_RELEASE_COMPATIBLE_WITH = "RepositoryVersions/release/compatible_with";
public static final String REPOSITORY_VERSION_AVAILABLE_SERVICES = "RepositoryVersions/services";
public static final String REPOSITORY_VERSION_STACK_SERVICES = "RepositoryVersions/stack_services";
public static final String REPOSITORY_VERSION_PARENT_ID = "RepositoryVersions/parent_id";
public static final String REPOSITORY_VERSION_HAS_CHILDREN = "RepositoryVersions/has_children";
@SuppressWarnings("serial")
private static Set<String> pkPropertyIds = new HashSet<String>() {
{
add(REPOSITORY_VERSION_ID_PROPERTY_ID);
}
};
@SuppressWarnings("serial")
public static Set<String> propertyIds = Sets.newHashSet(
REPOSITORY_VERSION_ID_PROPERTY_ID,
REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID,
REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID,
REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID,
REPOSITORY_VERSION_TYPE_PROPERTY_ID,
REPOSITORY_VERSION_RELEASE_BUILD,
REPOSITORY_VERSION_RELEASE_COMPATIBLE_WITH,
REPOSITORY_VERSION_RELEASE_NOTES,
REPOSITORY_VERSION_RELEASE_VERSION,
REPOSITORY_VERSION_PARENT_ID,
REPOSITORY_VERSION_HAS_CHILDREN,
REPOSITORY_VERSION_AVAILABLE_SERVICES,
REPOSITORY_VERSION_STACK_SERVICES);
@SuppressWarnings("serial")
public static Map<Type, String> keyPropertyIds = new HashMap<Type, String>() {
{
put(Type.Stack, REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID);
put(Type.StackVersion, REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID);
put(Type.RepositoryVersion, REPOSITORY_VERSION_ID_PROPERTY_ID);
}
};
@Inject
private Gson gson;
@Inject
private RepositoryVersionDAO repositoryVersionDAO;
@Inject
private ClusterVersionDAO clusterVersionDAO;
@Inject
private AmbariMetaInfo ambariMetaInfo;
@Inject
private RepositoryVersionHelper repositoryVersionHelper;
@Inject
private Provider<Clusters> clusters;
/**
* Data access object used for lookup up stacks.
*/
@Inject
private StackDAO stackDAO;
/**
* Create a new resource provider.
*
*/
public RepositoryVersionResourceProvider() {
super(propertyIds, keyPropertyIds);
setRequiredCreateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS));
setRequiredDeleteAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS));
setRequiredUpdateAuthorizations(EnumSet.of(RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS, RoleAuthorization.AMBARI_EDIT_STACK_REPOS));
setRequiredGetAuthorizations(EnumSet.of(
RoleAuthorization.AMBARI_MANAGE_STACK_VERSIONS,
RoleAuthorization.AMBARI_EDIT_STACK_REPOS,
RoleAuthorization.CLUSTER_VIEW_STACK_DETAILS,
RoleAuthorization.CLUSTER_UPGRADE_DOWNGRADE_STACK));
}
@Override
protected RequestStatus createResourcesAuthorized(final Request request)
throws SystemException,
UnsupportedPropertyException,
ResourceAlreadyExistsException,
NoSuchParentResourceException {
for (final Map<String, Object> properties : request.getProperties()) {
createResources(new Command<Void>() {
@Override
public Void invoke() throws AmbariException {
final String[] requiredProperties = {
REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID,
SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID,
REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID,
REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID,
REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID
};
for (String propertyName : requiredProperties) {
if (properties.get(propertyName) == null) {
throw new AmbariException("Property " + propertyName + " should be provided");
}
}
RepositoryVersionEntity entity = toRepositoryVersionEntity(properties);
if (repositoryVersionDAO.findByDisplayName(entity.getDisplayName()) != null) {
throw new AmbariException("Repository version with name " + entity.getDisplayName() + " already exists");
}
if (repositoryVersionDAO.findByStackAndVersion(entity.getStack(), entity.getVersion()) != null) {
throw new AmbariException("Repository version for stack " + entity.getStack() + " and version " + entity.getVersion() + " already exists");
}
validateRepositoryVersion(repositoryVersionDAO, ambariMetaInfo, entity);
repositoryVersionDAO.create(entity);
notifyCreate(Resource.Type.RepositoryVersion, request);
return null;
}
});
}
return getRequestStatus(null);
}
@Override
protected Set<Resource> getResourcesAuthorized(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
final Set<Resource> resources = new HashSet<>();
final Set<String> requestedIds = getRequestPropertyIds(request, predicate);
final Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
List<RepositoryVersionEntity> requestedEntities = new ArrayList<>();
for (Map<String, Object> propertyMap: propertyMaps) {
final StackId stackId = getStackInformationFromUrl(propertyMap);
if (stackId != null && propertyMaps.size() == 1 && propertyMap.get(REPOSITORY_VERSION_ID_PROPERTY_ID) == null) {
requestedEntities.addAll(repositoryVersionDAO.findByStack(stackId));
} else {
final Long id;
try {
id = Long.parseLong(propertyMap.get(REPOSITORY_VERSION_ID_PROPERTY_ID).toString());
} catch (Exception ex) {
throw new SystemException("Repository version should have numerical id");
}
final RepositoryVersionEntity entity = repositoryVersionDAO.findByPK(id);
if (entity == null) {
throw new NoSuchResourceException("There is no repository version with id " + id);
} else {
requestedEntities.add(entity);
}
}
}
for (RepositoryVersionEntity entity: requestedEntities) {
final Resource resource = new ResourceImpl(Resource.Type.RepositoryVersion);
setResourceProperty(resource, REPOSITORY_VERSION_ID_PROPERTY_ID, entity.getId(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID, entity.getStackName(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID, entity.getStackVersion(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID, entity.getDisplayName(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID, entity.getVersion(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_TYPE_PROPERTY_ID, entity.getType(), requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_PARENT_ID, entity.getParentId(), requestedIds);
List<RepositoryVersionEntity> children = entity.getChildren();
setResourceProperty(resource, REPOSITORY_VERSION_HAS_CHILDREN,
null != children && !children.isEmpty(), requestedIds);
final VersionDefinitionXml xml;
try {
xml = entity.getRepositoryXml();
} catch (Exception e) {
throw new SystemException(String.format("Could not load xml for Repository %s", entity.getId()), e);
}
final StackInfo stack;
try {
stack = ambariMetaInfo.getStack(entity.getStackName(), entity.getStackVersion());
} catch (AmbariException e) {
throw new SystemException(String.format("Could not load stack %s for Repository %s",
entity.getStackId().toString(), entity.getId()));
}
final List<ManifestServiceInfo> stackServices;
if (null != xml) {
setResourceProperty(resource, REPOSITORY_VERSION_RELEASE_VERSION, xml.release.version, requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_RELEASE_BUILD, xml.release.build, requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_RELEASE_COMPATIBLE_WITH, xml.release.compatibleWith, requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_RELEASE_NOTES, xml.release.releaseNotes, requestedIds);
setResourceProperty(resource, REPOSITORY_VERSION_AVAILABLE_SERVICES, xml.getAvailableServices(stack), requestedIds);
stackServices = xml.getStackServices(stack);
} else {
stackServices = new ArrayList<>();
for (ServiceInfo si : stack.getServices()) {
stackServices.add(new ManifestServiceInfo(si.getName(), si.getDisplayName(), si.getComment(),
Collections.singleton(si.getVersion())));
}
}
setResourceProperty(resource, REPOSITORY_VERSION_STACK_SERVICES, stackServices, requestedIds);
resources.add(resource);
}
return resources;
}
@Override
@Transactional
protected RequestStatus updateResourcesAuthorized(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
final Set<Map<String, Object>> propertyMaps = request.getProperties();
modifyResources(new Command<Void>() {
@Override
public Void invoke() throws AmbariException, AuthorizationException {
for (Map<String, Object> propertyMap : propertyMaps) {
final Long id;
try {
id = Long.parseLong(propertyMap.get(REPOSITORY_VERSION_ID_PROPERTY_ID).toString());
} catch (Exception ex) {
throw new AmbariException("Repository version should have numerical id");
}
final RepositoryVersionEntity entity = repositoryVersionDAO.findByPK(id);
if (entity == null) {
throw new ObjectNotFoundException("There is no repository version with id " + id);
}
List<OperatingSystemEntity> operatingSystemEntities = null;
if (StringUtils.isNotBlank(ObjectUtils.toString(propertyMap.get(SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID)))) {
if (!AuthorizationHelper.isAuthorized(ResourceType.AMBARI, null, RoleAuthorization.AMBARI_EDIT_STACK_REPOS)) {
throw new AuthorizationException("The authenticated user does not have authorization to modify stack repositories");
}
final Object operatingSystems = propertyMap.get(SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID);
final String operatingSystemsJson = gson.toJson(operatingSystems);
try {
operatingSystemEntities = repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
} catch (Exception ex) {
throw new AmbariException("Json structure for operating systems is incorrect", ex);
}
entity.setOperatingSystems(operatingSystemsJson);
}
if (StringUtils.isNotBlank(ObjectUtils.toString(propertyMap.get(REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID)))) {
entity.setDisplayName(propertyMap.get(REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID).toString());
}
validateRepositoryVersion(repositoryVersionDAO, ambariMetaInfo, entity);
repositoryVersionDAO.merge(entity);
//
// Update metaInfo table as well
//
if (operatingSystemEntities != null) {
String entityStackName = entity.getStackName();
String entityStackVersion = entity.getStackVersion();
for (OperatingSystemEntity osEntity : operatingSystemEntities) {
List<RepositoryEntity> repositories = osEntity.getRepositories();
for (RepositoryEntity repository : repositories) {
ambariMetaInfo.updateRepo(entityStackName, entityStackVersion, osEntity.getOsType(), repository.getRepositoryId(), repository.getBaseUrl(), repository.getMirrorsList());
}
}
}
}
return null;
}
});
return getRequestStatus(null);
}
@Override
protected RequestStatus deleteResourcesAuthorized(Request request, Predicate predicate)
throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
final Set<Map<String, Object>> propertyMaps = getPropertyMaps(predicate);
final List<RepositoryVersionEntity> entitiesToBeRemoved = new ArrayList<>();
for (Map<String, Object> propertyMap : propertyMaps) {
final Long id;
try {
id = Long.parseLong(propertyMap.get(REPOSITORY_VERSION_ID_PROPERTY_ID).toString());
} catch (Exception ex) {
throw new SystemException("Repository version should have numerical id");
}
final RepositoryVersionEntity entity = repositoryVersionDAO.findByPK(id);
if (entity == null) {
throw new NoSuchResourceException("There is no repository version with id " + id);
}
StackEntity stackEntity = entity.getStack();
String stackName = stackEntity.getStackName();
String stackVersion = stackEntity.getStackVersion();
final List<ClusterVersionEntity> clusterVersionEntities = clusterVersionDAO.findByStackAndVersion(
stackName, stackVersion, entity.getVersion());
final List<RepositoryVersionState> forbiddenToDeleteStates = Lists.newArrayList(
RepositoryVersionState.CURRENT,
RepositoryVersionState.INSTALLED,
RepositoryVersionState.INSTALLING);
for (ClusterVersionEntity clusterVersionEntity : clusterVersionEntities) {
if (clusterVersionEntity.getRepositoryVersion().getId().equals(id) && forbiddenToDeleteStates.contains(clusterVersionEntity.getState())) {
throw new SystemException("Repository version can't be deleted as it is " +
clusterVersionEntity.getState().name() + " on cluster " + clusterVersionEntity.getClusterEntity().getClusterName());
}
}
entitiesToBeRemoved.add(entity);
}
for (RepositoryVersionEntity entity: entitiesToBeRemoved) {
repositoryVersionDAO.remove(entity);
}
return getRequestStatus(null);
}
@Override
protected Set<String> getPKPropertyIds() {
return pkPropertyIds;
}
/**
* Validates newly created repository versions to contain actual information.
*
* @throws AmbariException exception with error message
*/
protected static void validateRepositoryVersion(RepositoryVersionDAO dao,
AmbariMetaInfo metaInfo, RepositoryVersionEntity repositoryVersion) throws AmbariException {
validateRepositoryVersion(dao, metaInfo, repositoryVersion, false);
}
/**
* Validates newly created repository versions to contain actual information. Optionally
* skip url duplication.
*
* @throws AmbariException exception with error message
*/
protected static void validateRepositoryVersion(RepositoryVersionDAO dao,
AmbariMetaInfo metaInfo, RepositoryVersionEntity repositoryVersion, boolean skipUrlCheck) throws AmbariException {
final StackId requiredStack = new StackId(repositoryVersion.getStack());
final String requiredStackName = requiredStack.getStackName();
final String requiredStackVersion = requiredStack.getStackVersion();
final String requiredStackId = requiredStack.getStackId();
// List of all repo urls that are already added at stack
Set<String> existingRepoUrls = new HashSet<>();
List<RepositoryVersionEntity> existingRepoVersions = dao.findByStack(requiredStack);
for (RepositoryVersionEntity existingRepoVersion : existingRepoVersions) {
for (OperatingSystemEntity operatingSystemEntity : existingRepoVersion.getOperatingSystems()) {
for (RepositoryEntity repositoryEntity : operatingSystemEntity.getRepositories()) {
if (repositoryEntity.isUnique() && !existingRepoVersion.getId().equals(repositoryVersion.getId())) { // Allow modifying already defined repo version
existingRepoUrls.add(repositoryEntity.getBaseUrl());
}
}
}
}
// check that repositories contain only supported operating systems
final Set<String> osSupported = new HashSet<>();
for (OperatingSystemInfo osInfo: metaInfo.getOperatingSystems(requiredStackName, requiredStackVersion)) {
osSupported.add(osInfo.getOsType());
}
final Set<String> osRepositoryVersion = new HashSet<>();
for (OperatingSystemEntity os: repositoryVersion.getOperatingSystems()) {
osRepositoryVersion.add(os.getOsType());
for (RepositoryEntity repositoryEntity : os.getRepositories()) {
String baseUrl = repositoryEntity.getBaseUrl();
if (!skipUrlCheck && os.isAmbariManagedRepos() && existingRepoUrls.contains(baseUrl)) {
throw new AmbariException("Base url " + baseUrl + " is already defined for another repository version. " +
"Setting up base urls that contain the same versions of components will cause stack upgrade to fail.");
}
}
}
if (osRepositoryVersion.isEmpty()) {
throw new AmbariException("At least one set of repositories for OS should be provided");
}
for (String os: osRepositoryVersion) {
if (!osSupported.contains(os)) {
throw new AmbariException("Operating system type " + os + " is not supported by stack " + requiredStackId);
}
}
if (!RepositoryVersionEntity.isVersionInStack(repositoryVersion.getStackId(), repositoryVersion.getVersion())) {
throw new AmbariException(MessageFormat.format("Version {0} needs to belong to stack {1}",
repositoryVersion.getVersion(), repositoryVersion.getStackName() + "-" + repositoryVersion.getStackVersion()));
}
}
/**
* Transforms map of json properties to repository version entity.
*
* @param properties json map
* @return constructed entity
* @throws AmbariException if some properties are missing or json has incorrect structure
*/
protected RepositoryVersionEntity toRepositoryVersionEntity(Map<String, Object> properties) throws AmbariException {
final RepositoryVersionEntity entity = new RepositoryVersionEntity();
final String stackName = properties.get(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).toString();
final String stackVersion = properties.get(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).toString();
StackEntity stackEntity = stackDAO.find(stackName, stackVersion);
entity.setDisplayName(properties.get(REPOSITORY_VERSION_DISPLAY_NAME_PROPERTY_ID).toString());
entity.setStack(stackEntity);
entity.setVersion(properties.get(REPOSITORY_VERSION_REPOSITORY_VERSION_PROPERTY_ID).toString());
final Object operatingSystems = properties.get(SUBRESOURCE_OPERATING_SYSTEMS_PROPERTY_ID);
final String operatingSystemsJson = gson.toJson(operatingSystems);
try {
repositoryVersionHelper.parseOperatingSystems(operatingSystemsJson);
} catch (Exception ex) {
throw new AmbariException("Json structure for operating systems is incorrect", ex);
}
entity.setOperatingSystems(operatingSystemsJson);
return entity;
}
protected StackId getStackInformationFromUrl(Map<String, Object> propertyMap) {
if (propertyMap.containsKey(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID) && propertyMap.containsKey(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID)) {
return new StackId(propertyMap.get(REPOSITORY_VERSION_STACK_NAME_PROPERTY_ID).toString(), propertyMap.get(REPOSITORY_VERSION_STACK_VERSION_PROPERTY_ID).toString());
}
return null;
}
@Override
protected ResourceType getResourceType(Request request, Predicate predicate) {
// This information is not associated with any particular resource
return null;
}
}