Skip to content

Commit

Permalink
Support for noFetch for ResourceType (provisioning) (MID-2707)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Dec 4, 2015
1 parent 63dcdf6 commit 0aec560
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 67 deletions.
Expand Up @@ -1271,7 +1271,7 @@ public void cleanupResult(Throwable e) {
OperationResult subresult = iterator.next();
if (subresult.getStatus() == OperationResultStatus.UNKNOWN) {
String message = "Subresult "+subresult.getOperation()+" of operation "+operation+" is still UNKNOWN during cleanup";
LOGGER.error("{}:\n{}", message, this.debugDump());
LOGGER.error("{}:\n{}", message, this.debugDump(), e);
if (e == null) {
throw new IllegalStateException(message);
} else {
Expand Down
Expand Up @@ -106,7 +106,7 @@ public ResourceType getResource() throws ObjectNotFoundException, SchemaExceptio
if (resourceOid == null) {
throw new SchemaException("Null resource OID "+getDesc());
}
resource = resourceManager.getResource(resourceOid, parentResult).asObjectable();
resource = resourceManager.getResource(resourceOid, null, parentResult).asObjectable();
if (resource != null && resource.getName() != null) {
super.setResourceName(resource.getName().getOrig());
}
Expand Down
Expand Up @@ -201,7 +201,7 @@ public <T extends ObjectType> PrismObject<T> getObject(Class<T> type, String oid
// (fresh)
// schema
try {
resultingObject = (PrismObject<T>) resourceManager.getResource(oid, result);
resultingObject = (PrismObject<T>) resourceManager.getResource(oid, SelectorOptions.findRootOptions(options), result);
} catch (ObjectNotFoundException ex) {
ProvisioningUtil.recordFatalError(LOGGER, result, "Resource object not found", ex);
throw ex;
Expand Down Expand Up @@ -497,7 +497,7 @@ public <T extends ObjectType> SearchResultList<PrismObject<T>> searchObjects(Cla
SearchResultMetadata metadata;
try {
if (!ShadowType.class.isAssignableFrom(type)) {
SearchResultList<PrismObject<T>> objects = searchRepoObjects(type, query, result);
SearchResultList<PrismObject<T>> objects = searchRepoObjects(type, query, options, result);
result.computeStatus();
result.recordSuccessIfUnknown();
result.cleanupResult();
Expand Down Expand Up @@ -543,7 +543,8 @@ public boolean handle(PrismObject<T> object, OperationResult parentResult) {


@SuppressWarnings("unchecked")
private <T extends ObjectType> SearchResultList<PrismObject<T>> searchRepoObjects(Class<T> type, ObjectQuery query, OperationResult result) throws SchemaException {
private <T extends ObjectType> SearchResultList<PrismObject<T>> searchRepoObjects(Class<T> type, ObjectQuery query,
Collection<SelectorOptions<GetOperationOptions>> options, OperationResult result) throws SchemaException {

List<PrismObject<T>> repoObjects = null;

Expand All @@ -558,7 +559,7 @@ private <T extends ObjectType> SearchResultList<PrismObject<T>> searchRepoObject

try {

PrismObject<T> completeResource = completeObject(type, repoObject, objResult);
PrismObject<T> completeResource = completeObject(type, repoObject, options, objResult);
newObjListType.add((PrismObject<T>) completeResource);

objResult.computeStatusIfUnknown();
Expand Down Expand Up @@ -626,12 +627,13 @@ private <T extends ObjectType> SearchResultList<PrismObject<T>> searchRepoObject

}

private <T extends ObjectType> PrismObject<T> completeObject(Class<T> type, PrismObject<T> inObject, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException {
private <T extends ObjectType> PrismObject<T> completeObject(Class<T> type, PrismObject<T> inObject,
Collection<SelectorOptions<GetOperationOptions>> options, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException {

if (ResourceType.class.equals(type)) {

PrismObject<ResourceType> completeResource = resourceManager.getResource((PrismObject<ResourceType>) inObject,
result);
PrismObject<ResourceType> completeResource = resourceManager.getResource((PrismObject<ResourceType>) inObject,
SelectorOptions.findRootOptions(options), result);
return (PrismObject<T>) completeResource;
} else {

Expand Down Expand Up @@ -1026,7 +1028,7 @@ public <T extends ShadowType> void finishOperation(PrismObject<T> object, Provis
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public <T extends ObjectType> SearchResultMetadata searchObjectsIterative(final Class<T> type, ObjectQuery query,
Collection<SelectorOptions<GetOperationOptions>> options,
final Collection<SelectorOptions<GetOperationOptions>> options,
final ResultHandler<T> handler, Task task, final OperationResult parentResult) throws SchemaException,
ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {

Expand Down Expand Up @@ -1072,7 +1074,7 @@ public <T extends ObjectType> SearchResultMetadata searchObjectsIterative(final
public boolean handle(PrismObject<T> object, OperationResult objResult) {
PrismObject<T> completeObject;
try {
completeObject = completeObject(type, object, objResult);
completeObject = completeObject(type, object, options, objResult);
} catch (SchemaException e) {
LOGGER.error("Error while completing {}: {}. Using non-complete object.", new Object[] {
object, e.getMessage(), e });
Expand Down Expand Up @@ -1270,7 +1272,7 @@ public <T extends ObjectType> void applyDefinition(ObjectDelta<T> delta, Objecta
if (ShadowType.class.isAssignableFrom(delta.getObjectTypeClass())){
getShadowCache(Mode.STANDARD).applyDefinition((ObjectDelta<ShadowType>) delta, (ShadowType) object, result);
} else if (ResourceType.class.isAssignableFrom(delta.getObjectTypeClass())){
resourceManager.applyDefinition((ObjectDelta<ResourceType>) delta, (ResourceType) object, result);
resourceManager.applyDefinition((ObjectDelta<ResourceType>) delta, (ResourceType) object, null, result);
} else {
throw new IllegalArgumentException("Could not apply definition to deltas for object type: " + delta.getObjectTypeClass());
}
Expand Down
Expand Up @@ -64,6 +64,8 @@
import com.evolveum.midpoint.provisioning.util.ProvisioningUtil;
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.CapabilityUtil;
import com.evolveum.midpoint.schema.GetOperationOptions;
import com.evolveum.midpoint.schema.SelectorOptions;
import com.evolveum.midpoint.schema.constants.ConnectorTestOperation;
import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition;
import com.evolveum.midpoint.schema.processor.ResourceAttributeContainerDefinition;
Expand Down Expand Up @@ -115,7 +117,7 @@ public class ResourceManager {

private static final String OPERATION_COMPLETE_RESOURCE = ResourceManager.class.getName() + ".completeResource";

public PrismObject<ResourceType> getResource(PrismObject<ResourceType> repositoryObject, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException{
public PrismObject<ResourceType> getResource(PrismObject<ResourceType> repositoryObject, GetOperationOptions options, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException{
InternalMonitor.getResourceCacheStats().recordRequest();

PrismObject<ResourceType> cachedResource = resourceCache.get(repositoryObject);
Expand All @@ -127,10 +129,10 @@ public PrismObject<ResourceType> getResource(PrismObject<ResourceType> repositor
LOGGER.debug("Storing fetched resource {}, version {} to cache (previously cached version {})",
new Object[]{ repositoryObject.getOid(), repositoryObject.getVersion(), resourceCache.getVersion(repositoryObject.getOid())});

return putToCache(repositoryObject, parentResult);
return loadAndCacheResource(repositoryObject, options, parentResult);
}

public PrismObject<ResourceType> getResource(String oid, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException{
public PrismObject<ResourceType> getResource(String oid, GetOperationOptions options, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException{
InternalMonitor.getResourceCacheStats().recordRequest();

String version = repositoryService.getVersion(ResourceType.class, oid, parentResult);
Expand All @@ -150,13 +152,19 @@ public PrismObject<ResourceType> getResource(String oid, OperationResult parentR

PrismObject<ResourceType> repositoryObject = repositoryService.getObject(ResourceType.class, oid, null, parentResult);

return putToCache(repositoryObject, parentResult);
return loadAndCacheResource(repositoryObject, options, parentResult);
}


private PrismObject<ResourceType> putToCache(PrismObject<ResourceType> repositoryObject, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException {
private PrismObject<ResourceType> loadAndCacheResource(PrismObject<ResourceType> repositoryObject,
GetOperationOptions options, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException {

PrismObject<ResourceType> completedResource = completeResource(repositoryObject, null, false, parentResult);
PrismObject<ResourceType> completedResource = completeResource(repositoryObject, null, false, options, parentResult);

if (!isComplete(completedResource)) {
// No not cache non-complete resources (e.g. those retrieved with noFetch)
return completedResource;
}

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Putting resource in cache:\n{}", completedResource.debugDump());
Expand Down Expand Up @@ -215,7 +223,7 @@ public void deleteResource(String oid, ProvisioningOperationOptions options, Tas
* @throws ConfigurationException
*/
private PrismObject<ResourceType> completeResource(PrismObject<ResourceType> repoResource, ResourceSchema resourceSchema,
boolean fetchedSchema, OperationResult parentResult) throws ObjectNotFoundException, SchemaException,
boolean fetchedSchema, GetOperationOptions options, OperationResult parentResult) throws ObjectNotFoundException, SchemaException,
CommunicationException, ConfigurationException {

// do not add as a subresult..it will be added later, if the completing
Expand Down Expand Up @@ -252,6 +260,12 @@ private PrismObject<ResourceType> completeResource(PrismObject<ResourceType> rep

} else {
// The resource is NOT complete. Try to fetch schema and capabilities

if (GetOperationOptions.isNoFetch(options)) {
// We need to fetch schema, but the noFetch option is specified. Therefore return whatever we have.
result.recordSuccessIfUnknown();
return repoResource;
}

ConnectorInstance connector = null;
try {
Expand Down Expand Up @@ -661,7 +675,7 @@ public void testConnection(PrismObject<ResourceType> resource, OperationResult p
// generate the resource schema - until we have full schema caching
// capability.
try {
resource = completeResource(resource, schema, true, schemaResult);
resource = completeResource(resource, schema, true, null, schemaResult);
} catch (ObjectNotFoundException e) {
schemaResult.recordFatalError(
"Object not found (unexpected error, probably a bug): " + e.getMessage(), e);
Expand Down Expand Up @@ -770,41 +784,6 @@ private void adjustSchemaForSimulatedCapabilities(PrismObject<ResourceType> reso
}
}

public ResourceSchema getResourceSchema(ResourceType resource, OperationResult parentResult) throws SchemaException, CommunicationException,
ConfigurationException {

ResourceSchema schema = null;
try {

if (!isComplete(resource.asPrismObject())) {
// Make sure that the schema is retrieved from the resource
// this will also retrieve the schema from cache and/or parse it if
// needed
resource = completeResource(resource.asPrismObject(), null, false, parentResult).asObjectable();
}
schema = RefinedResourceSchema.getResourceSchema(resource, prismContext);

} catch (SchemaException e) {
parentResult.recordFatalError("Unable to parse resource schema: " + e.getMessage(), e);
throw new SchemaException("Unable to parse resource schema: " + e.getMessage(), e);
} catch (ObjectNotFoundException e) {
// this really should not happen
parentResult.recordFatalError("Unexpected ObjectNotFoundException: " + e.getMessage(), e);
throw new SystemException("Unexpected ObjectNotFoundException: " + e.getMessage(), e);
} catch (ConfigurationException e) {
parentResult.recordFatalError("Unable to parse resource schema: " + e.getMessage(), e);
throw new ConfigurationException("Unable to parse resource schema: " + e.getMessage(), e);
}

if (schema == null) {
return null;
}

checkSchema(schema);

return schema;
}

private void checkSchema(PrismSchema schema) throws SchemaException {
// This is resource schema, it should contain only
// ResourceObjectDefintions
Expand Down Expand Up @@ -834,7 +813,7 @@ private ConnectorInstance getConnectorInstance(PrismObject<ResourceType> resourc
return connectorTypeManager.getConfiguredConnectorInstance(resource, forceFresh, parentResult);
}

public void applyDefinition(ObjectDelta<ResourceType> delta, ResourceType resourceWhenNoOid, OperationResult objectResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException {
public void applyDefinition(ObjectDelta<ResourceType> delta, ResourceType resourceWhenNoOid, GetOperationOptions options, OperationResult objectResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException {

if (delta.isAdd()) {
PrismObject<ResourceType> resource = delta.getObjectToAdd();
Expand All @@ -859,7 +838,7 @@ public void applyDefinition(ObjectDelta<ResourceType> delta, ResourceType resour
Validate.notNull(resourceWhenNoOid, "Resource oid not specified in the object delta, and resource is not specified as well. Could not apply definition.");
resource = resourceWhenNoOid.asPrismObject();
} else {
resource = getResource(resourceOid, objectResult);
resource = getResource(resourceOid, options, objectResult);
}

ResourceType resourceType = resource.asObjectable();
Expand Down Expand Up @@ -979,7 +958,7 @@ public void applyDefinition(ObjectQuery query, OperationResult result) {
}

public Object executeScript(String resourceOid, ProvisioningScriptType script, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
PrismObject<ResourceType> resource = getResource(resourceOid, result);
PrismObject<ResourceType> resource = getResource(resourceOid, null, result);
ConnectorInstance connectorInstance = connectorTypeManager.getConfiguredConnectorInstance(resource, false, result);
ExecuteProvisioningScriptOperation scriptOperation = ProvisioningUtil.convertToScriptOperation(script, "script on "+resource, prismContext);
try {
Expand Down
Expand Up @@ -639,16 +639,14 @@ public void visit(ObjectFilter filter) {
throw e;
}
}



protected ResourceType getResource(ResourceShadowDiscriminator coords, OperationResult parentResult)
throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException {
String resourceOid = coords.getResourceOid();
if (resourceOid == null) {
throw new IllegalArgumentException("No resource OID in " + coords);
}
return resourceManager.getResource(resourceOid, parentResult).asObjectable();
return resourceManager.getResource(resourceOid, null, parentResult).asObjectable();
}

@SuppressWarnings("rawtypes")
Expand Down
Expand Up @@ -252,13 +252,10 @@ public void test000Integrity() throws ObjectNotFoundException, SchemaException {
/**
* Check whether the connectors were discovered correctly and were added to
* the repository.
*
* @throws SchemaException
*
*/
@Test
public void test010Connectors() throws Exception {
final String TEST_NAME = "test010Connectors";
public void test010ListConnectors() throws Exception {
final String TEST_NAME = "test010ListConnectors";
TestUtil.displayTestTile(TEST_NAME);
// GIVEN
OperationResult result = new OperationResult(TestDummy.class.getName() + "." + TEST_NAME);
Expand Down Expand Up @@ -324,6 +321,48 @@ public void test012ConnectorRediscovery() {
assertTrue("Rediscovered something", discoverLocalConnectors.isEmpty());
}

/**
* List resources with noFetch option. This is what GUI does. This operation
* should be harmless and should not change resource state.
*/
@Test
public void test015ListResourcesNoFetch() throws Exception {
final String TEST_NAME = "test015ListResourcesNoFetch";
TestUtil.displayTestTile(TEST_NAME);
// GIVEN
Task task = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME);
OperationResult result = task.getResult();
Collection<SelectorOptions<GetOperationOptions>> options = SelectorOptions.createCollection(GetOperationOptions.createNoFetch());

// WHEN
SearchResultList<PrismObject<ResourceType>> resources = provisioningService.searchObjects(ResourceType.class, null, options, task, result);

// THEN
result.computeStatus();
display("searchObjects result", result);
TestUtil.assertSuccess(result);

assertFalse("No resources found", resources.isEmpty());
for (PrismObject<ResourceType> resource : resources) {
ResourceType resourceType = resource.asObjectable();
display("Found resource " + resourceType, resourceType);

display("XML " + resourceType, PrismTestUtil.serializeObjectToString(resource, PrismContext.LANG_XML));

XmlSchemaType xmlSchemaType = resourceType.getSchema();
if (xmlSchemaType != null) {
Element xsdSchemaElement = ResourceTypeUtil.getResourceXsdSchema(resourceType);
assertNull("Found schema in "+resource, xsdSchemaElement);
}
}

assertConnectorSchemaParseIncrement(1);
assertConnectorCapabilitiesFetchIncrement(0);
assertConnectorInitializationCountIncrement(0);
assertResourceSchemaFetchIncrement(0);
assertResourceSchemaParseCountIncrement(0);
}

/**
* This should be the very first test that works with the resource.
*
Expand Down Expand Up @@ -390,7 +429,7 @@ public void test020Connection() throws Exception {
// schema will be checked in next test

assertResourceSchemaFetchIncrement(1);
assertConnectorSchemaParseIncrement(1);
assertConnectorSchemaParseIncrement(0);
assertConnectorCapabilitiesFetchIncrement(1);
assertConnectorInitializationCountIncrement(1);
assertResourceSchemaParseCountIncrement(1);
Expand Down

0 comments on commit 0aec560

Please sign in to comment.