// todo consider whether it is always necessary to fetch the entitlements
public PrismObject<ShadowType> locateResourceObject(ProvisioningContext ctx,
			Collection<? extends ResourceAttribute<?>> identifiers, OperationResult parentResult) throws ObjectNotFoundException,
			CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException {
		LOGGER.trace("Locating resource object {}", identifiers);
		ConnectorInstance connector = ctx.getConnector(ReadCapabilityType.class, parentResult);
		AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(ctx);
		if (hasAllIdentifiers(identifiers, ctx.getObjectClassDefinition())) {
			return fetchResourceObject(ctx, identifiers, 
					attributesToReturn, true, parentResult);	// todo consider whether it is always necessary to fetch the entitlements
		} else {
			// Search
			Collection<? extends RefinedAttributeDefinition> secondaryIdentifierDefs = ctx.getObjectClassDefinition().getSecondaryIdentifiers();
			// Assume single secondary identifier for simplicity
			if (secondaryIdentifierDefs.size() > 1) {
				throw new UnsupportedOperationException("Composite secondary identifier is not supported yet");
			} else if (secondaryIdentifierDefs.isEmpty()) {
				throw new SchemaException("No secondary identifier defined, cannot search");
			}
			RefinedAttributeDefinition<String> secondaryIdentifierDef = secondaryIdentifierDefs.iterator().next();
			ResourceAttribute<?> secondaryIdentifier = null;
			for (ResourceAttribute<?> identifier: identifiers) {
				if (identifier.getElementName().equals(secondaryIdentifierDef.getName())) {
					secondaryIdentifier = identifier;
				}
			}
			if (secondaryIdentifier == null) {
				throw new SchemaException("No secondary identifier present, cannot search. Identifiers: "+identifiers);
			}
			final ResourceAttribute<?> finalSecondaryIdentifier = secondaryIdentifier;
            List<PrismPropertyValue<String>> secondaryIdentifierValues = (List) secondaryIdentifier.getValues();
            PrismPropertyValue<String> secondaryIdentifierValue;
            if (secondaryIdentifierValues.size() > 1) {
                throw new IllegalStateException("Secondary identifier has more than one value: " + secondaryIdentifier.getValues());
            } else if (secondaryIdentifierValues.size() == 1) {
                secondaryIdentifierValue = secondaryIdentifierValues.get(0).clone();
            } else {
                secondaryIdentifierValue = null;
            }
            ObjectQuery query = prismContext.queryFor(ShadowType.class)
					.itemWithDef(secondaryIdentifierDef, ShadowType.F_ATTRIBUTES, secondaryIdentifierDef.getName()).eq(secondaryIdentifierValue)
					.build();
			final Holder<PrismObject<ShadowType>> shadowHolder = new Holder<>();
			ShadowResultHandler handler = new ShadowResultHandler() {
				@Override
				public boolean handle(PrismObject<ShadowType> shadow) {
					if (!shadowHolder.isEmpty()) {
						throw new IllegalStateException("More than one value found for secondary identifier "+finalSecondaryIdentifier);
					}
					shadowHolder.setValue(shadow);
					return true;
				}
			};
			try {
				connector.search(ctx.getObjectClassDefinition(), query, handler, attributesToReturn, null, null, ctx, parentResult);
				if (shadowHolder.isEmpty()) {
					throw new ObjectNotFoundException("No object found for secondary identifier "+secondaryIdentifier);
				}
				PrismObject<ShadowType> shadow = shadowHolder.getValue();
				PrismObject<ShadowType> finalShadow = postProcessResourceObjectRead(ctx, shadow, true, parentResult);
				LOGGER.trace("Located resource object {}", finalShadow);
				return finalShadow;
			} catch (GenericFrameworkException e) {
				throw new GenericConnectorException(e.getMessage(), e);
			}
		}
	}
if (hasAllIdentifiers(identifiers, ctx.getObjectClassDefinition())) {
return fetchResourceObject(ctx, identifiers,
attributesToReturn, true, parentResult); // todo consider whether it is always necessary to fetch the entitlements
} else {
// Search
public PrismObject<ShadowType> locateResourceObject(ProvisioningContext ctx,
Collection<? extends ResourceAttribute<?>> identifiers, OperationResult parentResult) throws ObjectNotFoundException,
CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException {
LOGGER.trace("Locating resource object {}", identifiers);
ConnectorInstance connector = ctx.getConnector(ReadCapabilityType.class, parentResult);
AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(ctx);
if (hasAllIdentifiers(identifiers, ctx.getObjectClassDefinition())) {
return fetchResourceObject(ctx, identifiers,
attributesToReturn, true, parentResult); // todo consider whether it is always necessary to fetch the entitlements
} else {
// Search
Collection<? extends RefinedAttributeDefinition> secondaryIdentifierDefs = ctx.getObjectClassDefinition().getSecondaryIdentifiers();
// Assume single secondary identifier for simplicity
if (secondaryIdentifierDefs.size() > 1) {
throw new UnsupportedOperationException("Composite secondary identifier is not supported yet");
} else if (secondaryIdentifierDefs.isEmpty()) {
throw new SchemaException("No secondary identifier defined, cannot search");
}
RefinedAttributeDefinition<String> secondaryIdentifierDef = secondaryIdentifierDefs.iterator().next();
public PrismObject<ShadowType> locateResourceObject(ProvisioningContext ctx,
Collection<? extends ResourceAttribute<?>> identifiers, OperationResult parentResult) throws ObjectNotFoundException,
CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, GenericConnectorException, ExpressionEvaluationException {
LOGGER.trace("Locating resource object {}", identifiers);
ConnectorInstance connector = ctx.getConnector(ReadCapabilityType.class, parentResult);
AttributesToReturn attributesToReturn = ProvisioningUtil.createAttributesToReturn(ctx);
if (hasAllIdentifiers(identifiers, ctx.getObjectClassDefinition())) {
return fetchResourceObject(ctx, identifiers,
attributesToReturn, true, parentResult); // todo consider whether it is always necessary to fetch the entitlements
} else {
// Search
Collection<? extends RefinedAttributeDefinition> secondaryIdentifierDefs = ctx.getObjectClassDefinition().getSecondaryIdentifiers();
// Assume single secondary identifier for simplicity
if (secondaryIdentifierDefs.size() > 1) {
throw new UnsupportedOperationException("Composite secondary identifier is not supported yet");
} else if (secondaryIdentifierDefs.isEmpty()) {
throw new SchemaException("No secondary identifier defined, cannot search");
}
RefinedAttributeDefinition<String> secondaryIdentifierDef = secondaryIdentifierDefs.iterator().next();
ResourceAttribute<?> secondaryIdentifier = null;
for (ResourceAttribute<?> identifier: identifiers) {
if (identifier.getElementName().equals(secondaryIdentifierDef.getName())) {
secondaryIdentifier = identifier;
}
}
if (secondaryIdentifier == null) {
throw new SchemaException("No secondary identifier present, cannot search. Identifiers: "+identifiers);
}
final ResourceAttribute<?> finalSecondaryIdentifier = secondaryIdentifier;