use of com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignStateType.CLOSED in project midpoint by Evolveum.
the class CertificationManagerImpl method openNextStage.
@Override
public void openNextStage(String campaignOid, int requestedStageNumber, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ObjectNotFoundException, ObjectAlreadyExistsException {
Validate.notNull(campaignOid, "campaignOid");
Validate.notNull(task, "task");
Validate.notNull(parentResult, "parentResult");
OperationResult result = parentResult.createSubresult(OPERATION_OPEN_NEXT_STAGE);
result.addParam("campaignOid", campaignOid);
result.addParam("requestedStageNumber", requestedStageNumber);
try {
AccessCertificationCampaignType campaign = generalHelper.getCampaign(campaignOid, null, task, result);
result.addParam("campaign", ObjectTypeUtil.toShortString(campaign));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("openNextStage starting for {}", ObjectTypeUtil.toShortString(campaign));
}
securityEnforcer.authorize(ModelAuthorizationAction.OPEN_CERTIFICATION_CAMPAIGN_REVIEW_STAGE.getUrl(), null, campaign.asPrismObject(), null, null, null, result);
final int currentStageNumber = campaign.getStageNumber();
final int stages = CertCampaignTypeUtil.getNumberOfStages(campaign);
final AccessCertificationCampaignStateType state = campaign.getState();
LOGGER.trace("openNextStage: currentStageNumber={}, stages={}, requestedStageNumber={}, state={}", currentStageNumber, stages, requestedStageNumber, state);
if (IN_REVIEW_STAGE.equals(state)) {
result.recordFatalError("Couldn't advance to review stage " + requestedStageNumber + " as the stage " + currentStageNumber + " is currently open.");
} else if (IN_REMEDIATION.equals(state)) {
result.recordFatalError("Couldn't advance to review stage " + requestedStageNumber + " as the campaign is currently in the remediation phase.");
} else if (CLOSED.equals(state)) {
result.recordFatalError("Couldn't advance to review stage " + requestedStageNumber + " as the campaign is already closed.");
} else if (!REVIEW_STAGE_DONE.equals(state) && !CREATED.equals(state)) {
throw new IllegalStateException("Unexpected campaign state: " + state);
} else if (REVIEW_STAGE_DONE.equals(state) && requestedStageNumber != currentStageNumber + 1) {
result.recordFatalError("Couldn't advance to review stage " + requestedStageNumber + " as the campaign is currently in stage " + currentStageNumber);
} else if (CREATED.equals(state) && requestedStageNumber != 1) {
result.recordFatalError("Couldn't advance to review stage " + requestedStageNumber + " as the campaign was just created");
} else if (requestedStageNumber > stages) {
result.recordFatalError("Couldn't advance to review stage " + requestedStageNumber + " as the campaign has only " + stages + " stages");
} else {
final CertificationHandler handler = findCertificationHandler(campaign);
final AccessCertificationStageType stage = updateHelper.createStage(campaign, currentStageNumber + 1);
final List<ItemDelta<?, ?>> deltas = updateHelper.getDeltasForStageOpen(campaign, stage, handler, task, result);
updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltas, task, result);
updateHelper.afterStageOpen(campaignOid, stage, task, result);
}
} catch (RuntimeException e) {
result.recordFatalError("Couldn't move to certification campaign stage " + requestedStageNumber + ": unexpected exception: " + e.getMessage(), e);
throw e;
} finally {
result.computeStatusIfUnknown();
}
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignStateType.CLOSED in project midpoint by Evolveum.
the class WfPrepareRootOperationTaskHandler method run.
//endregion
//region run method
@Override
public TaskRunResult run(Task task) {
TaskRunResultStatus status = TaskRunResultStatus.FINISHED;
try {
OperationResult result = task.getResult();
WfTask rootWfTask = wfTaskController.recreateRootWfTask(task);
List<WfTask> children = rootWfTask.listChildren(result);
LensContext rootContext = (LensContext) rootWfTask.retrieveModelContext(result);
boolean changed = false;
for (WfTask child : children) {
if (child.getTaskExecutionStatus() != TaskExecutionStatus.CLOSED) {
throw new IllegalStateException("Child task " + child + " is not in CLOSED state; its state is " + child.getTaskExecutionStatus());
}
if (child.hasModelContext()) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Child job {} has model context present - skipping fetching deltas from it.", child);
}
} else {
ObjectTreeDeltas deltas = child.retrieveResultingDeltas();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Child job {} returned {} deltas", child, deltas != null ? deltas.getDeltaList().size() : 0);
}
if (deltas != null) {
LensFocusContext focusContext = rootContext.getFocusContext();
ObjectDelta focusDelta = deltas.getFocusChange();
if (focusDelta != null) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Adding delta from job {} to root model context; delta = {}", child, focusDelta.debugDump(0));
}
if (focusContext.getPrimaryDelta() != null && !focusContext.getPrimaryDelta().isEmpty()) {
focusContext.addPrimaryDelta(focusDelta);
} else {
focusContext.setPrimaryDelta(focusDelta);
}
changed = true;
}
Set<Map.Entry<ResourceShadowDiscriminator, ObjectDelta<ShadowType>>> entries = deltas.getProjectionChangeMapEntries();
for (Map.Entry<ResourceShadowDiscriminator, ObjectDelta<ShadowType>> entry : entries) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Adding projection delta from job {} to root model context; rsd = {}, delta = {}", child, entry.getKey(), entry.getValue().debugDump());
}
ModelProjectionContext projectionContext = rootContext.findProjectionContext(entry.getKey());
if (projectionContext == null) {
// TODO more liberal treatment?
throw new IllegalStateException("No projection context for " + entry.getKey());
}
if (projectionContext.getPrimaryDelta() != null && !projectionContext.getPrimaryDelta().isEmpty()) {
projectionContext.addPrimaryDelta(entry.getValue());
} else {
projectionContext.setPrimaryDelta(entry.getValue());
}
changed = true;
}
}
}
}
if (!rootContext.hasAnyPrimaryChange()) {
// deletes the model context
rootContext = null;
// regardless of whether rootContext was changed or not
changed = true;
}
if (changed) {
rootWfTask.storeModelContext(rootContext);
rootWfTask.commitChanges(result);
}
} catch (SchemaException | ObjectNotFoundException | ObjectAlreadyExistsException | ConfigurationException | ExpressionEvaluationException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't aggregate resulting deltas from child workflow-monitoring tasks due to schema exception", e);
status = TaskRunResultStatus.PERMANENT_ERROR;
} catch (CommunicationException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't aggregate resulting deltas from child workflow-monitoring tasks", e);
status = TaskRunResultStatus.TEMPORARY_ERROR;
}
TaskRunResult runResult = new TaskRunResult();
runResult.setRunResultStatus(status);
return runResult;
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignStateType.CLOSED in project midpoint by Evolveum.
the class TestSanityLegacy method test400ImportFromResource.
@Test
public void test400ImportFromResource() throws Exception {
final String TEST_NAME = "test400ImportFromResource";
TestUtil.displayTestTile(TEST_NAME);
// GIVEN
checkAllShadows();
assertNoRepoCache();
OperationResult result = new OperationResult(TestSanityLegacy.class.getName() + "." + TEST_NAME);
// Make sure Mr. Gibbs has "l" attribute set to the same value as an outbound expression is setting
ChangeRecordEntry entry = openDJController.executeLdifChange(LDIF_GIBBS_MODIFY_FILE);
display("Entry from LDIF", entry);
// Let's add an entry with multiple uids.
Entry addEntry = openDJController.addEntryFromLdifFile(LDIF_HERMAN_FILENAME);
display("Entry from LDIF", addEntry);
// WHEN
TaskType taskType = modelWeb.importFromResource(RESOURCE_OPENDJ_OID, IMPORT_OBJECTCLASS);
// THEN
assertNoRepoCache();
displayJaxb("importFromResource result", taskType.getResult(), SchemaConstants.C_RESULT);
AssertJUnit.assertEquals("importFromResource has failed", OperationResultStatusType.IN_PROGRESS, taskType.getResult().getStatus());
// Convert the returned TaskType to a more usable Task
Task task = taskManager.createTaskInstance(taskType.asPrismObject(), result);
AssertJUnit.assertNotNull(task);
assertNotNull(task.getOid());
AssertJUnit.assertTrue(task.isAsynchronous());
AssertJUnit.assertEquals(TaskExecutionStatus.RUNNABLE, task.getExecutionStatus());
// AssertJUnit.assertEquals(TaskExclusivityStatus.CLAIMED, task.getExclusivityStatus());
display("Import task after launch", task);
PrismObject<TaskType> tObject = repositoryService.getObject(TaskType.class, task.getOid(), null, result);
TaskType taskAfter = tObject.asObjectable();
display("Import task in repo after launch", taskAfter);
result.computeStatus();
TestUtil.assertSuccess("getObject has failed", result);
final String taskOid = task.getOid();
waitFor("Waiting for import to complete", new Checker() {
@Override
public boolean check() throws CommonException {
Holder<OperationResultType> resultHolder = new Holder<OperationResultType>();
Holder<ObjectType> objectHolder = new Holder<ObjectType>();
OperationResult opResult = new OperationResult("import check");
assertNoRepoCache();
SelectorQualifiedGetOptionsType options = new SelectorQualifiedGetOptionsType();
try {
modelWeb.getObject(ObjectTypes.TASK.getTypeQName(), taskOid, options, objectHolder, resultHolder);
} catch (FaultMessage faultMessage) {
throw new SystemException(faultMessage);
}
assertNoRepoCache();
// display("getObject result (wait loop)",resultHolder.value);
TestUtil.assertSuccess("getObject has failed", resultHolder.value);
Task task = taskManager.createTaskInstance((PrismObject<TaskType>) objectHolder.value.asPrismObject(), opResult);
System.out.println(new Date() + ": Import task status: " + task.getExecutionStatus() + ", progress: " + task.getProgress());
if (task.getExecutionStatus() == TaskExecutionStatus.CLOSED) {
// Task closed, wait finished
return true;
}
// IntegrationTestTools.display("Task result while waiting: ", task.getResult());
return false;
}
@Override
public void timeout() {
// No reaction, the test will fail right after return from this
}
}, 180000);
// wait a second until the task will be definitely saved
Thread.sleep(1000);
//### Check task state after the task is finished ###
Holder<ObjectType> objectHolder = new Holder<ObjectType>();
Holder<OperationResultType> resultHolder = new Holder<OperationResultType>();
SelectorQualifiedGetOptionsType options = new SelectorQualifiedGetOptionsType();
assertNoRepoCache();
modelWeb.getObject(ObjectTypes.TASK.getTypeQName(), task.getOid(), options, objectHolder, resultHolder);
assertNoRepoCache();
TestUtil.assertSuccess("getObject has failed", resultHolder.value);
task = taskManager.createTaskInstance((PrismObject<TaskType>) objectHolder.value.asPrismObject(), result);
display("Import task after finish (fetched from model)", task);
AssertJUnit.assertEquals(TaskExecutionStatus.CLOSED, task.getExecutionStatus());
assertNotNull("Null lastRunStartTimestamp in " + task, task.getLastRunStartTimestamp());
assertNotNull("Null lastRunFinishTimestamp in " + task, task.getLastRunFinishTimestamp());
long importDuration = task.getLastRunFinishTimestamp() - task.getLastRunStartTimestamp();
double usersPerSec = (task.getProgress() * 1000) / importDuration;
display("Imported " + task.getProgress() + " users in " + importDuration + " milliseconds (" + usersPerSec + " users/sec)");
OperationResult taskResult = task.getResult();
AssertJUnit.assertNotNull("Task has no result", taskResult);
TestUtil.assertSuccess("Import task result is not success", taskResult);
AssertJUnit.assertTrue("Task failed", taskResult.isSuccess());
AssertJUnit.assertTrue("No progress", task.getProgress() > 0);
//### Check if the import created users and shadows ###
// Listing of shadows is not supported by the provisioning. So we need
// to look directly into repository
List<PrismObject<ShadowType>> sobjects = repositoryService.searchObjects(ShadowType.class, null, null, result);
result.computeStatus();
TestUtil.assertSuccess("listObjects has failed", result);
AssertJUnit.assertFalse("No shadows created", sobjects.isEmpty());
for (PrismObject<ShadowType> aObject : sobjects) {
ShadowType shadow = aObject.asObjectable();
display("Shadow object after import (repo)", shadow);
// This would be really strange ;-)
assertNotEmpty("No OID in shadow", shadow.getOid());
assertNotEmpty("No name in shadow", shadow.getName());
AssertJUnit.assertNotNull("No objectclass in shadow", shadow.getObjectClass());
AssertJUnit.assertNotNull("Null attributes in shadow", shadow.getAttributes());
assertAttributeNotNull("No UID in shadow", shadow, SchemaConstants.ICFS_UID);
}
Holder<ObjectListType> listHolder = new Holder<ObjectListType>();
assertNoRepoCache();
modelWeb.searchObjects(ObjectTypes.USER.getTypeQName(), null, null, listHolder, resultHolder);
assertNoRepoCache();
ObjectListType uobjects = listHolder.value;
TestUtil.assertSuccess("listObjects has failed", resultHolder.value);
AssertJUnit.assertFalse("No users created", uobjects.getObject().isEmpty());
// TODO: use another account, not guybrush
display("Users after import " + uobjects.getObject().size());
for (ObjectType oo : uobjects.getObject()) {
UserType user = (UserType) oo;
if (SystemObjectsType.USER_ADMINISTRATOR.value().equals(user.getOid())) {
//skip administrator check
continue;
}
display("User after import (repo)", user);
// This would be
assertNotEmpty("No OID in user", user.getOid());
// really
// strange ;-)
assertNotEmpty("No name in user", user.getName());
assertNotNull("No fullName in user", user.getFullName());
assertNotEmpty("No fullName in user", user.getFullName().getOrig());
assertNotEmpty("No familyName in user", user.getFamilyName().getOrig());
if (user.getName().getOrig().equals(USER_GUYBRUSH_USERNAME)) {
// skip the rest of checks for guybrush, he does not have LDAP account now
continue;
}
assertTrue("User " + user.getName() + " is disabled (" + user.getActivation().getAdministrativeStatus() + ")", user.getActivation() == null || user.getActivation().getAdministrativeStatus() == ActivationStatusType.ENABLED);
List<ObjectReferenceType> accountRefs = user.getLinkRef();
AssertJUnit.assertEquals("Wrong accountRef for user " + user.getName(), 1, accountRefs.size());
ObjectReferenceType accountRef = accountRefs.get(0);
boolean found = false;
for (PrismObject<ShadowType> aObject : sobjects) {
ShadowType acc = aObject.asObjectable();
if (accountRef.getOid().equals(acc.getOid())) {
found = true;
break;
}
}
if (!found) {
AssertJUnit.fail("accountRef does not point to existing account " + accountRef.getOid());
}
PrismObject<ShadowType> aObject = modelService.getObject(ShadowType.class, accountRef.getOid(), null, task, result);
ShadowType account = aObject.asObjectable();
display("Account after import ", account);
String attributeValueL = ShadowUtil.getMultiStringAttributeValueAsSingle(account, new QName(ResourceTypeUtil.getResourceNamespace(resourceTypeOpenDjrepo), "l"));
// assertEquals("Unexcpected value of l", "middle of nowhere", attributeValueL);
assertEquals("Unexcpected value of l", getUserLocality(user), attributeValueL);
}
// This also includes "idm" user imported from LDAP. Later we need to ignore that one.
assertEquals("Wrong number of users after import", 10, uobjects.getObject().size());
checkAllShadows();
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignStateType.CLOSED in project midpoint by Evolveum.
the class AbstractManualResourceTest method test204CloseCaseAndRefreshAccountWill.
/**
* Case is closed. The operation is complete.
*/
@Test
public void test204CloseCaseAndRefreshAccountWill() throws Exception {
final String TEST_NAME = "test204CloseCaseAndRefreshAccountWill";
displayTestTile(TEST_NAME);
// GIVEN
Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();
syncServiceMock.reset();
PrismObject<ShadowType> shadowBefore = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, result);
display("Shadow before", shadowBefore);
closeCase(willLastCaseOid);
accountWillCompletionTimestampStart = clock.currentTimeXMLGregorianCalendar();
// WHEN
displayWhen(TEST_NAME);
provisioningService.refreshShadow(shadowBefore, null, task, result);
// THEN
displayThen(TEST_NAME);
assertSuccess(result);
accountWillCompletionTimestampEnd = clock.currentTimeXMLGregorianCalendar();
PrismObject<ShadowType> shadowRepo = repositoryService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, result);
display("Repo shadow", shadowRepo);
assertSinglePendingOperation(shadowRepo, accountWillReqestTimestampStart, accountWillReqestTimestampEnd, OperationResultStatusType.SUCCESS, accountWillCompletionTimestampStart, accountWillCompletionTimestampEnd);
assertShadowActivationAdministrativeStatusFromCache(shadowRepo, ActivationStatusType.ENABLED);
assertAttribute(shadowRepo, ATTR_USERNAME_QNAME, ACCOUNT_WILL_USERNAME);
assertAttributeFromCache(shadowRepo, ATTR_FULLNAME_QNAME, ACCOUNT_WILL_FULLNAME_PIRATE);
PrismObject<ShadowType> shadowProvisioning = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, result);
display("Provisioning shadow", shadowProvisioning);
ShadowType shadowTypeProvisioning = shadowProvisioning.asObjectable();
assertShadowName(shadowProvisioning, ACCOUNT_WILL_USERNAME);
assertEquals("Wrong kind (provisioning)", ShadowKindType.ACCOUNT, shadowTypeProvisioning.getKind());
assertShadowActivationAdministrativeStatus(shadowProvisioning, ActivationStatusType.ENABLED);
assertAttribute(shadowProvisioning, ATTR_USERNAME_QNAME, ACCOUNT_WILL_USERNAME);
if (supportsBackingStore()) {
assertAttribute(shadowProvisioning, ATTR_FULLNAME_QNAME, ACCOUNT_WILL_FULLNAME);
} else {
assertAttribute(shadowProvisioning, ATTR_FULLNAME_QNAME, ACCOUNT_WILL_FULLNAME_PIRATE);
}
assertAttributeFromBackingStore(shadowProvisioning, ATTR_DESCRIPTION_QNAME, ACCOUNT_WILL_DESCRIPTION_MANUAL);
assertShadowPassword(shadowProvisioning);
PendingOperationType pendingOperation = assertSinglePendingOperation(shadowProvisioning, accountWillReqestTimestampStart, accountWillReqestTimestampEnd, OperationResultStatusType.SUCCESS, accountWillCompletionTimestampStart, accountWillCompletionTimestampEnd);
PrismObject<ShadowType> shadowProvisioningFuture = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE)), task, result);
display("Provisioning shadow (future)", shadowProvisioningFuture);
assertShadowName(shadowProvisioningFuture, ACCOUNT_WILL_USERNAME);
assertEquals("Wrong kind (provisioning)", ShadowKindType.ACCOUNT, shadowProvisioningFuture.asObjectable().getKind());
assertShadowActivationAdministrativeStatus(shadowProvisioningFuture, ActivationStatusType.ENABLED);
assertAttribute(shadowProvisioningFuture, ATTR_USERNAME_QNAME, ACCOUNT_WILL_USERNAME);
assertAttribute(shadowProvisioningFuture, ATTR_FULLNAME_QNAME, ACCOUNT_WILL_FULLNAME_PIRATE);
assertAttributeFromBackingStore(shadowProvisioningFuture, ATTR_DESCRIPTION_QNAME, ACCOUNT_WILL_DESCRIPTION_MANUAL);
assertShadowPassword(shadowProvisioningFuture);
assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED);
// In this case check notifications at the end. There were some reads that
// internally triggered refresh. Maku sure no extra notifications were sent.
syncServiceMock.assertNoNotifyChange();
syncServiceMock.assertNotifySuccessOnly();
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignStateType.CLOSED in project midpoint by Evolveum.
the class AbstractManualResourceTest method test110CloseCaseAndRefreshAccountWill.
/**
* Case is closed. The operation is complete.
*/
@Test
public void test110CloseCaseAndRefreshAccountWill() throws Exception {
final String TEST_NAME = "test110CloseCaseAndRefreshAccountWill";
displayTestTile(TEST_NAME);
// GIVEN
Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();
syncServiceMock.reset();
PrismObject<ShadowType> shadowBefore = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, result);
display("Shadow before", shadowBefore);
closeCase(willLastCaseOid);
accountWillCompletionTimestampStart = clock.currentTimeXMLGregorianCalendar();
// WHEN
displayWhen(TEST_NAME);
provisioningService.refreshShadow(shadowBefore, null, task, result);
// THEN
displayThen(TEST_NAME);
assertSuccess(result);
accountWillCompletionTimestampEnd = clock.currentTimeXMLGregorianCalendar();
PrismObject<ShadowType> shadowRepo = repositoryService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, result);
display("Repo shadow", shadowRepo);
assertSinglePendingOperation(shadowRepo, accountWillReqestTimestampStart, accountWillReqestTimestampEnd, OperationResultStatusType.SUCCESS, accountWillCompletionTimestampStart, accountWillCompletionTimestampEnd);
assertAttribute(shadowRepo, ATTR_USERNAME_QNAME, ACCOUNT_WILL_USERNAME);
assertAttributeFromCache(shadowRepo, ATTR_FULLNAME_QNAME, ACCOUNT_WILL_FULLNAME);
assertShadowActivationAdministrativeStatusFromCache(shadowRepo, ActivationStatusType.ENABLED);
syncServiceMock.assertNoNotifyChange();
syncServiceMock.assertNotifySuccessOnly();
PrismObject<ShadowType> shadowProvisioning = provisioningService.getObject(ShadowType.class, ACCOUNT_WILL_OID, null, task, result);
display("Provisioning shadow", shadowProvisioning);
ShadowType shadowTypeProvisioning = shadowProvisioning.asObjectable();
assertShadowName(shadowProvisioning, ACCOUNT_WILL_USERNAME);
assertEquals("Wrong kind (provisioning)", ShadowKindType.ACCOUNT, shadowTypeProvisioning.getKind());
assertAttribute(shadowProvisioning, ATTR_USERNAME_QNAME, ACCOUNT_WILL_USERNAME);
assertAttribute(shadowProvisioning, ATTR_FULLNAME_QNAME, ACCOUNT_WILL_FULLNAME);
assertAttributeFromBackingStore(shadowProvisioning, ATTR_DESCRIPTION_QNAME, ACCOUNT_WILL_DESCRIPTION_MANUAL);
assertShadowActivationAdministrativeStatus(shadowProvisioning, ActivationStatusType.ENABLED);
assertShadowPassword(shadowProvisioning);
PendingOperationType pendingOperation = assertSinglePendingOperation(shadowProvisioning, accountWillReqestTimestampStart, accountWillReqestTimestampEnd, OperationResultStatusType.SUCCESS, accountWillCompletionTimestampStart, accountWillCompletionTimestampEnd);
assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED);
}
Aggregations