Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into feature/skip-mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
katkav committed Apr 19, 2021
2 parents c7815a3 + 36add64 commit 774b053
Show file tree
Hide file tree
Showing 38 changed files with 1,045 additions and 357 deletions.
Expand Up @@ -231,7 +231,7 @@ public ColumnMenuAction<PrismContainerValueWrapper<C>> createDeleteColumnAction(
@Override
public void onClick(AjaxRequestTarget target) {
if (getRowModel() == null) {
deleteItemPerformed(target, new ArrayList<>());
deleteItemPerformed(target, getSelectedItems());
} else {
List<PrismContainerValueWrapper<C>> toDelete = new ArrayList<>();
toDelete.add(getRowModel().getObject());
Expand Down
@@ -1,26 +1,26 @@
/*
* Copyright (c) 2010-2019 Evolveum and contributors
* Copyright (C) 2010-2021 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.util.statistics;

import ch.qos.logback.classic.Level;
import com.evolveum.midpoint.util.PrettyPrinter;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.util.aspect.ProfilingDataManager;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.MDC;

import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import ch.qos.logback.classic.Level;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.MDC;

import com.evolveum.midpoint.util.PrettyPrinter;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.util.aspect.ProfilingDataManager;

/**
* This class provides basically the functionality of MidpointInterceptor. However it was refactored to be callable also
* outside of the context of AOP - manually by injecting appropriate code, mimicking MidpointInterceptor.invoke method.
Expand Down Expand Up @@ -87,7 +87,7 @@ public static OperationInvocationRecord create(String operationName, Object[] ar
methodName = "unknownMethod";
} else {
className = operationName.substring(0, i);
methodName = operationName.substring(i+1);
methodName = operationName.substring(i + 1);
}
OperationInvocationRecord ctx = new OperationInvocationRecord(className, methodName, measureCpuTime);
ctx.beforeCall(arguments);
Expand Down Expand Up @@ -141,12 +141,12 @@ private boolean isTrace(Level level) {
private void beforeCall(Object[] arguments) {
previousSubsystem = swapSubsystemMark(subsystem != null ? subsystem.name() : null);

StringBuilder infoLog = new StringBuilder("#### Entry: ");
invocationId = ID_COUNTER.incrementAndGet();

if (debugEnabled) {
StringBuilder infoLog = new StringBuilder("#### Entry: ");
infoLog.append(invocationId);

infoLog.append(" ");
if (traceEnabled) {
String depthStringValue = MDC.get(OperationExecutionLogger.MDC_DEPTH_KEY);
if (depthStringValue == null || depthStringValue.isEmpty()) {
Expand All @@ -155,9 +155,7 @@ private void beforeCall(Object[] arguments) {
callDepth = Integer.parseInt(depthStringValue) + 1;
}
MDC.put(OperationExecutionLogger.MDC_DEPTH_KEY, Integer.toString(callDepth));
for (int i = 0; i < callDepth; i++) {
infoLog.append(OperationExecutionLogger.INDENT_STRING);
}
infoLog.append(OperationExecutionLogger.INDENT_STRING.repeat(Math.max(0, callDepth)));
}

infoLog.append(shortenedClassName);
Expand Down Expand Up @@ -229,9 +227,7 @@ public void afterCall(MethodInvocation invocation) {
sb.append(invocationId);
sb.append(" ");
if (traceEnabled) {
for (int i = 0; i < callDepth + 1; i++) {
sb.append(OperationExecutionLogger.INDENT_STRING);
}
sb.append(OperationExecutionLogger.INDENT_STRING.repeat(Math.max(0, callDepth + 1)));
}
sb.append(shortenedClassName);
sb.append("->");
Expand Down
4 changes: 2 additions & 2 deletions repo/repo-sqale/sql/pgnew-repo.sql
Expand Up @@ -102,7 +102,7 @@ CREATE TYPE SynchronizationSituationType AS ENUM (

CREATE TYPE TaskBindingType AS ENUM ('LOOSE', 'TIGHT');

CREATE TYPE TaskExecutionStatusType AS ENUM ('RUNNABLE', 'WAITING', 'SUSPENDED', 'CLOSED');
CREATE TYPE TaskExecutionStateType AS ENUM ('RUNNING', 'RUNNABLE', 'WAITING', 'SUSPENDED', 'CLOSED');

CREATE TYPE TaskRecurrenceType AS ENUM ('SINGLE', 'RECURRING');

Expand Down Expand Up @@ -1036,7 +1036,7 @@ CREATE TABLE m_task (
binding TaskBindingType,
category TEXT/*VARCHAR(255)*/,
completionTimestamp TIMESTAMPTZ,
executionStatus TaskExecutionStatusType,
executionStatus TaskExecutionStateType,
fullResult BYTEA,
handlerUri_id INTEGER REFERENCES m_uri(id),
lastRunStartTimestamp TIMESTAMPTZ,
Expand Down
Expand Up @@ -6,92 +6,149 @@
*/
package com.evolveum.midpoint.repo.sqale;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.PrismContainer;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

/**
* Generator assigning missing IDs to PCVs of multi-value containers.
*/
public class ContainerValueIdGenerator {

private final PrismObject<?> object;
private static final Trace LOGGER = TraceManager.getTrace(ContainerValueIdGenerator.class);

private final Set<Long> usedIds = new HashSet<>();
private final List<PrismContainerValue<?>> pcvsWithoutId = new ArrayList<>();

private long maxUsedId = 0; // tracks max CID (set to duplicate CID if found)

public ContainerValueIdGenerator(@NotNull PrismObject<?> object) {
this.object = object;
/**
* Method inserts IDs for prism container values without IDs and returns highest CID.
* This directly changes the object provided as a parameter, if necessary.
*/
public long generateForNewObject(@NotNull PrismObject<?> object) throws SchemaException {
checkExistingContainers(object);
LOGGER.trace("Generating " + pcvsWithoutId.size() + " missing container IDs for "
+ object.toDebugType() + "/" + object.getOid());
assignMissingContainerIds();
return maxUsedId;
}

/** Method inserts IDs for prism container values without IDs and returns highest CID. */
public long generate() throws SchemaException {
processContainers();
generateContainerIds();
return maxUsedId;
/**
* Initializes the generator for modify object and checks that no previous CIDs are missing.
* This is a critical step before calling {@link #processModification}.
*/
public ContainerValueIdGenerator forModifyObject(
@NotNull PrismObject<?> object, long containerIdSeq) throws SchemaException {
checkExistingContainers(object);
if (!pcvsWithoutId.isEmpty()) {
LOGGER.warn("Generating missing container IDs in previously persisted prism object "
+ object.toDebugType() + "/" + object.getOid() + " for container values: "
+ pcvsWithoutId);
assignMissingContainerIds();
}
if (containerIdSeq <= maxUsedId) {
LOGGER.warn("Current CID sequence (" + containerIdSeq + ") is not above max used CID ("
+ maxUsedId + ") for " + object.toDebugType() + "/" + object.getOid()
+ ". CID sequence will be fixed, but it's suspicious!");
}
return this;
}

private void processContainers() throws SchemaException {
try {
//noinspection unchecked
object.accept(visitable -> {
if (!(visitable instanceof PrismContainer)) {
return;
}
/**
* This checks the modification for containers without assigned CIDs and adds them.
* This changes values inside the modification and this *must be called before the modification
* is applied to the prism object*.
*
* Theoretically, the changes may affect the prism object after the fact, but if any cloning
* is involved this may not be true, so preferably use this *before* applying the modification.
*/
public void processModification(ItemDelta<?, ?> modification) throws SchemaException {
processModificationValues(modification.getValuesToAdd());
processModificationValues(modification.getValuesToReplace());
// values to delete are irrelevant

assignMissingContainerIds();
}

if (visitable instanceof PrismObject) {
return;
private void processModificationValues(Collection<? extends PrismValue> values)
throws SchemaException {
if (values != null) {
for (PrismValue prismValue : values) {
if (prismValue instanceof PrismContainerValue) {
PrismContainerValue<?> pcv = (PrismContainerValue<?>) prismValue;
// the top level value is not covered by checkExistingContainers()
if (pcv.getDefinition().isMultiValue()) {
processContainerValue(pcv);
}

checkExistingContainers(pcv);
}
}
}
}

PrismContainer<?> container = (PrismContainer<?>) visitable;
PrismContainerDefinition<?> def = container.getDefinition();
if (def.isSingleValue()) {
return;
/**
* Checks the provided container (possibly the whole object) and finds values requiring CID.
* This does NOT cover top-level PCV if provided as parameter.
*/
private void checkExistingContainers(Visitable<?> object) throws SchemaException {
try {
object.accept(visitable -> {
if (visitable instanceof PrismContainer
&& !(visitable instanceof PrismObject)
&& ((PrismContainer<?>) visitable).getDefinition().isMultiValue()) {
processContainer((PrismContainer<?>) visitable);
}

processContainer(container);
});
} catch (DuplicateContainerIdException e) {
throw new SchemaException("CID " + maxUsedId + " is used repeatedly in the object!");
throw new SchemaException(
"CID " + maxUsedId + " is used repeatedly in the object: " + object);
}
}

private void processContainer(PrismContainer<?> container) {
for (PrismContainerValue<?> val : container.getValues()) {
if (val.getId() != null) {
Long cid = val.getId();
if (!usedIds.add(cid)) {
maxUsedId = cid;
throw DuplicateContainerIdException.INSTANCE;
}
maxUsedId = Math.max(maxUsedId, cid);
} else {
pcvsWithoutId.add(val);
processContainerValue(val);
}
}

private void processContainerValue(PrismContainerValue<?> val) {
if (val.getId() != null) {
Long cid = val.getId();
if (!usedIds.add(cid)) {
maxUsedId = cid;
throw DuplicateContainerIdException.INSTANCE;
}
maxUsedId = Math.max(maxUsedId, cid);
} else {
pcvsWithoutId.add(val);
}
}

private void generateContainerIds() {
/** Generates container IDs for {@link #pcvsWithoutId} and clears the list. */
private void assignMissingContainerIds() {
for (PrismContainerValue<?> val : pcvsWithoutId) {
val.setId(nextId());
}
pcvsWithoutId.clear();
}

public long nextId() {
maxUsedId++;
return maxUsedId;
}

public long lastUsedId() {
return maxUsedId;
}

private static class DuplicateContainerIdException extends RuntimeException {
static final DuplicateContainerIdException INSTANCE = new DuplicateContainerIdException();

Expand Down
Expand Up @@ -6,14 +6,16 @@
*/
package com.evolveum.midpoint.repo.sqale;

import javax.xml.namespace.QName;

import com.querydsl.sql.SQLQuery;
import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.query.InOidFilter;
import com.evolveum.midpoint.repo.sqale.filtering.InOidFilterProcessor;
import com.evolveum.midpoint.repo.sqale.qmodel.SqaleTableMapping;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.SqlRepoContext;
import com.evolveum.midpoint.repo.sqlbase.SqlTransformerSupport;
import com.evolveum.midpoint.repo.sqlbase.filtering.FilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.mapping.QueryTableMapping;
import com.evolveum.midpoint.repo.sqlbase.mapping.SqlTransformer;
Expand All @@ -23,7 +25,8 @@ public class SqaleQueryContext<S, Q extends FlexibleRelationalPathBase<R>, R>
extends SqlQueryContext<S, Q, R> {

public static <S, Q extends FlexibleRelationalPathBase<R>, R> SqaleQueryContext<S, Q, R> from(
Class<S> schemaType, SqlTransformerSupport transformerSupport, SqlRepoContext sqlRepoContext) {
Class<S> schemaType, SqaleTransformerSupport transformerSupport,
SqlRepoContext sqlRepoContext) {

SqaleTableMapping<S, Q, R> rootMapping = sqlRepoContext.getMappingBySchemaType(schemaType);
Q rootPath = rootMapping.defaultAlias();
Expand All @@ -32,13 +35,14 @@ public static <S, Q extends FlexibleRelationalPathBase<R>, R> SqaleQueryContext<
// we must take care of unique alias names for JOINs, which is what we want.
query.getMetadata().setValidate(true);

return new SqaleQueryContext<>(rootPath, rootMapping, transformerSupport, sqlRepoContext, query);
return new SqaleQueryContext<>(
rootPath, rootMapping, transformerSupport, sqlRepoContext, query);
}

private SqaleQueryContext(
Q entityPath,
SqaleTableMapping<S, Q, R> mapping,
SqlTransformerSupport transformerSupport,
SqaleTransformerSupport transformerSupport,
SqlRepoContext sqlRepoContext,
SQLQuery<?> query) {
super(entityPath, mapping, sqlRepoContext, transformerSupport, query);
Expand All @@ -54,6 +58,10 @@ public FilterProcessor<InOidFilter> createInOidFilter(SqlQueryContext<?, ?, ?> c
return new InOidFilterProcessor(context);
}

public @NotNull Integer searchCachedRelationId(QName qName) {
return transformerSupport().searchCachedRelationId(qName);
}

/**
* Returns {@link SqaleQueryContext} - lot of ugly casting here, but it is not possible to
* use covariant return type with covariant parametric types (narrower generics).
Expand All @@ -64,6 +72,10 @@ public FilterProcessor<InOidFilter> createInOidFilter(SqlQueryContext<?, ?, ?> c
deriveNew(DQ newPath, QueryTableMapping<?, DQ, DR> newMapping) {
return (SqlQueryContext<?, DQ, DR>) new SqaleQueryContext(
newPath, (SqaleTableMapping<?, ?, ?>) newMapping,
transformerSupport, sqlRepoContext, sqlQuery);
transformerSupport(), sqlRepoContext, sqlQuery);
}

private SqaleTransformerSupport transformerSupport() {
return (SqaleTransformerSupport) transformerSupport;
}
}
Expand Up @@ -67,6 +67,7 @@ public SqaleRepoContext(
public void clearCaches() {
try (JdbcSession jdbcSession = newJdbcSession().startReadOnlyTransaction()) {
uriCache.initialize(jdbcSession);
jdbcSession.commit();
}
}

Expand All @@ -82,7 +83,7 @@ public Integer searchCachedUriId(String uri) {
}

/** @see UriCache#resolveUriToId(String) */
public Integer resolveUriToId(String uri) {
public @NotNull Integer resolveUriToId(String uri) {
return uriCache.resolveUriToId(uri);
}

Expand Down

0 comments on commit 774b053

Please sign in to comment.