Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Evolveum/midpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
1azyman committed May 2, 2022
2 parents ebbd517 + dc3a115 commit 40ceef3
Show file tree
Hide file tree
Showing 13 changed files with 201 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ private String getStringValue(Object object, PrismObject<LookupTableType> lookup
}

protected String getStringValueForObject(ObjectType object) {
return WebComponentUtil.getDisplayName(object.asPrismObject());
return WebComponentUtil.getDisplayNameOrName(object.asPrismObject());
}

private boolean isPolyString(QName typeName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventRecordType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.apache.commons.lang3.StringUtils;

/**
* @author lskublik
*/
Expand Down Expand Up @@ -378,6 +380,7 @@ public void resetTable(AjaxRequestTarget target) {

@Override
protected String getStringValueForObject(ObjectType object) {
return super.getStringValueForObject(object) + " (" + object.getOid() + ")";
String displayName = super.getStringValueForObject(object);
return StringUtils.isEmpty(displayName) ? object.getOid() : displayName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ public static String prettyPrintForReport(ObjectType object, LocalizationService
name = PolyString.getOrig(ObjectTypeUtil.getDisplayName(object));
}
}
return name + " (" + object.getOid() + ")";
return StringUtils.isEmpty(name) ? object.getOid() : name;
}

public static String prettyPrintUsersForReport(List<ObjectReferenceType> userRefList) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
package com.evolveum.midpoint.provisioning.impl.resources;

import com.evolveum.midpoint.CacheInvalidationContext;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.repo.api.Cache;
import com.evolveum.midpoint.repo.api.RepositoryService;
Expand All @@ -21,6 +20,9 @@
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SingleCacheStateInformationType;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.SetMultimap;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
Expand All @@ -31,17 +33,22 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.evolveum.midpoint.util.MiscUtil.schemaCheck;
import static com.evolveum.midpoint.util.caching.CacheConfiguration.StatisticsLevel.PER_CACHE;

/**
* Caches ResourceType instances with a parsed schemas.
* Caches {@link ResourceType} instances with a parsed schemas.
*
* Resource cache is similar to repository cache. One of the differences is that it does not expire its entries.
* It relies on versions and on invalidation events instead. So we have to use resource object versions when querying it.
* (This could be perhaps changed in the future. But not now.)
*
* The cache deals with concrete resources, i.e. _not_ the abstract ones. So, when an abstract resource is invalidated,
* all concrete ones that inherit from it should be invalidated as well.
*
* @author Radovan Semancik
*/
@Component
Expand All @@ -50,7 +57,6 @@ public class ResourceCache implements Cache {
private static final Trace LOGGER = TraceManager.getTrace(ResourceCache.class);
private static final Trace LOGGER_CONTENT = TraceManager.getTrace(ResourceCache.class.getName() + ".content");

@Autowired private PrismContext prismContext;
@Autowired private CacheRegistry cacheRegistry;
@Autowired @Qualifier("cacheRepositoryService")
private RepositoryService repositoryService;
Expand All @@ -73,16 +79,28 @@ public void unregister() {
*/
private final Map<String, PrismObject<ResourceType>> cache = new ConcurrentHashMap<>();

synchronized void put(PrismObject<ResourceType> resource) throws SchemaException {
/**
* `K -> V` means that (concrete) resource `V` depends on (concrete or abstract) resource `K`.
*/
private final SetMultimap<String, String> dependencyMap = HashMultimap.create();

/**
* Puts a (complete) resource into the cache.
*
* @param resource The object to cache.
* @param ancestorsOids OIDs of the resource ancestor(s), if any. Invalidation of any of these results in the invalidation
* of the cached resource.
*/
synchronized void put(
@NotNull PrismObject<ResourceType> resource,
@NotNull Collection<String> ancestorsOids) throws SchemaException {
String oid = resource.getOid();
if (oid == null) {
throw new SchemaException("Attempt to cache "+resource+" without an OID");
}
schemaCheck(oid != null, "Attempt to cache %s without an OID", resource);

String version = resource.getVersion();
if (version == null) {
throw new SchemaException("Attempt to cache "+resource+" without version");
}
schemaCheck(version != null, "Attempt to cache %s without version", resource);

updateDependencies(oid, ancestorsOids);

PrismObject<ResourceType> cachedResource = cache.get(oid);
if (cachedResource == null) {
Expand All @@ -98,6 +116,23 @@ synchronized void put(PrismObject<ResourceType> resource) throws SchemaException
}
}

/**
* Updates the {@link #dependencyMap} with the current information about ancestors of given (concrete) resource.
*
* Guarded by `this` (responsible of the caller).
*/
private void updateDependencies(String concreteResourceOid, Collection<String> ancestorsOids) {
// Removing no-longer-valid ancestor OIDs
dependencyMap.entries().removeIf(
entry ->
concreteResourceOid.equals(entry.getValue())
&& !ancestorsOids.contains(entry.getKey()));

// Re-adding (all) ancestor OIDs; some are already there, but ignoring it.
ancestorsOids.forEach(
ancestorOid -> dependencyMap.put(ancestorOid, concreteResourceOid));
}

private boolean compareVersion(String version1, String version2) {
return version1 == null && version2 == null || version1 != null && version1.equals(version2);
}
Expand All @@ -117,7 +152,7 @@ synchronized PrismObject<ResourceType> get(@NotNull String oid, String requested
LOGGER.debug("MISS(wrong version) for {} (req={}, actual={})", oid, requestedVersion, cachedResource.getVersion());
LOGGER.trace("Cached resource version {} does not match requested resource version {}, purging from cache",
cachedResource.getVersion(), requestedVersion);
cache.remove(oid);
invalidateSingle(oid);
resourceToReturn = null;
} else if (readOnly) {
cachedResource.checkImmutable();
Expand Down Expand Up @@ -176,26 +211,49 @@ synchronized String getVersion(String oid) {
return cachedResource.getVersion();
}

synchronized void remove(String oid) {
cache.remove(oid);
}

@Override
public synchronized void invalidate(Class<?> type, String oid, CacheInvalidationContext context) {
if (type == null || type.isAssignableFrom(ResourceType.class)) {
if (oid != null) {
remove(oid);
invalidateSingle(oid);
} else {
cache.clear();
invalidateAll();
}
}
}

/** Invalidates single (concrete) resource and all its descendants. */
synchronized void invalidateSingle(@NotNull String oid) {
Set<String> descendants = dependencyMap.get(oid);
LOGGER.trace("Invalidating {} and all its descendants: {}", oid, descendants);

invalidateSingleShallow(oid);
descendants.forEach(this::invalidateSingle);
}

/**
* Removes the specific resource from {@link #cache} and {@link #dependencyMap}). Not touching the descendants.
* Must be guarded by `this` (caller's responsibility).
*/
private void invalidateSingleShallow(@NotNull String oid) {
cache.remove(oid);
dependencyMap.removeAll(oid);
dependencyMap.entries().removeIf(
entry -> oid.equals(entry.getValue()));
}

/** Invalidates the whole cache. Must be guarded by `this` (caller's responsibility). */
private void invalidateAll() {
LOGGER.trace("Invalidating the whole cache");
cache.clear();
dependencyMap.clear();
}

@NotNull
@Override
public synchronized Collection<SingleCacheStateInformationType> getStateInformation() {
return Collections.singleton(
new SingleCacheStateInformationType(prismContext)
new SingleCacheStateInformationType()
.name(ResourceCache.class.getName())
.size(cache.size())
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class ResourceCompletionOperation {
@NotNull private final Task task;
@NotNull private final CommonBeans beans;

@NotNull private final ResourceExpansionOperation expansionOperation;

/**
* Operation result for the operation itself. It is quite unusual to store the operation result
* like this, but we need it to provide the overall success/failure of the operation.
Expand All @@ -112,6 +114,7 @@ class ResourceCompletionOperation {
this.capabilityMap = capabilityMap;
this.task = task;
this.beans = beans;
this.expansionOperation = new ResourceExpansionOperation(resource, beans);
}

/**
Expand All @@ -137,6 +140,7 @@ class ResourceCompletionOperation {

result = parentResult.createMinorSubresult(OP_COMPLETE_RESOURCE);
try {
expansionOperation.execute(result);
applyConnectorSchema();
PrismObject<ResourceType> reloaded = completeAndReload();
parseSchema(reloaded);
Expand Down Expand Up @@ -494,6 +498,10 @@ public OperationResultStatus getOperationResultStatus() {
return result.getStatus();
}

public Collection<String> getAncestorsOids() {
return expansionOperation.getAncestorsOids();
}

/** Stopping the evaluation, and returning the {@link #resource}. */
private static class StopException extends Exception {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2010-2022 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.provisioning.impl.resources;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.provisioning.impl.CommonBeans;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;

import org.jetbrains.annotations.NotNull;

import java.util.HashSet;
import java.util.Set;

/**
* TODO better name
*
* Represents an operation where the concrete (incomplete) resource is expanded into its full form by resolving
* its ancestor(s). This process is called resource inheritance, and is used to implement e.g. resource templates.
*/
class ResourceExpansionOperation {

private static final String OP_EXPAND = ResourceExpansionOperation.class.getName() + ".expand";

/**
* The resource being expanded. TODO name
*/
@NotNull private final PrismObject<ResourceType> resource;
@NotNull private final CommonBeans beans;

@NotNull private final Set<String> ancestorsOids = new HashSet<>();

ResourceExpansionOperation(@NotNull PrismObject<ResourceType> resource, @NotNull CommonBeans beans) {
this.resource = resource;
this.beans = beans;
}

public void execute(OperationResult parentResult) {
OperationResult result = parentResult.createMinorSubresult(OP_EXPAND);
try {
// TODO
} catch (Throwable t) {
result.recordFatalError(t);
throw t;
} finally {
result.close();
}
}

public @NotNull Set<String> getAncestorsOids() {
return ancestorsOids;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import com.evolveum.midpoint.schema.internals.InternalMonitor;
import com.evolveum.midpoint.schema.processor.ResourceObjectTypeDefinition;
import com.evolveum.midpoint.schema.processor.ResourceSchema;
import com.evolveum.midpoint.schema.processor.ResourceSchemaFactory;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.schema.statistics.ConnectorOperationalStatus;
Expand Down Expand Up @@ -154,7 +153,7 @@ public class ResourceManager {
} else {
LOGGER.debug("Putting {} into cache", repositoryObject);
// Cache only resources that are completely OK
beans.resourceCache.put(completedResource);
beans.resourceCache.put(completedResource, completionOperation.getAncestorsOids());
}
}
return completedResource;
Expand All @@ -180,29 +179,11 @@ private void logResourceAfterCompletion(PrismObject<ResourceType> completedResou
return repositoryService.getObject(ResourceType.class, oid, null, parentResult);
}

public void deleteResource(String oid, OperationResult parentResult) throws ObjectNotFoundException {
resourceCache.remove(oid);
public void deleteResource(@NotNull String oid, OperationResult parentResult) throws ObjectNotFoundException {
resourceCache.invalidateSingle(oid);
repositoryService.deleteObject(ResourceType.class, oid, parentResult);
}

/**
* Applies proper definition (connector schema) to the resource.
*/
void applyConnectorSchemasToResource(PrismObject<ResourceType> resource, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
schemaHelper.applyConnectorSchemasToResource(resource, task, result);
}

/**
* Apply proper definition (connector schema) to the resource.
*/
void applyConnectorSchemaToResource(ConnectorSpec connectorSpec, PrismObjectDefinition<ResourceType> resourceDefinition,
PrismObject<ResourceType> resource, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException,
ConfigurationException, SecurityViolationException {
schemaHelper.applyConnectorSchemaToResource(connectorSpec, resourceDefinition, resource, task, result);
}

public SystemConfigurationType getSystemConfiguration() {
return provisioningService.getSystemConfiguration();
}
Expand Down Expand Up @@ -245,18 +226,6 @@ public void testConnection(PrismObject<ResourceType> resource, Task task, Operat
.execute(parentResult);
}

void updateResourceSchema(List<ConnectorSpec> allConnectorSpecs, OperationResult parentResult,
PrismObject<ResourceType> resource)
throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException {
ResourceSchema resourceSchema = ResourceSchemaFactory.getRawSchema(resource);
if (resourceSchema != null) {
for (ConnectorSpec connectorSpec : allConnectorSpecs) {
ConnectorInstance instance = connectorManager.getConfiguredConnectorInstance(connectorSpec, false, parentResult);
instance.updateSchema(resourceSchema);
}
}
}

/**
* Modifies resource availability status in the repository (if needed).
*
Expand Down Expand Up @@ -329,6 +298,24 @@ public void applyDefinition(ObjectQuery query, OperationResult result) {
// TODO: not implemented yet
}

/**
* Applies proper definition (connector schema) to the resource.
*/
void applyConnectorSchemasToResource(PrismObject<ResourceType> resource, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
schemaHelper.applyConnectorSchemasToResource(resource, task, result);
}

/**
* Apply proper definition (connector schema) to the resource.
*/
void applyConnectorSchemaToResource(ConnectorSpec connectorSpec, PrismObjectDefinition<ResourceType> resourceDefinition,
PrismObject<ResourceType> resource, Task task, OperationResult result)
throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, CommunicationException,
ConfigurationException, SecurityViolationException {
schemaHelper.applyConnectorSchemaToResource(connectorSpec, resourceDefinition, resource, task, result);
}

public Object executeScript(String resourceOid, ProvisioningScriptType script, Task task, OperationResult result)
throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException,
ExpressionEvaluationException {
Expand Down

0 comments on commit 40ceef3

Please sign in to comment.