final List<ConditionProperties> conditionProperties =
conditions.getConditions().stream().collect(Collectors.toList());
final CmHandles cmHandles = new CmHandles();
- final Collection<String> cmHandleIdentifiers = processConditions(conditionProperties);
- cmHandleIdentifiers.forEach(cmHandle -> cmHandles.setCmHandles(toCmHandleProperties(cmHandle)));
+ cmHandles.setCmHandles(toCmHandleProperties(processConditions(conditionProperties)));
return ResponseEntity.ok(cmHandles);
}
return moduleNames;
}
- private CmHandleProperties toCmHandleProperties(final String cmHandleId) {
+ private CmHandleProperties toCmHandleProperties(final Collection<String> cmHandleIdentifiers) {
final CmHandleProperties cmHandleProperties = new CmHandleProperties();
- final CmHandleProperty cmHandleProperty = new CmHandleProperty();
- cmHandleProperty.setCmHandleId(cmHandleId);
- cmHandleProperties.add(cmHandleProperty);
+ for (final String cmHandleIdentifier : cmHandleIdentifiers) {
+ final CmHandleProperty cmHandleProperty = new CmHandleProperty();
+ cmHandleProperty.setCmHandleId(cmHandleIdentifier);
+ cmHandleProperties.add(cmHandleProperty);
+ }
return cmHandleProperties;
}
given: 'an endpoint and json data'
def searchesEndpoint = "$ncmpBasePathV1/ch/searches"
String jsonData = TestUtils.getResourceFileContent('cmhandle-search.json')
- and: 'the service method is invoked with module names and returns a cm handle id'
- mockNetworkCmProxyDataService.executeCmHandleHasAllModulesSearch(['module1', 'module2']) >> ['some-cmhandle-id']
+ and: 'the service method is invoked with module names and returns two cm handle ids'
+ mockNetworkCmProxyDataService.executeCmHandleHasAllModulesSearch(['module1', 'module2']) >> ['some-cmhandle-id1', 'some-cmhandle-id2']
when: 'the searches api is invoked'
def response = mvc.perform(post(searchesEndpoint)
.contentType(MediaType.APPLICATION_JSON)
then: 'response status returns OK'
response.status == HttpStatus.OK.value()
and: 'the expected response content is returned'
- response.contentAsString == '{"cmHandles":[{"cmHandleId":"some-cmhandle-id"}]}'
+ response.contentAsString == '{"cmHandles":[{"cmHandleId":"some-cmhandle-id1"},{"cmHandleId":"some-cmhandle-id2"}]}'
}
def 'Call execute cm handle searches with unrecognized condition name.'() {
.contentType(MediaType.APPLICATION_JSON)
.content(jsonData)).andReturn().response
then: 'an empty cm handle identifier is returned'
- response.contentAsString == '{"cmHandles":null}'
+ response.contentAsString == '{"cmHandles":[]}'
}
def 'Update resource data from passthrough running.' () {
import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.entities.AnchorEntity;
import org.onap.cps.spi.entities.DataspaceEntity;
+import org.onap.cps.spi.entities.YangResourceModuleReference;
import org.onap.cps.spi.exceptions.AlreadyDefinedException;
import org.onap.cps.spi.exceptions.ModuleNamesNotFoundException;
import org.onap.cps.spi.model.Anchor;
@Override
public Collection<Anchor> queryAnchors(final String dataspaceName, final Collection<String> inputModuleNames) {
validateDataspaceAndModuleNames(dataspaceName, inputModuleNames);
- final Collection<AnchorEntity> anchorEntities =
- anchorRepository.getAnchorsByDataspaceNameAndModuleNames(dataspaceName, inputModuleNames);
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final Collection<AnchorEntity> anchorEntities = anchorRepository
+ .getAnchorsByDataspaceIdAndModuleNames(dataspaceEntity.getId(), inputModuleNames, inputModuleNames.size());
return anchorEntities.stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet());
}
final Collection<String> inputModuleNames) {
final Collection<String> retrievedModuleNames =
yangResourceRepository.findAllModuleReferences(dataspaceName, inputModuleNames)
- .stream().map(module -> module.getModuleName())
+ .stream().map(YangResourceModuleReference::getModuleName)
.collect(Collectors.toList());
if (retrievedModuleNames.isEmpty()) {
dataspaceRepository.getByName(dataspaceName);
private static final Gson GSON = new GsonBuilder().create();
private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?]){0,1})";
- private static final String REG_EX_FOR_LIST_ELEMENT_KEY_PREDICATE = "\\[(\\@([^/]*?)){0,99}( and)*\\]$";
+ private static final Pattern REG_EX_PATTERN_FOR_LIST_ELEMENT_KEY_PREDICATE =
+ Pattern.compile("\\[(\\@([^\\/]{0,9999}))\\]$");
@Override
public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentXpath,
final String parentNodeXpath = targetXpath.substring(0, targetXpath.lastIndexOf('/'));
final FragmentEntity parentFragmentEntity = getFragmentByXpath(dataspaceName, anchorName, parentNodeXpath);
final String lastXpathElement = targetXpath.substring(targetXpath.lastIndexOf('/'));
- final boolean isListElement = Pattern.compile(REG_EX_FOR_LIST_ELEMENT_KEY_PREDICATE)
- .matcher(lastXpathElement).find();
+ final boolean isListElement = REG_EX_PATTERN_FOR_LIST_ELEMENT_KEY_PREDICATE.matcher(lastXpathElement).find();
boolean targetExist;
if (isListElement) {
targetExist = deleteDataNode(parentFragmentEntity, targetXpath);
Collection<AnchorEntity> findAllBySchemaSet(@NotNull SchemaSetEntity schemaSetEntity);
- @Query(value = "SELECT DISTINCT\n"
- + "anchor.*\n"
- + "FROM\n"
- + "yang_resource\n"
- + "JOIN schema_set_yang_resources ON "
- + "schema_set_yang_resources.yang_resource_id = yang_resource.id\n"
+ @Query(value = "SELECT anchor.* FROM yang_resource\n"
+ + "JOIN schema_set_yang_resources ON schema_set_yang_resources.yang_resource_id = yang_resource.id\n"
+ "JOIN schema_set ON schema_set.id = schema_set_yang_resources.schema_set_id\n"
+ "JOIN anchor ON anchor.schema_set_id = schema_set.id\n"
- + "JOIN dataspace ON dataspace.id = anchor.dataspace_id AND dataspace.name = :dataspaceName\n"
- + "WHERE yang_resource.module_Name IN (:moduleNames)", nativeQuery = true)
- Collection<AnchorEntity> getAnchorsByDataspaceNameAndModuleNames(@Param("dataspaceName") String dataspaceName,
- @Param("moduleNames") Collection<String> moduleNames);
+ + "WHERE schema_set.dataspace_id = :dataspaceId AND module_name IN (:moduleNames)\n"
+ + "GROUP BY anchor.id, anchor.name, anchor.dataspace_id, anchor.schema_set_id\n"
+ + "HAVING COUNT(DISTINCT module_name) = :sizeOfModuleNames", nativeQuery = true)
+ Collection<AnchorEntity> getAnchorsByDataspaceIdAndModuleNames(@Param("dataspaceId") int dataspaceId,
+ @Param("moduleNames") Collection<String> moduleNames, @Param("sizeOfModuleNames") int sizeOfModuleNames);
}
\ No newline at end of file
@Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES])
def 'Query anchors that have #scenario.'() {
when: 'all anchor are retrieved for the given dataspace name and module names'
- def anchors = objectUnderTest.queryAnchors('DATASPACE-001', inputModuleNames)
+ def anchors = objectUnderTest.queryAnchors('dataspace-1', inputModuleNames)
then: 'the expected anchors are returned'
anchors.size() == expectedAnchors.size()
anchors.containsAll(expectedAnchors)
where: 'the following data is used'
- scenario | inputModuleNames || expectedAnchors
- 'one module' | ['MODULE-NAME-001'] || [buildAnchor('ANCHOR1', 'DATASPACE-001', 'SCHEMA-SET-001')]
- 'two modules' | ['MODULE-NAME-001', 'MODULE-NAME-002'] || [buildAnchor('ANCHOR1', 'DATASPACE-001', 'SCHEMA-SET-001'), buildAnchor('ANCHOR2', 'DATASPACE-001', 'SCHEMA-SET-002'), buildAnchor('ANCHOR3', 'DATASPACE-001', 'SCHEMA-SET-004')]
- 'a module attached to multiple anchors' | ['MODULE-NAME-003'] || [buildAnchor('ANCHOR1', 'DATASPACE-001', 'SCHEMA-SET-001'), buildAnchor('ANCHOR2', 'DATASPACE-001', 'SCHEMA-SET-002')]
- 'same module with different revisions' | ['MODULE-NAME-002'] || [buildAnchor('ANCHOR2', 'DATASPACE-001', 'SCHEMA-SET-002'), buildAnchor('ANCHOR3', 'DATASPACE-001', 'SCHEMA-SET-004')]
+ scenario | inputModuleNames || expectedAnchors
+ 'one module' | ['module-name-1'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')]
+ 'two modules' | ['module-name-1', 'module-name-2'] || [buildAnchor('anchor-2', 'dataspace-1', 'schema-set-2'), buildAnchor('anchor-1', 'dataspace-1', 'schema-set-1')]
+ 'no anchors for all three modules' | ['module-name-1', 'module-name-2', 'module-name-3'] || []
}
@Sql([CLEAR_DATA, SAMPLE_DATA_FOR_ANCHORS_WITH_MODULES])
def thrownException = thrown(expectedException)
thrownException.details.contains(expectedMessageDetails)
where: 'the following data is used'
- scenario | dataspaceName | moduleNames || expectedException | expectedMessageDetails
- 'existing module in an unknown dataspace' | 'db-does-not-exist' | ['does-not-matter'] || DataspaceNotFoundException | 'db-does-not-exist'
- 'unknown module in an existing dataspace' | 'DATASPACE-001' | ['module-does-not-exist'] || ModuleNamesNotFoundException | 'module-does-not-exist'
- 'unknown module and known module in an existing dataspace' | 'DATASPACE-001' | ['MODULE-NAME-001', 'module-does-not-exist'] || ModuleNamesNotFoundException | 'module-does-not-exist'
+ scenario | dataspaceName | moduleNames || expectedException | expectedMessageDetails | messageDoesNotContain
+ 'unknown dataspace' | 'db-does-not-exist' | ['does-not-matter'] || DataspaceNotFoundException | 'db-does-not-exist' | 'does-not-matter'
+ 'unknown module and known module' | 'dataspace-1' | ['module-name-1', 'module-does-not-exist'] || ModuleNamesNotFoundException | 'module-does-not-exist' | 'module-name-1'
}
def buildAnchor(def anchorName, def dataspaceName, def SchemaSetName) {
*/
INSERT INTO DATASPACE (ID, NAME) VALUES
- (1001, 'DATASPACE-001'), (1002, 'DATASPACE-002');
+ (1001, 'dataspace-1'), (1002, 'dataspace-2');
INSERT INTO SCHEMA_SET (ID, NAME, DATASPACE_ID) VALUES
- (2001, 'SCHEMA-SET-001', 1001),
- (2002, 'SCHEMA-SET-002', 1002),
- (2003, 'SCHEMA-SET-003', 1001),
- (2004, 'SCHEMA-SET-004', 1001);
+ (2001, 'schema-set-1', 1001),
+ (2002, 'schema-set-2', 1001),
+ (2003, 'schema-set-3', 1001),
+ (2004, 'schema-set-4', 1002);
INSERT INTO YANG_RESOURCE (ID, NAME, CONTENT, CHECKSUM, MODULE_NAME, REVISION) VALUES
- (3001, 'module1@2020-02-02.yang', 'CONTENT-001', 'checksum1','MODULE-NAME-001',null),
- (3002, 'module2@2020-02-02.yang', 'CONTENT-002', 'checksum2','MODULE-NAME-002','REVISION-002'),
- (3003, 'module3@2020-02-02.yang', 'CONTENT-003', 'checksum3','MODULE-NAME-003','REVISION-003'),
- (3004, 'module4@2020-02-02.yang', 'CONTENT-004', 'checksum4','MODULE-NAME-004','REVISION-004'),
- (3005, 'module5@2020-03-02.yang', 'CONTENT-005', 'checksum5','MODULE-NAME-002','REVISION-003');
+ (3001, 'module1@revA.yang', 'some-content', 'checksum1','module-name-1','revA'),
+ (3002, 'module2@revA.yang', 'some-content', 'checksum2','module-name-2','revA'),
+ (3003, 'module2@revB.yang', 'some-content', 'checksum3','module-name-2','revB'),
+ (3004, 'module3@revA.yang', 'some-content', 'checksum4','module-name-3','revA');
INSERT INTO SCHEMA_SET_YANG_RESOURCES (SCHEMA_SET_ID, YANG_RESOURCE_ID) VALUES
- (2001, 3001), (2002, 3002),
- (2001, 3003), (2002, 3003),
- (2003, 3004), (2004, 3005);
+ (2001, 3001), --schema-set-1(anchor-1) has modules module1@revA, module2@revA
+ (2001, 3002),
+ (2002, 3001), --schema-set-2(anchor-2) has modules module1@revA, module2@revB
+ (2002, 3003),
+ (2003, 3002), --schema-set-3(anchor-3) has modules module2@revA, module2@revB
+ (2003, 3003),
+ (2004, 3001); --schema-set-4(anchor-4) has module module1@revA but in other dataspace
INSERT INTO ANCHOR (ID, NAME, DATASPACE_ID, SCHEMA_SET_ID) VALUES
- (6001, 'ANCHOR1', 1001, 2001),
- (6002, 'ANCHOR2', 1001, 2002),
- (6003, 'ANCHOR3', 1001, 2004);
+ (6001, 'anchor-1', 1001, 2001),
+ (6002, 'anchor-2', 1001, 2002),
+ (6003, 'anchor-3', 1001, 2003),
+ (6005, 'anchor-4', 1002, 2004);
@Override
public Collection<String> queryAnchorNames(final String dataspaceName, final Collection<String> moduleNames) {
final Collection<Anchor> anchors = cpsAdminPersistenceService.queryAnchors(dataspaceName, moduleNames);
- return anchors.stream().map(anchor -> anchor.getName()).collect(Collectors.toList());
+ return anchors.stream().map(Anchor::getName).collect(Collectors.toList());
}
}
public class DataNodeNotFoundException extends DataValidationException {
private static final long serialVersionUID = 7786740001662205407L;
-
+ private static final String DATANODE_NOT_FOUND = "DataNode not found";
/**
* Constructor.
*
* @param xpath datanode xpath
* @param additionalInformation additional information
*/
+
public DataNodeNotFoundException(final String dataspaceName, final String anchorName, final String xpath,
final String additionalInformation) {
- super("DataNode not found", String
+ super(DATANODE_NOT_FOUND, String
.format("DataNode with xpath %s was not found for anchor %s and dataspace %s, %s.", xpath,
anchorName, dataspaceName, additionalInformation));
}
* @param xpath datanode xpath
*/
public DataNodeNotFoundException(final String dataspaceName, final String anchorName, final String xpath) {
- super("DataNode not found", String
+ super(DATANODE_NOT_FOUND, String
.format("DataNode with xpath %s was not found for anchor %s and dataspace %s.", xpath,
anchorName, dataspaceName));
}
* @param anchorName the anchor name
*/
public DataNodeNotFoundException(final String dataspaceName, final String anchorName) {
- super("DataNode not found", String.format(
+ super(DATANODE_NOT_FOUND, String.format(
"DataNode not found for anchor %s and dataspace %s.", anchorName, dataspaceName));
}
}
- ``/shops/bookstore/categories[@numberOfBooks=1]``
- ``//categories[@name="Kids"]``
- ``//categories[@name='Kids']``
- - ``//categories[@code=1]/book[@title='Dune' and price=5]``
+ - ``//categories[@code=1]/books/book[@title='Dune' and @price=5]``
**Limitations**
- Only the last list or container can be queried leaf values. Any ancestor list will have to be referenced by its key name-value pair(s).
| | | |
| | If not defined, the password is generated when deploying the application. | |
| | | |
-| | See also :ref:`credentials_retrieval`. | |
+| | See also :ref:`cps_common_credentials_retrieval`. | |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
| config.dmiPluginUserName | User name used by cps-core to authenticate themselves for using ncmp-dmi-plugin service. | ``dmiuser`` |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
| | | |
| | If not defined, the password is generated when deploying the application. | |
| | | |
-| | See also :ref:`credentials_retrieval`. | |
+| | See also :ref:`cps_common_credentials_retrieval`. | |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
| postgres.config.pgUserName | Internal user name used by cps-core to connect to its own database. | ``cps`` |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
| | | |
| | If not defined, the password is generated when deploying the application. | |
| | | |
-| | See also :ref:`credentials_retrieval`. | |
+| | See also :ref:`cps_common_credentials_retrieval`. | |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
| postgres.config.pgDatabase | Database name used by cps-core | ``cpsdb`` |
| | | |
* DMI-Plugin: REST based interface which is used to provide integration
and allow the DMI registry API's have access to the corresponding NCMP API's within CPS Core.
- More information on the DMI-Plugins offered APIs can be found on the `DMI-Plugin's Design Page <https://docs.onap.org/projects/onap-cps-ncmp-dmi-plugin/en/latest/design.html>`_.
+ More information on the DMI-Plugins offered APIs can be found on the :ref:`DMI-Plugin's Design Page <onap-cps-ncmp-dmi-plugin:design>`.
CPS Path
========
Querying
-- **CPS Path** is used to query data nodes. The CPS Path is described in detail in :doc:`cps-path`.
+- **CPS Path** is used to query data nodes.
+.. toctree::
+ :maxdepth: 1
+
+ cps-path.rst
.. Below Label is used by documentation for other CPS components to link here, do not remove even if it gives a warning
.. _cps_ncmp_modelling: