The import service was ignoring the selected model for imported nodes.
It was also trying to set a different icon for resources that already
exist in the database, creating a validation error.
There was also a nullpointer in relation to not found capability.
Change-Id: Ifa9320c5554bbf5e8fed0cc2e2dea6b05503d213
Issue-ID: SDC-4266
Signed-off-by: André Schmid <andre.schmid@est.tech>
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
message: "An unexpected error occurred while %1."
messageId: "SVC4013"
+ # %1 - The capability name
+ # %2 - The model
+ CAPABILITY_NOT_FOUND:
+ code: 404
+ message: "Capability '%1' was not found for model '%2'."
+ messageId: "SVC4014"
\ No newline at end of file
code: 500
message: "An unexpected error occurred while %1."
messageId: "SVC4013"
+
+
+ # %1 - The capability name
+ # %2 - The model
+ CAPABILITY_NOT_FOUND:
+ code: 404
+ message: "Capability '%1' was not found for model '%2'."
+ messageId: "SVC4014"
\ No newline at end of file
csarUUID, oldResource.getComponentMetadataDefinition().getMetadataDataDefinition().getImportedToscaChecksum(), checksum);
oldResource.getComponentMetadataDefinition().getMetadataDataDefinition().setImportedToscaChecksum(checksum);
}
- return new ServiceCsarInfo(user, csarUUID, csar, service.getName(), toscaYamlCsarStatus.getKey(), toscaYamlCsarStatus.getValue(), true);
+ return new ServiceCsarInfo(user, csarUUID, csar, service.getName(), service.getModel(), toscaYamlCsarStatus.getKey(),
+ toscaYamlCsarStatus.getValue(), true);
}
public ParsedToscaYamlInfo getParsedToscaYamlInfo(String topologyTemplateYaml, String yamlName, Map<String, NodeTypeInfo> nodeTypesInfo,
private static final Logger log = Logger.getLogger(ServiceCsarInfo.class);
private final Map<String, Map<String, Object>> mainTemplateImports;
private List<NodeTypeDefinition> nodeTypeDefinitions;
+ private final String model;
- public ServiceCsarInfo(final User modifier, final String csarUUID, final Map<String, byte[]> csar, final String vfResourceName,
+ public ServiceCsarInfo(final User modifier, final String csarUUID, final Map<String, byte[]> csar,
+ final String vfResourceName, final String model,
final String mainTemplateName, final String mainTemplateContent, final boolean isUpdate) {
super(modifier, csarUUID, csar, vfResourceName, mainTemplateName, mainTemplateContent, isUpdate);
-
+ this.model = model;
final Path mainTemplateDir = Paths.get(getMainTemplateName().substring(0, getMainTemplateName().lastIndexOf('/') + 1));
final Collection<Path> filesHandled = new HashSet<>();
filesHandled.add(Paths.get(mainTemplateName));
if (CollectionUtils.isNotEmpty(importsList)) {
if (importsList.get(0) instanceof String) {
List<Path> importPaths = new ArrayList<>();
- importsList.stream()
- .forEach(importPath -> importPaths.add(fileParentDir == null ? Paths.get((String) importPath)
- : fileParentDir.resolve(Paths.get((String) importPath)).normalize()));
+ importsList.forEach(
+ importPath -> {
+ final Path path = fileParentDir == null ?
+ Paths.get((String) importPath) : fileParentDir.resolve(Paths.get((String) importPath)).normalize();
+ importPaths.add(path);
+ });
return importPaths;
} else if (importsList.get(0) instanceof Map) {
return getTemplateImportFilePathsMultiLineGrammar(importsList, fileParentDir);
private Map<String, Object> getTypes(ToscaTagNamesEnum toscaTag) {
final Map<String, Object> types = new HashMap<>();
- mainTemplateImports.entrySet().stream().forEach(entry -> types.putAll(getTypesFromTemplate(entry.getValue(), toscaTag)));
+ mainTemplateImports.entrySet().forEach(entry -> types.putAll(getTypesFromTemplate(entry.getValue(), toscaTag)));
types.putAll(getTypesFromTemplate(getMappedToscaMainTemplate(), toscaTag));
return types;
}
public Map<String, Object> getArtifactTypes() {
final Map<String, Object> artifactsTypes = new HashMap<>();
- mainTemplateImports.entrySet().stream()
+ mainTemplateImports.entrySet()
.forEach(entry -> artifactsTypes.putAll(getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.ARTIFACT_TYPES)));
artifactsTypes.putAll(getTypesFromTemplate(getMappedToscaMainTemplate(), TypeUtils.ToscaTagNamesEnum.ARTIFACT_TYPES));
return artifactsTypes;
for (final String dependencyName : getDependencyTypes(nodeType, nodeTypes)) {
final NodeTypeDefinition dependency = nodeTypeDefinitionsMap.get(dependencyName);
final int indexOfDependency = sortedNodeTypeDefinitions.lastIndexOf(dependency);
- highestDependencyIndex = indexOfDependency > highestDependencyIndex ? indexOfDependency : highestDependencyIndex;
+ highestDependencyIndex = Math.max(indexOfDependency, highestDependencyIndex);
}
sortedNodeTypeDefinitions.add(highestDependencyIndex + 1, nodeType);
nodeTypeDefinitionsMap.put(nodeType.getMappedNodeType().getKey(), nodeType);
}
private Set<NodeTypeDefinition> getNodeTypeDefinitions(final Set<String> nodeTypesToGet) {
- final Set<NodeTypeDefinition> nodeTypesToReturn = new HashSet<>();
final Set<NodeTypeDefinition> foundNodeTypes = getTypes(nodeTypesToGet);
- nodeTypesToReturn.addAll(foundNodeTypes);
+ final Set<NodeTypeDefinition> nodeTypesToReturn = new HashSet<>(foundNodeTypes);
final Set<String> recursiveNodeTypesToGet = new HashSet<>();
- foundNodeTypes.stream().forEach(nodeTypeDef -> {
+ foundNodeTypes.forEach(nodeTypeDef -> {
Either<Object, ResultStatusEnum> derivedFromTypeEither =
findToscaElement((Map<String, Object>) nodeTypeDef.getMappedNodeType().getValue(), TypeUtils.ToscaTagNamesEnum.DERIVED_FROM,
ToscaElementTypeEnum.STRING);
private Set<NodeTypeDefinition> getTypes(final Set<String> nodeTypes) {
Set<NodeTypeDefinition> nodeTypeDefinitionsLocal = new HashSet<>();
- mainTemplateImports.entrySet().forEach(entry -> {
- final Map<String, Object> types = getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.NODE_TYPES, nodeTypes);
+ mainTemplateImports.values().forEach(template -> {
+ final Map<String, Object> types = getTypesFromTemplate(template, ToscaTagNamesEnum.NODE_TYPES, nodeTypes);
if (MapUtils.isNotEmpty(types)) {
- types.entrySet().stream().forEach(typesEntry -> {
+ types.entrySet().forEach(typesEntry -> {
final NodeTypeMetadata metadata =
- getMetaDataFromTemplate(entry.getValue(), typesEntry.getKey());
+ getMetaDataFromTemplate(template, typesEntry.getKey());
nodeTypeDefinitionsLocal.add(new NodeTypeDefinition(typesEntry, metadata));
});
}
nodeTypeMetadata.setResourceType((String) metadata.get("type"));
nodeTypeMetadata.setVendorName((String) metadata.get("resourceVendor"));
nodeTypeMetadata.setVendorRelease(String.valueOf(metadata.get("resourceVendorRelease")));
- nodeTypeMetadata.setModel((String) metadata.get("model"));
+ nodeTypeMetadata.setModel(model);
nodeTypeMetadata.setNormative(false);
}
private NullNodeTypeMetadata createDefaultMetadata(String nodeTemplateType) {
NullNodeTypeMetadata nodeTypeMetadata = new NullNodeTypeMetadata();
nodeTypeMetadata.setToscaName(nodeTemplateType);
+ nodeTypeMetadata.setModel(model);
return nodeTypeMetadata;
}
}
if (newResource.getContactId() == null) {
newResource.setContactId(oldResource.getContactId());
}
+ newResource.setIcon(oldResource.getIcon());
newResource.setCategories(oldResource.getCategories());
if (newResource.getVendorName() == null) {
newResource.setVendorName(oldResource.getVendorName());
final Map<String, Object> dataTypesToCreate = getDatatypesToCreate(service.getModel(), csarInfo);
if (MapUtils.isNotEmpty(dataTypesToCreate)) {
dataTypeBusinessLogic.createDataTypeFromYaml(new Yaml().dump(dataTypesToCreate), service.getModel(), true);
- dataTypesToCreate.entrySet().stream().forEach(createdOrUpdatedDataType -> {
- applicationDataTypeCache.reload(service.getModel(),
- UniqueIdBuilder.buildDataTypeUid(service.getModel(), createdOrUpdatedDataType.getKey()));
- });
+ dataTypesToCreate.keySet().forEach(key ->
+ applicationDataTypeCache.reload(service.getModel(), UniqueIdBuilder.buildDataTypeUid(service.getModel(), key))
+ );
}
final Map<String, Object> artifactTypesToCreate = getArtifactTypesToCreate(service.getModel(), csarInfo);
NodeTypesMetadataList nodeTypesMetadataList = new NodeTypesMetadataList();
List<NodeTypeMetadata> nodeTypeMetadataList = new ArrayList<>();
final Map<String, Object> allTypesToCreate = new HashMap<>();
- nodeTypesToCreate.stream().forEach(nodeType -> {
+ nodeTypesToCreate.forEach(nodeType -> {
allTypesToCreate.put(nodeType.getMappedNodeType().getKey(), nodeType.getMappedNodeType().getValue());
nodeTypeMetadataList.add(nodeType.getNodeTypeMetadata());
});
if (nodeNamespaceMap.containsKey(uploadComponentInstanceInfo.getType())) {
uploadComponentInstanceInfo.setType(nodeNamespaceMap.get(uploadComponentInstanceInfo.getType()).getToscaResourceName());
}
- Resource refResource = validateResourceInstanceBeforeCreate(yamlName, uploadComponentInstanceInfo, existingnodeTypeMap);
+ Resource refResource =
+ validateResourceInstanceBeforeCreate(yamlName, component.getModel(), uploadComponentInstanceInfo, existingnodeTypeMap);
ComponentInstance componentInstance = new ComponentInstance();
componentInstance.setComponentUid(refResource.getUniqueId());
Collection<String> directives = uploadComponentInstanceInfo.getDirectives();
componentInstance.setName(uploadComponentInstanceInfo.getName());
componentInstance.setIcon(origResource.getIcon());
resourcesInstancesMap.put(componentInstance, origResource);
- } catch (Exception e) {
+ } catch (final ComponentException e) {
+ throw e;
+ } catch (final Exception e) {
throw new ComponentException(ActionStatus.GENERAL_ERROR, e.getMessage());
}
}
- protected Resource validateResourceInstanceBeforeCreate(String yamlName, UploadComponentInstanceInfo uploadComponentInstanceInfo,
+ protected Resource validateResourceInstanceBeforeCreate(String yamlName, String model, UploadComponentInstanceInfo uploadComponentInstanceInfo,
Map<String, Resource> nodeNamespaceMap) {
Resource refResource;
try {
if (nodeNamespaceMap.containsKey(uploadComponentInstanceInfo.getType())) {
refResource = nodeNamespaceMap.get(uploadComponentInstanceInfo.getType());
} else {
- Either<Resource, StorageOperationStatus> findResourceEither = toscaOperationFacade
- .getLatestResourceByToscaResourceName(uploadComponentInstanceInfo.getType());
- if (findResourceEither.isRight()) {
+ final Either<Component, StorageOperationStatus> resourceEither =
+ toscaOperationFacade.getLatestByToscaResourceName(uploadComponentInstanceInfo.getType(), model);
+ if (resourceEither.isRight()) {
ResponseFormat responseFormat = componentsUtils
- .getResponseFormat(componentsUtils.convertFromStorageResponse(findResourceEither.right().value()));
+ .getResponseFormat(componentsUtils.convertFromStorageResponse(resourceEither.right().value()));
throw new ComponentException(responseFormat);
}
- refResource = findResourceEither.left().value();
+ refResource = (Resource) resourceEither.left().value();
nodeNamespaceMap.put(refResource.getToscaResourceName(), refResource);
}
String componentState = refResource.getComponentMetadataDefinition().getMetadataDataDefinition().getState();
throw new ComponentException(responseFormat);
}
return refResource;
- } catch (Exception e) {
+ } catch (final ComponentException e) {
+ throw e;
+ } catch (final Exception e) {
throw new ComponentException(ActionStatus.GENERAL_ERROR, e.getMessage());
}
}
case SCHEMA_VIOLATION:
responseEnum = ActionStatus.CAPABILITY_TYPE_ALREADY_EXIST;
break;
+ case NOT_FOUND:
+ responseEnum = ActionStatus.CAPABILITY_NOT_FOUND;
+ break;
default:
responseEnum = ActionStatus.GENERAL_ERROR;
break;
log.debug(START_HANDLE_REQUEST_OF, url);
log.debug(MODIFIER_ID_IS, userId);
try {
- final Wrapper<Response> responseWrapper = performUIImport(data, request, userId, null);
+ final Wrapper<Response> responseWrapper = performUIImport(data, request, userId);
return responseWrapper.getInnerElement();
} catch (IOException | ZipException e) {
BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Import Service");
}
}
- private Wrapper<Response> performUIImport(String data, final HttpServletRequest request, String userId,
- String serviceUniqueId) throws FileNotFoundException, ZipException {
+ private Wrapper<Response> performUIImport(String data, final HttpServletRequest request,
+ String userId) throws FileNotFoundException, ZipException {
Wrapper<Response> responseWrapper = new Wrapper<>();
Wrapper<User> userWrapper = new Wrapper<>();
Wrapper<UploadServiceInfo> uploadServiceInfoWrapper = new Wrapper<>();
message: "An unexpected error occurred while %1."
messageId: "SVC4013"
+
+ # %1 - The capability name
+ # %2 - The model
+ CAPABILITY_NOT_FOUND:
+ code: 404
+ message: "Capability '%1' was not found for model '%2'."
+ messageId: "SVC4014"
\ No newline at end of file
assertNotNull(mainTemplateService);
final String mainTemplateContent = new String(mainTemplateService);
- return new ServiceCsarInfo(user, csarUuid, csar, vfReousrceName, mainTemplateName, mainTemplateContent, false);
+ return new ServiceCsarInfo(user, csarUuid, csar, vfReousrceName, null, mainTemplateName, mainTemplateContent, false);
} catch (URISyntaxException | ZipException e) {
fail(e);
}
final File csarFile = new File(ServiceCsarInfoTest.class.getClassLoader().getResource(csarFileName).toURI());
final Map<String, byte[]> payload = ZipUtils.readZip(csarFile, false);
String mainTemplateContent = new String(payload.get(mainTemplateName));
-
-return new ServiceCsarInfo(user, CSAR_UUID, payload, SERVICE_NAME, mainTemplateName, mainTemplateContent, true);
+ return new ServiceCsarInfo(user, CSAR_UUID, payload, SERVICE_NAME, null, mainTemplateName, mainTemplateContent, true);
}
@SuppressWarnings("unchecked")
String resourceUniqueId = "extcp_resource";
resource.setUniqueId(resourceUniqueId);
resource.setToscaArtifacts(toscaArtifacts);
+ resource.getComponentMetadataDefinition().getMetadataDataDefinition().setState(LifecycleStateEnum.CERTIFIED.name());
+ resource.setResourceType(ResourceTypeEnum.VF);
+
ImmutablePair<String, byte[]> resourceTemplate = getNodeType();
String updatedNodeType = "org.openecomp.resource.cp.extCP";
+ resource.setToscaResourceName(updatedNodeType);
newService.setComponentInstancesProperties(
Collections.singletonMap(COMPONENT_ID + "." + "zxjTestImportServiceAb", Collections.singletonList(componentInstanceProperty)));
when(serviceImportParseLogic.getNodeTypesFromTemplate(anyMap())).thenReturn(getNodeTypes());
when(serviceImportParseLogic.createNodeTypeResourceFromYaml(anyString(), any(Map.Entry.class), any(User.class), anyMap(), any(Service.class),
anyBoolean(), any(), anyList(), anyBoolean(), any(CsarInfo.class), anyBoolean())).thenReturn(
- new ImmutablePair<>(new Resource(), ActionStatus.OK));
+ new ImmutablePair<>(resource, ActionStatus.OK));
when(serviceImportParseLogic.getComponentWithInstancesFilter()).thenReturn(new ComponentParametersView());
when(toscaOperationFacade.getToscaElement(anyString(), any(ComponentParametersView.class))).thenReturn(Either.left(newService));
when(serviceImportParseLogic.getComponentFilterAfterCreateRelations()).thenReturn(new ComponentParametersView());
.thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
when(toscaOperationFacade.getLatestByToscaResourceName(contains("tosca.nodes."), isNull()))
.thenReturn(Either.right(StorageOperationStatus.NOT_FOUND));
- when(toscaOperationFacade.getLatestByToscaResourceName(contains(updatedNodeType), isNull())).thenReturn(Either.left(resource));
+ when(toscaOperationFacade.getLatestByToscaResourceName(updatedNodeType, null)).thenReturn(Either.left(resource));
when(artifactsBusinessLogic.handleDownloadRequestById(resourceUniqueId, artifactUniqueId, user.getUserId(), ComponentTypeEnum.RESOURCE, null, null))
.thenReturn(resourceTemplate);
when(toscaOperationFacade.updatePropertyOfComponent(eq(oldService), any(PropertyDefinition.class))).thenReturn(Either.left(null));
originResource.setComponentType(ComponentTypeEnum.RESOURCE);
originResource.setToscaResourceName("toscaResourceName");
originResource.setResourceType(ResourceTypeEnum.VF);
- originResource.setResourceType(ResourceTypeEnum.VF);
Map<String, Resource> nodeNamespaceMap = new HashMap<>();
nodeNamespaceMap.put("resources", originResource);
- when(toscaOperationFacade.getLatestResourceByToscaResourceName(anyString())).thenReturn(Either.left(originResource));
+ when(toscaOperationFacade.getLatestByToscaResourceName(RESOURCE_TOSCA_NAME, null)).thenReturn(Either.left(originResource));
Assertions.assertNotNull(
- sIBL.validateResourceInstanceBeforeCreate(yamlName, uploadComponentInstanceInfo, nodeNamespaceMap));
+ sIBL.validateResourceInstanceBeforeCreate(yamlName, null, uploadComponentInstanceInfo, nodeNamespaceMap));
}
@Test
assertNotNull(mainTemplateService);
final String mainTemplateContent = new String(mainTemplateService);
- return new ServiceCsarInfo(user, csarUuid, csar, vfReousrceName, mainTemplateName, mainTemplateContent, false);
+ return new ServiceCsarInfo(user, csarUuid, csar, vfReousrceName, null, mainTemplateName, mainTemplateContent, false);
} catch (URISyntaxException | ZipException e) {
fail(e);
}
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.openecomp.sdc.be.dao.api.ActionStatus;
import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao;
import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
-import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
import org.openecomp.sdc.be.externalapi.servlet.representation.AbstractResourceInfo;
import org.openecomp.sdc.be.externalapi.servlet.representation.AbstractTemplateInfo;
protected static final String SERVICE_CATEGORY = "Mobility";
protected static final String INSTANTIATION_TYPE = "A-la-carte";
- protected static final String CERTIFIED_VERSION = "1.0";
- protected static final String UNCERTIFIED_VERSION = "0.2";
protected static final String COMPONENT_ID = "myUniqueId";
protected static final String GENERIC_SERVICE_NAME = "org.openecomp.resource.abstract.nodes.service";
- protected static final String SERVICE_ROLE = JsonPresentationFields.SERVICE_ROLE.getPresentation();
- protected static final String SERVICE_TYPE = JsonPresentationFields.SERVICE_TYPE.getPresentation();
- protected static final String SERVICE_FUNCTION = JsonPresentationFields.SERVICE_FUNCTION.getPresentation();
private static final String RESOURCE_NAME = "My-Resource_Name with space";
- private static final String RESOURCE_TOSCA_NAME = "My-Resource_Tosca_Name";
+ protected static final String RESOURCE_TOSCA_NAME = "org.openecomp.resource.cp.extCP";
private static final String RESOURCE_CATEGORY1 = "Network Layer 2-3";
private static final String RESOURCE_SUBCATEGORY = "Router";
protected UploadComponentInstanceInfo getUploadComponentInstanceInfo() {
UploadComponentInstanceInfo uploadComponentInstanceInfo = new UploadComponentInstanceInfo();
- uploadComponentInstanceInfo.setType("My-Resource_Tosca_Name");
- Collection<String> directives = new Collection<String>() {
- @Override
- public int size() {
- return 0;
- }
-
- @Override
- public boolean isEmpty() {
- return false;
- }
-
- @Override
- public boolean contains(Object o) {
- return false;
- }
-
- @Override
- public Iterator<String> iterator() {
- return null;
- }
-
- @Override
- public Object[] toArray() {
- return new Object[0];
- }
-
- @Override
- public <T> T[] toArray(T[] ts) {
- return null;
- }
-
- @Override
- public boolean add(String s) {
- return false;
- }
-
- @Override
- public boolean remove(Object o) {
- return false;
- }
-
- @Override
- public boolean containsAll(Collection<?> collection) {
- return false;
- }
-
- @Override
- public boolean addAll(Collection<? extends String> collection) {
- return false;
- }
-
- @Override
- public boolean removeAll(Collection<?> collection) {
- return false;
- }
-
- @Override
- public boolean retainAll(Collection<?> collection) {
- return false;
- }
-
- @Override
- public void clear() {
-
- }
- };
- uploadComponentInstanceInfo.setDirectives(directives);
+ uploadComponentInstanceInfo.setType(RESOURCE_TOSCA_NAME);
+ uploadComponentInstanceInfo.setDirectives(new ArrayList<>());
UploadNodeFilterInfo uploadNodeFilterInfo = new UploadNodeFilterInfo();
Map<String, List<UploadReqInfo>> requirements = new HashMap<>();
List<UploadReqInfo> uploadReqInfoList = new ArrayList<>();
assertNotNull(mainTemplateService);
final String mainTemplateContent = new String(mainTemplateService);
- return new ServiceCsarInfo(user, csarUuid, csar, vfReousrceName, mainTemplateName, mainTemplateContent, false);
+ return new ServiceCsarInfo(user, csarUuid, csar, vfReousrceName, null, mainTemplateName, mainTemplateContent, false);
} catch (URISyntaxException | ZipException e) {
fail(e);
}
message: "An unexpected error occurred while %1."
messageId: "SVC4013"
+
+
+ # %1 - The capability name
+ # %2 - The model
+ CAPABILITY_NOT_FOUND:
+ code: 404
+ message: "Capability '%1' was not found for model '%2'."
+ messageId: "SVC4014"
\ No newline at end of file
import org.openecomp.sdc.be.model.category.CategoryDefinition;
import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
-public class DefaultUploadResourceInfo extends UploadResourceInfo{
+public class DefaultUploadResourceInfo extends UploadResourceInfo {
public DefaultUploadResourceInfo(String toscaName){
SubCategoryDefinition subCategory = new SubCategoryDefinition();
if (validationRes.isRight()) {
log.error("#addCapabilityType - One or all properties of capability type {} not valid. status is {}", capabilityTypeDefinition,
validationRes.right().value());
- return result;
+ return validationRes;
}
Either<CapabilityTypeData, StorageOperationStatus> eitherStatus = addCapabilityTypeToGraph(capabilityTypeDefinition);
result = eitherStatus.left().map(CapabilityTypeData::getUniqueId).left().bind(uniqueId -> getCapabilityType(uniqueId, inTransaction));
message: "Error: Internal Server Error. Please try again later.",
messageId: "POL5000"
}
+
+ # %1 - The capability name
+ # %2 - The model
+ CAPABILITY_NOT_FOUND:
+ code: 404
+ message: "Capability '%1' was not found for model '%2'."
+ messageId: "SVC4014"
\ No newline at end of file