diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java index 7b7f8fa451b..964f1cf0190 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java @@ -66,9 +66,7 @@ public class GetOperationOptions extends AbstractOptions implements Serializable private Boolean resolve; /** - * Resolve the object reference names. (Currently applicable only as a top-level option.) - * - * EXPERIMENTAL. + * Resolve the object reference names. */ private Boolean resolveNames; @@ -149,6 +147,11 @@ public class GetOperationOptions extends AbstractOptions implements Serializable */ private Boolean distinct; + /** + * Whether to attach diagnostics data to the returned object(s). + */ + private Boolean attachDiagData; + public RetrieveOption getRetrieve() { return retrieve; } @@ -650,6 +653,32 @@ public static GetOperationOptions createDistinct() { return opts; } + public Boolean getAttachDiagData() { + return attachDiagData; + } + + public void setAttachDiagData(Boolean value) { + this.attachDiagData = value; + } + + public static boolean isAttachDiagData(GetOperationOptions options) { + if (options == null) { + return false; + } + if (options.attachDiagData == null) { + return false; + } + return options.attachDiagData; + } + + /** + * Whether to attach diagnostics data to the returned object(s). + */ + public static GetOperationOptions createAttachDiagData() { + GetOperationOptions opts = new GetOperationOptions(); + opts.setAttachDiagData(true); + return opts; + } public RelationalValueSearchQuery getRelationalValueSearchQuery() { return relationalValueSearchQuery; diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationConstants.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationConstants.java index e342faf8a05..32ae451a4e4 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationConstants.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/result/OperationConstants.java @@ -47,6 +47,7 @@ public class OperationConstants { public static final String CREATE_REPORT_FILE = PREFIX + ".createReportFile"; public static final String CHECK_SHADOW_INTEGRITY = PREFIX + ".checkShadowIntegrity"; + public static final String CHECK_OBJECT_INTEGRITY = PREFIX + ".checkObjectIntegrity"; public static final String REINDEX = PREFIX + ".reindex"; public static final String AUDIT_REINDEX = PREFIX + ".auditReindex"; public static final String SHADOW_REFRESH = PREFIX + ".shadowRefresh"; diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/histogram/Histogram.java b/infra/util/src/main/java/com/evolveum/midpoint/util/histogram/Histogram.java new file mode 100644 index 00000000000..ce85e88de8f --- /dev/null +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/histogram/Histogram.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.util.histogram; + +import org.apache.commons.lang.StringUtils; + +import java.util.ArrayList; + +/** + * @author mederly + */ +public class Histogram { + + private final int step; + private final int maxLength; + + public Histogram(int step, int maxLength) { + this.step = step; + this.maxLength = maxLength; + } + + private final ArrayList> entries = new ArrayList<>(); + + private long minValue, maxValue, totalValue = 0; + private T minItem, maxItem; + private int items = 0; + + public void register(T item, long value) { + if (items == 0) { + minValue = maxValue = value; + minItem = maxItem = item; + } else { + if (value < minValue) { + minValue = value; + minItem = item; + } + if (value > maxValue) { + maxValue = value; + maxItem = item; + } + } + totalValue += value; + items++; + + long bucketLong = value / step; + int bucket = bucketLong < maxLength-1 ? (int) bucketLong : maxLength-1; + if (entries.size() <= bucket) { + entries.ensureCapacity(bucket); + while (entries.size() <= bucket) { + entries.add(new HistogramEntry<>()); + } + } + entries.get(bucket).record(item, value); + } + + public int getStep() { + return step; + } + + public int getMaxLength() { + return maxLength; + } + + public ArrayList> getEntries() { + return entries; + } + + @SuppressWarnings("unused") + public long getMinValue() { + return minValue; + } + + @SuppressWarnings("unused") + public long getMaxValue() { + return maxValue; + } + + @SuppressWarnings("unused") + public long getTotalValue() { + return totalValue; + } + + public int getItems() { + return items; + } + + public String dump(int columns) { + StringBuilder sb = new StringBuilder(); + sb.append("Count: ").append(items).append("\n"); + if (items == 0) { + return sb.toString(); + } + sb.append("Min: ").append(minValue).append(" (").append(minItem).append(")\n"); + sb.append("Max: ").append(maxValue).append(" (").append(maxItem).append(")\n"); + sb.append("Avg: ").append(totalValue / items).append("\n"); + sb.append("\nHistogram:\n\n"); + int maxIntervalLength = Math.max(getIntervalString(entries.size()).length(), 10); + String rowFormatString = "%" + maxIntervalLength + "s : %6s : %s : %s\n"; + //noinspection ConstantConditions + int maxCount = entries.stream().mapToInt(e -> e.getItemsCount()).max().getAsInt(); + sb.append(String.format(rowFormatString, "Interval", "Items", column(0, maxCount, columns), "Representative")); + sb.append(StringUtils.repeat("-", maxIntervalLength + columns + 40)).append("\n"); + for (int i = 0; i < entries.size(); i++) { + HistogramEntry entry = entries.get(i); + sb.append(String.format(rowFormatString, getIntervalString(i), + String.valueOf(entry.getItemsCount()), column(entry.getItemsCount(), maxCount, columns), getRepresentative(entry))); + } + sb.append("\n"); + return sb.toString(); + } + + private Object column(int count, int maxCount, int columns) { + int bars = (int) ((double) columns * (double) count / (double) maxCount); + return StringUtils.repeat("#", bars) + StringUtils.repeat(" ", columns-bars); + } + + private String getRepresentative(HistogramEntry entry) { + if (entry.getRepresentativeItem() == null) { + return ""; + } + return entry.getRepresentativeItem() + " (" + entry.getRepresentativeItemValue() + ")"; + } + + private String getIntervalString(int i) { + if (i == entries.size()-1) { + return String.format("[%d-%d]", getLower(i), maxValue); + } else { + return String.format("[%d-%d]", getLower(i), getUpper(i)); + } + } + + private long getLower(int bucket) { + return bucket * step; + } + + private long getUpper(int bucket) { + return getLower(bucket+1)-1; + } +} diff --git a/infra/util/src/main/java/com/evolveum/midpoint/util/histogram/HistogramEntry.java b/infra/util/src/main/java/com/evolveum/midpoint/util/histogram/HistogramEntry.java new file mode 100644 index 00000000000..64d20c4376a --- /dev/null +++ b/infra/util/src/main/java/com/evolveum/midpoint/util/histogram/HistogramEntry.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.util.histogram; + +/** + * @author mederly + */ +public class HistogramEntry { + + private int itemsCount; + private long representativeItemValue; + private T representativeItem; + + public int getItemsCount() { + return itemsCount; + } + + public T getRepresentativeItem() { + return representativeItem; + } + + public long getRepresentativeItemValue() { + return representativeItemValue; + } + + public void record(T item, long value) { + if (representativeItem == null || representativeItemValue < value) { + representativeItem = item; + representativeItemValue = value; + } + itemsCount++; + } +} diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelPublicConstants.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelPublicConstants.java index 4be784f0ea7..f8371c9cbeb 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelPublicConstants.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelPublicConstants.java @@ -33,6 +33,7 @@ public class ModelPublicConstants { public static final String AUDIT_REINDEX_TASK_HANDLER_URI = SchemaConstants.NS_MODEL + "/auditReindex/handler-3"; public static final String CLEANUP_TASK_HANDLER_URI = SchemaConstants.NS_MODEL + "/cleanup/handler-3"; public static final String SHADOW_INTEGRITY_CHECK_TASK_HANDLER_URI = SchemaConstants.NS_MODEL + "/shadow-integrity-check/handler-3"; + public static final String OBJECT_INTEGRITY_CHECK_TASK_HANDLER_URI = SchemaConstants.NS_MODEL + "/object-integrity-check/handler-3"; public static final String FOCUS_VALIDITY_SCANNER_TASK_HANDLER_URI = NS_SYNCHRONIZATION_TASK_PREFIX + "/focus-validation-scanner/handler-3"; // TODO why synchronization? public static final String TRIGGER_SCANNER_TASK_HANDLER_URI = SchemaConstants.NS_MODEL + "/trigger/scanner/handler-3"; public static final String SHADOW_REFRESH_TASK_HANDLER_URI = SchemaConstants.NS_MODEL + "/shadowRefresh/handler-3"; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 951b1f3170c..e331aeecbd2 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -44,6 +44,7 @@ import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.*; import com.evolveum.midpoint.prism.query.builder.QueryBuilder; +import com.evolveum.midpoint.prism.util.CloneUtil; import com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.repo.api.RepoAddOptions; @@ -216,20 +217,21 @@ private CertificationManager getCertificationManagerChecked() { @Override public PrismObject getObject(Class clazz, String oid, - Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, + Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { Validate.notEmpty(oid, "Object oid must not be null or empty."); Validate.notNull(parentResult, "Operation result must not be null."); Validate.notNull(clazz, "Object class must not be null."); RepositoryCache.enter(); - PrismObject object = null; + PrismObject object; OperationResult result = parentResult.createMinorSubresult(GET_OBJECT); result.addParam("oid", oid); - result.addCollectionOfSerializablesAsParam("options", options); + result.addCollectionOfSerializablesAsParam("options", rawOptions); result.addParam("class", clazz); - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + Collection> options = preProcessOptionsSecurity(rawOptions); + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); try { if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 @@ -273,7 +275,7 @@ public PrismObject getObject(Class clazz, String oi return object; } - protected void resolve(PrismObject object, Collection> options, + private void resolve(PrismObject object, Collection> options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { if (object == null) { return; @@ -281,7 +283,7 @@ protected void resolve(PrismObject object, Collection> options, + private void resolve(Containerable containerable, Collection> options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { if (containerable == null || options == null) { return; @@ -766,7 +768,7 @@ private void applyDefinitions(Collection> delt @Override public SearchResultList> searchObjects(Class type, ObjectQuery query, - Collection> options, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Collection> rawOptions, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { Validate.notNull(type, "Object type must not be null."); Validate.notNull(parentResult, "Operation result must not be null."); @@ -774,6 +776,7 @@ public SearchResultList> searchObjects(Cla ModelUtils.validatePaging(query.getPaging()); } + Collection> options = preProcessOptionsSecurity(rawOptions); GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); ObjectTypes.ObjectManager searchProvider = ObjectTypes.getObjectManagerForClass(type); @@ -784,7 +787,7 @@ public SearchResultList> searchObjects(Cla OperationResult result = parentResult.createSubresult(SEARCH_OBJECTS); result.addParams(new String[] { "query", "paging", "searchProvider" }, query, (query != null ? query.getPaging() : "undefined"), searchProvider); - + query = preProcessQuerySecurity(type, query); if (isFilterNone(query, result)) { return new SearchResultList<>(new ArrayList<>()); @@ -883,7 +886,7 @@ private class ContainerOperationContext { @Override public SearchResultList searchContainers( - Class type, ObjectQuery query, Collection> options, + Class type, ObjectQuery query, Collection> rawOptions, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException { Validate.notNull(type, "Container value type must not be null."); @@ -894,6 +897,7 @@ public SearchResultList searchContainers( final ContainerOperationContext ctx = new ContainerOperationContext<>(type, query); + Collection> options = preProcessOptionsSecurity(rawOptions); final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); final OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); @@ -959,7 +963,7 @@ public SearchResultList searchContainers( @Override public Integer countContainers( - Class type, ObjectQuery query, Collection> options, + Class type, ObjectQuery query, Collection> rawOptions, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException { Validate.notNull(type, "Container value type must not be null."); @@ -967,6 +971,7 @@ public Integer countContainers( final ContainerOperationContext ctx = new ContainerOperationContext<>(type, query); + final Collection> options = preProcessOptionsSecurity(rawOptions); final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); final OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); @@ -1062,7 +1067,7 @@ protected void logQuery(ObjectQuery query) { @Override public SearchResultMetadata searchObjectsIterative(Class type, ObjectQuery query, - final ResultHandler handler, final Collection> options, + final ResultHandler handler, final Collection> rawOptions, final Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { Validate.notNull(type, "Object type must not be null."); @@ -1071,7 +1076,8 @@ public SearchResultMetadata searchObjectsIterative(Class< ModelUtils.validatePaging(query.getPaging()); } - final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + final Collection> options = preProcessOptionsSecurity(rawOptions); + final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); ObjectTypes.ObjectManager searchProvider = ObjectTypes.getObjectManagerForClass(type); if (searchProvider == null || searchProvider == ObjectTypes.ObjectManager.MODEL || GetOperationOptions.isRaw(rootOptions)) { searchProvider = ObjectTypes.ObjectManager.REPOSITORY; @@ -1151,7 +1157,7 @@ private void processSearchException(Throwable e, GetOperationOptions rootOptions @Override public Integer countObjects(Class type, ObjectQuery query, - Collection> options, Task task, OperationResult parentResult) + Collection> rawOptions, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException, CommunicationException, ExpressionEvaluationException { OperationResult result = parentResult.createMinorSubresult(COUNT_OBJECTS); @@ -1167,6 +1173,7 @@ public Integer countObjects(Class type, ObjectQuery qu try { RepositoryCache.enter(); + Collection> options = preProcessOptionsSecurity(rawOptions); GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); ObjectTypes.ObjectManager objectManager = ObjectTypes.getObjectManagerForClass(type); @@ -1248,7 +1255,7 @@ public PrismObject findShadowOwner(String accountOid, Task task, Opera } @Override - public PrismObject searchShadowOwner(String shadowOid, Collection> options, Task task, OperationResult parentResult) + public PrismObject searchShadowOwner(String shadowOid, Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SecurityViolationException, SchemaException, ConfigurationException { Validate.notEmpty(shadowOid, "Account oid must not be null or empty."); Validate.notNull(parentResult, "Result type must not be null."); @@ -1263,7 +1270,7 @@ public PrismObject searchShadowOwner(String shadowOid, Coll result.addParams(new String[] { "accountOid" }, shadowOid); try { - + Collection> options = preProcessOptionsSecurity(rawOptions); focus = cacheRepositoryService.searchShadowOwner(shadowOid, options, result); result.recordSuccess(); } catch (RuntimeException | Error ex) { @@ -1592,7 +1599,7 @@ public void postInit(OperationResult parentResult) { @Override public CompareResultType compareObject(PrismObject provided, - Collection> readOptions, ModelCompareOptions compareOptions, + Collection> rawReadOptions, ModelCompareOptions compareOptions, @NotNull List ignoreItems, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { @@ -1602,10 +1609,12 @@ public CompareResultType compareObject(PrismObject pro OperationResult result = parentResult.createMinorSubresult(COMPARE_OBJECT); result.addParam("oid", provided.getOid()); result.addParam("name", provided.getName()); - result.addCollectionOfSerializablesAsParam("readOptions", readOptions); + result.addCollectionOfSerializablesAsParam("readOptions", rawReadOptions); result.addParam("compareOptions", compareOptions); result.addCollectionOfSerializablesAsParam("ignoreItems", ignoreItems); + Collection> readOptions = preProcessOptionsSecurity(rawReadOptions); + CompareResultType rv = new CompareResultType(); try { @@ -1720,6 +1729,19 @@ private void removeOperationalItems(PrismObject object removeIgnoredItems(object, operationalItems); } + private Collection> preProcessOptionsSecurity(Collection> options) + throws SchemaException { + GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + if (GetOperationOptions.isAttachDiagData(rootOptions) && + !securityEnforcer.isAuthorized(AuthorizationConstants.AUTZ_ALL_URL, null, null, null, null, null)) { + Collection> reducedOptions = CloneUtil.cloneCollectionMembers(options); + SelectorOptions.findRootOptions(reducedOptions).setAttachDiagData(false); + return reducedOptions; + } else { + return options; + } + } + private ObjectQuery preProcessQuerySecurity(Class objectType, ObjectQuery origQuery) throws SchemaException { ObjectFilter origFilter = null; if (origQuery != null) { @@ -1792,7 +1814,8 @@ public void scheduleTasksNow(Collection taskOids, OperationResult parent } @Override - public PrismObject getTaskByIdentifier(String identifier, Collection> options, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException { + public PrismObject getTaskByIdentifier(String identifier, Collection> rawOptions, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ConfigurationException, SecurityViolationException { + Collection> options = preProcessOptionsSecurity(rawOptions); PrismObject task = taskManager.getTaskTypeByIdentifier(identifier, options, parentResult); GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); task = task.cloneIfImmutable(); @@ -1991,13 +2014,15 @@ public void recordDecision(String campaignOid, long caseId, long workItemId, Acc @Deprecated @Override - public List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException { + public List searchOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException { + Collection> options = preProcessOptionsSecurity(rawOptions); return getCertificationManagerChecked().searchOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, options, task, parentResult); } @Deprecated @Override - public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, Collection> options, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException { + public int countOpenWorkItems(ObjectQuery baseWorkItemsQuery, boolean notDecidedOnly, Collection> rawOptions, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, SecurityViolationException { + Collection> options = preProcessOptionsSecurity(rawOptions); return getCertificationManagerChecked().countOpenWorkItems(baseWorkItemsQuery, notDecidedOnly, options, task, parentResult); } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java index 4934f237bbe..c5a4b2f8136 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/SchemaTransformer.java @@ -15,57 +15,35 @@ */ package com.evolveum.midpoint.model.impl.controller; -import java.util.*; - -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.schema.SearchResultList; -import com.evolveum.midpoint.schema.internals.InternalsConfig; -import com.evolveum.midpoint.schema.util.ObjectTypeUtil; -import org.apache.commons.lang.Validate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - import com.evolveum.midpoint.common.crypto.CryptoUtil; import com.evolveum.midpoint.model.api.ModelAuthorizationAction; import com.evolveum.midpoint.model.common.SystemObjectCache; -import com.evolveum.midpoint.model.impl.util.Utils; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.xml.XsdTypeMapper; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.internals.InternalsConfig; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.security.api.ObjectSecurityConstraints; import com.evolveum.midpoint.security.api.SecurityEnforcer; import com.evolveum.midpoint.security.api.SecurityUtil; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.AuthorizationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationDecisionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AuthorizationPhaseType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.LayerType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectPolicyConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateItemDefinitionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PropertyAccessType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PropertyLimitationsType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ReportType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; +import org.apache.commons.lang.Validate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; import javax.xml.namespace.QName; +import java.util.*; /** * Transforms the schema and objects by applying security constraints, diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectInfo.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectInfo.java new file mode 100644 index 00000000000..5521ba17745 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectInfo.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.integrity; + +import com.evolveum.midpoint.prism.polystring.PolyString; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +/** + * TODO better name? + * @author mederly + */ +public class ObjectInfo { + private String oid; + private String name; + + public ObjectInfo(ObjectType object) { + oid = object.getOid(); + name = PolyString.getOrig(object.getName()); + } + + public String getOid() { + return oid; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return name + "(" + oid + ")"; + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectIntegrityCheckResultHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectIntegrityCheckResultHandler.java new file mode 100644 index 00000000000..6f33264a692 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectIntegrityCheckResultHandler.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.integrity; + +import com.evolveum.midpoint.model.common.SystemObjectCache; +import com.evolveum.midpoint.model.impl.util.AbstractSearchIterativeResultHandler; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.util.exception.CommonException; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +import java.util.Map; + +/** + * @author mederly + */ +public class ObjectIntegrityCheckResultHandler extends AbstractSearchIterativeResultHandler { + + private static final Trace LOGGER = TraceManager.getTrace(ObjectIntegrityCheckResultHandler.class); + + private static final String CLASS_DOT = ObjectIntegrityCheckResultHandler.class.getName() + "."; + private static final int HISTOGRAM_COLUMNS = 80; + + private PrismContext prismContext; + private RepositoryService repositoryService; + private SystemObjectCache systemObjectCache; + + private ObjectStatistics statistics = new ObjectStatistics(); + + public ObjectIntegrityCheckResultHandler(Task coordinatorTask, String taskOperationPrefix, String processShortName, + String contextDesc, TaskManager taskManager, PrismContext prismContext, RepositoryService repositoryService, + SystemObjectCache systemObjectCache, OperationResult result) { + super(coordinatorTask, taskOperationPrefix, processShortName, contextDesc, taskManager); + this.prismContext = prismContext; + this.repositoryService = repositoryService; + this.systemObjectCache = systemObjectCache; + setStopOnError(false); + setLogErrors(false); // we do log errors ourselves + + Integer tasks = getWorkerThreadsCount(coordinatorTask); + if (tasks != null && tasks != 0) { + throw new UnsupportedOperationException("Unsupported number of worker threads: " + tasks + ". This task cannot be run with worker threads. Please remove workerThreads extension property or set its value to 0."); + } + + logConfiguration("Object integrity check is starting"); + } + + private void logConfiguration(String state) { + LOGGER.info("{}", state); + } + + @Override + protected boolean handleObject(PrismObject object, Task workerTask, OperationResult parentResult) throws CommonException { + OperationResult result = parentResult.createMinorSubresult(CLASS_DOT + "handleObject"); + try { + statistics.record(object); + } catch (RuntimeException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Unexpected error while checking object {} integrity", e, ObjectTypeUtil.toShortString(object)); + result.recordPartialError("Unexpected error while checking object integrity", e); + statistics.incrementObjectsWithErrors(); + } finally { + workerTask.markObjectActionExecutedBoundary(); + } + + result.computeStatusIfUnknown(); + return true; + } + + public ObjectStatistics getStatistics() { + return statistics; + } + + @Override + public void completeProcessing(Task task, OperationResult result) { + super.completeProcessing(task, result); + logConfiguration("Object integrity check finished."); + dumpStatistics(); + } + + private void dumpStatistics() { + Map map = statistics.getStatisticsMap(); + if (map.isEmpty()) { + LOGGER.info("(no objects were found)"); + } else { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : map.entrySet()) { + sb.append("\n\n**************************************** Statistics for ").append(entry.getKey()).append(" ****************************************\n\n"); + sb.append(entry.getValue().dump(HISTOGRAM_COLUMNS)); + } + LOGGER.info("{}", sb.toString()); + } + LOGGER.info("Objects processed with errors: {}", statistics.getErrors()); + } + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectIntegrityCheckTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectIntegrityCheckTaskHandler.java new file mode 100644 index 00000000000..13bc72f23c0 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectIntegrityCheckTaskHandler.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.integrity; + +import com.evolveum.midpoint.model.api.ModelPublicConstants; +import com.evolveum.midpoint.model.common.SystemObjectCache; +import com.evolveum.midpoint.model.impl.util.AbstractSearchIterativeTaskHandler; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SelectorOptions; +import com.evolveum.midpoint.schema.result.OperationConstants; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskCategory; +import com.evolveum.midpoint.task.api.TaskRunResult; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.Collection; +import java.util.List; + +/** + * Task handler for "Object integrity check" task. + * + * The purpose of this task is to detect and optionally fix anomalies in repository objects. + * + * However, currently its only function is to display information about objects size. + * + * @author Pavol Mederly + */ +@Component +public class ObjectIntegrityCheckTaskHandler extends AbstractSearchIterativeTaskHandler { + + public static final String HANDLER_URI = ModelPublicConstants.OBJECT_INTEGRITY_CHECK_TASK_HANDLER_URI; + + // WARNING! This task handler is efficiently singleton! + // It is a spring bean and it is supposed to handle all search task instances + // Therefore it must not have task-specific fields. It can only contain fields specific to + // all tasks of a specified type + + @Autowired private SystemObjectCache systemObjectCache; + + private static final Trace LOGGER = TraceManager.getTrace(ObjectIntegrityCheckTaskHandler.class); + + public ObjectIntegrityCheckTaskHandler() { + super("Object integrity check", OperationConstants.CHECK_OBJECT_INTEGRITY); + setLogFinishInfo(true); + setPreserveStatistics(false); + } + + @PostConstruct + private void initialize() { + taskManager.registerHandler(HANDLER_URI, this); + } + + @Override + protected ObjectIntegrityCheckResultHandler createHandler(TaskRunResult runResult, Task coordinatorTask, OperationResult opResult) { + return new ObjectIntegrityCheckResultHandler(coordinatorTask, ObjectIntegrityCheckTaskHandler.class.getName(), + "check object integrity", "check object integrity", taskManager, prismContext, + repositoryService, systemObjectCache, opResult); + } + + @Override + protected boolean initializeRun(ObjectIntegrityCheckResultHandler handler, + TaskRunResult runResult, Task task, OperationResult opResult) { + return super.initializeRun(handler, runResult, task, opResult); + } + + @Override + protected Class getType(Task task) { + return ObjectType.class; + } + + @Override + protected ObjectQuery createQuery(ObjectIntegrityCheckResultHandler handler, TaskRunResult runResult, Task task, OperationResult opResult) throws SchemaException { + ObjectQuery query = createQueryFromTask(handler, runResult, task, opResult); + LOGGER.info("Using query:\n{}", query.debugDump()); + return query; + } + + @Override + protected Collection> createQueryOptions(ObjectIntegrityCheckResultHandler resultHandler, + TaskRunResult runResult, Task coordinatorTask, OperationResult opResult) { + return SelectorOptions.createCollection(GetOperationOptions.createAttachDiagData()); + } + + @Override + protected boolean useRepositoryDirectly(ObjectIntegrityCheckResultHandler resultHandler, TaskRunResult runResult, Task coordinatorTask, OperationResult opResult) { + return true; + } + + @Override + public String getCategoryName(Task task) { + return TaskCategory.UTIL; + } + + @Override + public List getCategoryNames() { + return null; + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectStatistics.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectStatistics.java new file mode 100644 index 00000000000..4c63f43ff22 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectStatistics.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.integrity; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author mederly + */ +public class ObjectStatistics { + + private int errors = 0; + private final Map statisticsMap = new HashMap<>(); // key is object class full name + + public Map getStatisticsMap() { + return statisticsMap; + } + + public int getErrors() { + return errors; + } + + public void record(PrismObject object) { + String key = object.asObjectable().getClass().getName(); + ObjectTypeStatistics typeStatistics = statisticsMap.computeIfAbsent(key, (k) -> new ObjectTypeStatistics()); + typeStatistics.register(object); + } + + public void incrementObjectsWithErrors() { + errors++; + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectTypeStatistics.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectTypeStatistics.java new file mode 100644 index 00000000000..f9520870dac --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ObjectTypeStatistics.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.integrity; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.repo.api.RepositoryObjectDiagnosticData; +import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.util.histogram.Histogram; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +/** + * @author mederly + */ +public class ObjectTypeStatistics { + + private static final Trace LOGGER = TraceManager.getTrace(ObjectTypeStatistics.class); + + private static final int SIZE_HISTOGRAM_STEP = 10000; + private static final int MAX_SIZE_HISTOGRAM_LENGTH = 100000; // corresponds to object size of 1 GB + + private final Histogram sizeHistogram = new Histogram<>(SIZE_HISTOGRAM_STEP, MAX_SIZE_HISTOGRAM_LENGTH); + + public void register(PrismObject object) { + RepositoryObjectDiagnosticData diag = (RepositoryObjectDiagnosticData) object.getUserData(RepositoryService.KEY_DIAG_DATA); + if (diag == null) { + throw new IllegalStateException("No diagnostic data in " + object); + } + ObjectInfo info = new ObjectInfo(object.asObjectable()); + long size = diag.getStoredObjectSize(); + LOGGER.trace("Found object: {}: {}", info, size); + sizeHistogram.register(info, size); + } + + public String dump(int histogramColumns) { + return sizeHistogram.dump(histogramColumns); + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ShadowIntegrityCheckResultHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ShadowIntegrityCheckResultHandler.java index 7700545a15c..e57be79131f 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ShadowIntegrityCheckResultHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ShadowIntegrityCheckResultHandler.java @@ -108,7 +108,7 @@ public class ShadowIntegrityCheckResultHandler extends AbstractSearchIterativeRe private PrismObject configuration; - private Statistics statistics = new Statistics(); + private ShadowStatistics statistics = new ShadowStatistics(); private DuplicateShadowsResolver duplicateShadowsResolver; private Set duplicateShadowsDetected = new HashSet<>(); @@ -299,15 +299,15 @@ private void checkShadow(ShadowCheckResult checkResult, PrismObject statistics.incrementShadows(); if (resourceRef == null) { - checkResult.recordError(Statistics.NO_RESOURCE_OID, new SchemaException("No resourceRef")); - fixNoResourceIfRequested(checkResult, Statistics.NO_RESOURCE_OID); + checkResult.recordError(ShadowStatistics.NO_RESOURCE_OID, new SchemaException("No resourceRef")); + fixNoResourceIfRequested(checkResult, ShadowStatistics.NO_RESOURCE_OID); applyFixes(checkResult, shadow, workerTask, result); return; } String resourceOid = resourceRef.getOid(); if (resourceOid == null) { - checkResult.recordError(Statistics.NO_RESOURCE_OID, new SchemaException("Null resource OID")); - fixNoResourceIfRequested(checkResult, Statistics.NO_RESOURCE_OID); + checkResult.recordError(ShadowStatistics.NO_RESOURCE_OID, new SchemaException("Null resource OID")); + fixNoResourceIfRequested(checkResult, ShadowStatistics.NO_RESOURCE_OID); applyFixes(checkResult, shadow, workerTask, result); return; } @@ -317,15 +317,17 @@ private void checkShadow(ShadowCheckResult checkResult, PrismObject try { resource = provisioningService.getObject(ResourceType.class, resourceOid, null, workerTask, result); } catch (ObjectNotFoundException e) { - checkResult.recordError(Statistics.NO_RESOURCE, new ObjectNotFoundException("Resource object does not exist: " + e.getMessage(), e)); - fixNoResourceIfRequested(checkResult, Statistics.NO_RESOURCE); + checkResult.recordError( + ShadowStatistics.NO_RESOURCE, new ObjectNotFoundException("Resource object does not exist: " + e.getMessage(), e)); + fixNoResourceIfRequested(checkResult, ShadowStatistics.NO_RESOURCE); applyFixes(checkResult, shadow, workerTask, result); return; } catch (SchemaException e) { - checkResult.recordError(Statistics.CANNOT_GET_RESOURCE, new SchemaException("Resource object has schema problems: " + e.getMessage(), e)); + checkResult.recordError( + ShadowStatistics.CANNOT_GET_RESOURCE, new SchemaException("Resource object has schema problems: " + e.getMessage(), e)); return; } catch (CommonException|RuntimeException e) { - checkResult.recordError(Statistics.CANNOT_GET_RESOURCE, new SystemException("Resource object cannot be fetched for some reason: " + e.getMessage(), e)); + checkResult.recordError(ShadowStatistics.CANNOT_GET_RESOURCE, new SystemException("Resource object cannot be fetched for some reason: " + e.getMessage(), e)); return; } resources.put(resourceOid, resource); @@ -335,7 +337,7 @@ private void checkShadow(ShadowCheckResult checkResult, PrismObject ShadowKindType kind = shadowType.getKind(); if (kind == null) { // TODO or simply assume account? - checkResult.recordError(Statistics.NO_KIND_SPECIFIED, new SchemaException("No kind specified")); + checkResult.recordError(ShadowStatistics.NO_KIND_SPECIFIED, new SchemaException("No kind specified")); return; } @@ -356,22 +358,22 @@ private void checkShadow(ShadowCheckResult checkResult, PrismObject if (owners != null) { shadow.setUserData(KEY_OWNERS, owners); if (owners.size() > 1) { - checkResult.recordError(Statistics.MULTIPLE_OWNERS, new SchemaException("Multiple owners: " + owners)); + checkResult.recordError(ShadowStatistics.MULTIPLE_OWNERS, new SchemaException("Multiple owners: " + owners)); } } if (shadowType.getSynchronizationSituation() == SynchronizationSituationType.LINKED && (owners == null || owners.isEmpty())) { - checkResult.recordError(Statistics.LINKED_WITH_NO_OWNER, new SchemaException("Linked shadow with no owner")); + checkResult.recordError(ShadowStatistics.LINKED_WITH_NO_OWNER, new SchemaException("Linked shadow with no owner")); } if (shadowType.getSynchronizationSituation() != SynchronizationSituationType.LINKED && owners != null && !owners.isEmpty()) { - checkResult.recordError(Statistics.NOT_LINKED_WITH_OWNER, new SchemaException("Shadow with an owner but not marked as linked (marked as " + checkResult.recordError(ShadowStatistics.NOT_LINKED_WITH_OWNER, new SchemaException("Shadow with an owner but not marked as linked (marked as " + shadowType.getSynchronizationSituation() + ")")); } } String intent = shadowType.getIntent(); if (checkIntents && (intent == null || intent.isEmpty())) { - checkResult.recordWarning(Statistics.NO_INTENT_SPECIFIED, "None or empty intent"); + checkResult.recordWarning(ShadowStatistics.NO_INTENT_SPECIFIED, "None or empty intent"); } if (fixIntents && (intent == null || intent.isEmpty())) { doFixIntent(checkResult, fetchedShadow, shadow, resource, workerTask, result); @@ -386,17 +388,18 @@ private void checkShadow(ShadowCheckResult checkResult, PrismObject try { resourceSchema = RefinedResourceSchemaImpl.getRefinedSchema(context.getResource(), LayerType.MODEL, prismContext); } catch (SchemaException e) { - checkResult.recordError(Statistics.CANNOT_GET_REFINED_SCHEMA, new SchemaException("Couldn't derive resource schema: " + e.getMessage(), e)); + checkResult.recordError( + ShadowStatistics.CANNOT_GET_REFINED_SCHEMA, new SchemaException("Couldn't derive resource schema: " + e.getMessage(), e)); return; } if (resourceSchema == null) { - checkResult.recordError(Statistics.NO_RESOURCE_REFINED_SCHEMA, new SchemaException("No resource schema")); + checkResult.recordError(ShadowStatistics.NO_RESOURCE_REFINED_SCHEMA, new SchemaException("No resource schema")); return; } context.setObjectClassDefinition(resourceSchema.getRefinedDefinition(kind, shadowType)); if (context.getObjectClassDefinition() == null) { // TODO or warning only? - checkResult.recordError(Statistics.NO_OBJECT_CLASS_REFINED_SCHEMA, new SchemaException("No refined object class definition for kind=" + kind + ", intent=" + intent)); + checkResult.recordError(ShadowStatistics.NO_OBJECT_CLASS_REFINED_SCHEMA, new SchemaException("No refined object class definition for kind=" + kind + ", intent=" + intent)); return; } contextMap.put(key, context); @@ -405,7 +408,8 @@ private void checkShadow(ShadowCheckResult checkResult, PrismObject try { provisioningService.applyDefinition(shadow, workerTask, result); } catch (SchemaException|ObjectNotFoundException|CommunicationException|ConfigurationException|ExpressionEvaluationException e) { - checkResult.recordError(Statistics.OTHER_FAILURE, new SystemException("Couldn't apply definition to shadow from repo", e)); + checkResult.recordError( + ShadowStatistics.OTHER_FAILURE, new SystemException("Couldn't apply definition to shadow from repo", e)); return; } @@ -417,25 +421,26 @@ private void checkShadow(ShadowCheckResult checkResult, PrismObject PrismContainer attributesContainer = shadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer == null) { // might happen on unfinished shadows? - checkResult.recordError(Statistics.OTHER_FAILURE, new SchemaException("No attributes container")); + checkResult.recordError(ShadowStatistics.OTHER_FAILURE, new SchemaException("No attributes container")); return; } for (RefinedAttributeDefinition identifier : identifiers) { PrismProperty property = attributesContainer.getValue().findProperty(identifier.getName()); if (property == null || property.size() == 0) { - checkResult.recordWarning(Statistics.OTHER_FAILURE, "No value for identifier " + identifier.getName()); + checkResult.recordWarning(ShadowStatistics.OTHER_FAILURE, "No value for identifier " + identifier.getName()); continue; } if (property.size() > 1) { // we don't expect multi-valued identifiers - checkResult.recordError(Statistics.OTHER_FAILURE, new SchemaException("Multi-valued identifier " + identifier.getName() + " with values " + property.getValues())); + checkResult.recordError( + ShadowStatistics.OTHER_FAILURE, new SchemaException("Multi-valued identifier " + identifier.getName() + " with values " + property.getValues())); continue; } // size == 1 String value = (String) property.getValue().getValue(); if (value == null) { - checkResult.recordWarning(Statistics.OTHER_FAILURE, "Null value for identifier " + identifier.getName()); + checkResult.recordWarning(ShadowStatistics.OTHER_FAILURE, "Null value for identifier " + identifier.getName()); continue; } if (checkUniqueness) { @@ -458,7 +463,7 @@ private void applyFixes(ShadowCheckResult checkResult, PrismObject s applyFix(checkResult, shadow, workerTask, result); checkResult.setFixApplied(true); } catch (CommonException e) { - checkResult.recordError(Statistics.CANNOT_APPLY_FIX, new SystemException("Couldn't apply the shadow fix", e)); + checkResult.recordError(ShadowStatistics.CANNOT_APPLY_FIX, new SystemException("Couldn't apply the shadow fix", e)); } } } @@ -492,7 +497,7 @@ private PrismObject fetchShadow(ShadowCheckResult checkResult, Prism SelectorOptions.createCollection(GetOperationOptions.createDoNotDiscovery()), task, result); } catch (ObjectNotFoundException | CommunicationException | SchemaException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error e) { - checkResult.recordError(Statistics.CANNOT_FETCH_RESOURCE_OBJECT, new SystemException("The resource object couldn't be fetched", e)); + checkResult.recordError(ShadowStatistics.CANNOT_FETCH_RESOURCE_OBJECT, new SystemException("The resource object couldn't be fetched", e)); return null; } } @@ -506,7 +511,7 @@ private void doFixIntent(ShadowCheckResult checkResult, PrismObject fullShadow = fetchedShadow; } if (fullShadow == null) { - checkResult.recordError(Statistics.CANNOT_APPLY_FIX, new SystemException("Cannot fix missing intent, because the resource object couldn't be fetched")); + checkResult.recordError(ShadowStatistics.CANNOT_APPLY_FIX, new SystemException("Cannot fix missing intent, because the resource object couldn't be fetched")); return; } @@ -514,7 +519,7 @@ private void doFixIntent(ShadowCheckResult checkResult, PrismObject try { synchronizationPolicy = synchronizationService.determineSynchronizationPolicy(resource.asObjectable(), fullShadow, configuration, task, result); } catch (SchemaException|ObjectNotFoundException|ExpressionEvaluationException|RuntimeException e) { - checkResult.recordError(Statistics.CANNOT_APPLY_FIX, new SystemException("Couldn't prepare fix for missing intent, because the synchronization policy couldn't be determined", e)); + checkResult.recordError(ShadowStatistics.CANNOT_APPLY_FIX, new SystemException("Couldn't prepare fix for missing intent, because the synchronization policy couldn't be determined", e)); return; } if (synchronizationPolicy != null) { @@ -523,7 +528,7 @@ private void doFixIntent(ShadowCheckResult checkResult, PrismObject if (LOGGER.isTraceEnabled()) { LOGGER.trace("Intent fix delta (not executed now) = \n{}", delta.debugDump()); } - checkResult.addFixDelta(delta, Statistics.NO_INTENT_SPECIFIED); + checkResult.addFixDelta(delta, ShadowStatistics.NO_INTENT_SPECIFIED); } else { LOGGER.info("Synchronization policy does not contain intent: {}", synchronizationPolicy); } @@ -570,14 +575,16 @@ private void doCheckNormalization(ShadowCheckResult checkResult, RefinedAttribut try { matchingRule = matchingRuleRegistry.getMatchingRule(matchingRuleQName, identifier.getTypeName()); } catch (SchemaException e) { - checkResult.recordError(Statistics.OTHER_FAILURE, new SchemaException("Couldn't retrieve matching rule for identifier " + + checkResult.recordError( + ShadowStatistics.OTHER_FAILURE, new SchemaException("Couldn't retrieve matching rule for identifier " + identifier.getName() + " (rule name = " + matchingRuleQName + ")")); return; } Object normalizedValue = matchingRule.normalize(value); if (!(normalizedValue instanceof String)) { - checkResult.recordError(Statistics.OTHER_FAILURE, new SchemaException("Normalized value is not a string, it's " + normalizedValue.getClass() + + checkResult.recordError( + ShadowStatistics.OTHER_FAILURE, new SchemaException("Normalized value is not a string, it's " + normalizedValue.getClass() + " (identifier " + identifier.getName() + ", value " + value)); return; } @@ -586,14 +593,14 @@ private void doCheckNormalization(ShadowCheckResult checkResult, RefinedAttribut } String normalizedStringValue = (String) normalizedValue; - checkResult.recordError(Statistics.NON_NORMALIZED_IDENTIFIER_VALUE, + checkResult.recordError(ShadowStatistics.NON_NORMALIZED_IDENTIFIER_VALUE, new SchemaException("Non-normalized value of identifier " + identifier.getName() + ": " + value + " (normalized form: " + normalizedValue + ")")); if (fixNormalization) { PropertyDelta delta = identifier.createEmptyDelta(new ItemPath(ShadowType.F_ATTRIBUTES, identifier.getName())); delta.setValueToReplace(new PrismPropertyValue<>(normalizedStringValue)); - checkResult.addFixDelta(delta, Statistics.NON_NORMALIZED_IDENTIFIER_VALUE); + checkResult.addFixDelta(delta, ShadowStatistics.NON_NORMALIZED_IDENTIFIER_VALUE); } } @@ -631,7 +638,7 @@ private void addIdentifierValue(ShadowCheckResult checkResult, ObjectTypeContext // return sb.toString(); // } - public Statistics getStatistics() { + public ShadowStatistics getStatistics() { return statistics; } @@ -838,10 +845,10 @@ private void checkOrFixActivationItem(ShadowCheckResult checkResult, PrismObject if (property == null || property.isEmpty()) { return; } - checkResult.recordWarning(Statistics.EXTRA_ACTIVATION_DATA, "Unexpected activation item: " + property); + checkResult.recordWarning(ShadowStatistics.EXTRA_ACTIVATION_DATA, "Unexpected activation item: " + property); if (fixExtraData) { PropertyDelta delta = PropertyDelta.createReplaceEmptyDelta(shadow.getDefinition(), new ItemPath(ShadowType.F_ACTIVATION, itemName)); - checkResult.addFixDelta(delta, Statistics.EXTRA_ACTIVATION_DATA); + checkResult.addFixDelta(delta, ShadowStatistics.EXTRA_ACTIVATION_DATA); } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/Statistics.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ShadowStatistics.java similarity index 99% rename from model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/Statistics.java rename to model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ShadowStatistics.java index 58d6207e262..13c5c05d5b5 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/Statistics.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/integrity/ShadowStatistics.java @@ -28,7 +28,7 @@ * * @author Pavol Mederly */ -public class Statistics { +public class ShadowStatistics { public static final String NON_NORMALIZED_IDENTIFIER_VALUE = "Non-normalized identifier value"; public static final String DUPLICATE_SHADOWS = "Duplicate shadows"; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractSearchIterativeTaskHandler.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractSearchIterativeTaskHandler.java index ea6b35b3b62..81ee1c331cb 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractSearchIterativeTaskHandler.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/util/AbstractSearchIterativeTaskHandler.java @@ -286,7 +286,7 @@ public TaskRunResult runInternal(Task coordinatorTask) { if (!useRepository) { modelObjectResolver.searchIterative((Class) type, query, queryOptions, resultHandler, coordinatorTask, opResult); } else { - repositoryService.searchObjectsIterative(type, query, (ResultHandler) resultHandler, null, false, opResult); // TODO think about this + repositoryService.searchObjectsIterative(type, query, (ResultHandler) resultHandler, queryOptions, false, opResult); // TODO think about this } resultHandler.completeProcessing(coordinatorTask, opResult); diff --git a/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/RepositoryObjectDiagnosticData.java b/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/RepositoryObjectDiagnosticData.java new file mode 100644 index 00000000000..7315103adea --- /dev/null +++ b/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/RepositoryObjectDiagnosticData.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2010-2017 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.repo.api; + +/** + * @author mederly + */ +public class RepositoryObjectDiagnosticData { + + private long storedObjectSize; + + public RepositoryObjectDiagnosticData(long storedObjectSize) { + this.storedObjectSize = storedObjectSize; + } + + public long getStoredObjectSize() { + return storedObjectSize; + } + + public void setStoredObjectSize(long storedObjectSize) { + this.storedObjectSize = storedObjectSize; + } +} diff --git a/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/RepositoryService.java b/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/RepositoryService.java index 2aff7d0eddd..ad85fb0bdd5 100644 --- a/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/RepositoryService.java +++ b/repo/repo-api/src/main/java/com/evolveum/midpoint/repo/api/RepositoryService.java @@ -140,6 +140,8 @@ public interface RepositoryService { String RETURN_UNUSED_VALUES_TO_SEQUENCE = CLASS_NAME_WITH_DOT + "returnUnusedValuesToSequence"; String EXECUTE_QUERY_DIAGNOSTICS = CLASS_NAME_WITH_DOT + "executeQueryDiagnostics"; + String KEY_DIAG_DATA = "repositoryDiagData"; // see GetOperationOptions.attachDiagData + /** * Returns object for provided OID. * diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/CertificationCaseHelper.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/CertificationCaseHelper.java index 05ba4aa4220..02a671a4f1f 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/CertificationCaseHelper.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/CertificationCaseHelper.java @@ -278,6 +278,7 @@ private void updateCasesContent(Session session, String campaignOid, Collection< if (RepoModifyOptions.isExecuteIfNoChanges(modifyOptions)) { Query query = session.getNamedQuery("get.campaignCases"); query.setString("ownerOid", campaignOid); + @SuppressWarnings({"raw", "unchecked"}) List cases = query.list(); for (Object o : cases) { if (!(o instanceof byte[])) { @@ -319,7 +320,8 @@ public AccessCertificationCaseType updateLoadedCertificationCase(GetContainerabl Collection> options, Session session, OperationResult operationResult) throws SchemaException { - AccessCertificationCaseType aCase = RAccessCertificationCase.createJaxb(result.getFullObject(), prismContext, false); + byte[] fullObject = result.getFullObject(); + AccessCertificationCaseType aCase = RAccessCertificationCase.createJaxb(fullObject, prismContext, false); generalHelper.validateContainerable(aCase, AccessCertificationCaseType.class); String ownerOid = result.getOwnerOid(); @@ -327,7 +329,8 @@ public AccessCertificationCaseType updateLoadedCertificationCase(GetContainerabl if (campaign != null && !campaign.asObjectable().getCase().contains(aCase)) { campaign.asObjectable().getCase().add(aCase); } - return aCase; + objectRetriever.attachDiagDataIfRequested(aCase.asPrismContainerValue(), fullObject, options); + return aCase; } public AccessCertificationWorkItemType updateLoadedCertificationWorkItem(GetCertificationWorkItemResult result, @@ -347,6 +350,7 @@ public AccessCertificationWorkItemType updateLoadedCertificationWorkItem(GetCert .and().id(caseId) .build(); RQuery caseQuery = engine.interpret(query, AccessCertificationCaseType.class, null, false, session); + @SuppressWarnings({"raw", "unchecked"}) List cases = caseQuery.list(); if (cases.size() > 1) { throw new IllegalStateException( @@ -355,6 +359,7 @@ public AccessCertificationWorkItemType updateLoadedCertificationWorkItem(GetCert // we need it, because otherwise we have only identifiers for the work item, no data throw new IllegalStateException("No certification case found for campaign " + campaignOid + ", ID " + caseId); } + // TODO really use options of 'null' ? AccessCertificationCaseType _case = updateLoadedCertificationCase(cases.get(0), campaignsCache, null, session, operationResult); casePcv = _case.asPrismContainerValue(); casesCache.put(caseKey, casePcv); @@ -399,6 +404,7 @@ public void updateLoadedCampaign(PrismObject object, criteria.add(Restrictions.eq("ownerOid", object.getOid())); // TODO fetch only XML representation + @SuppressWarnings({"raw", "unchecked"}) List cases = criteria.list(); if (cases == null || cases.isEmpty()) { return; diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/ObjectRetriever.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/ObjectRetriever.java index 21cd5ae1726..cf1199c766d 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/ObjectRetriever.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/ObjectRetriever.java @@ -21,6 +21,7 @@ import com.evolveum.midpoint.prism.marshaller.XNodeProcessorEvaluationMode; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.repo.api.RepositoryObjectDiagnosticData; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.repo.sql.ObjectPagingAfterOid; import com.evolveum.midpoint.repo.sql.SqlRepositoryConfiguration; @@ -57,6 +58,8 @@ import javax.xml.namespace.QName; import java.util.*; +import static org.apache.commons.lang3.ArrayUtils.getLength; + /** * @author lazyman, mederly */ @@ -69,28 +72,17 @@ public class ObjectRetriever { private static final Trace LOGGER = TraceManager.getTrace(ObjectRetriever.class); private static final Trace LOGGER_PERFORMANCE = TraceManager.getTrace(SqlRepositoryServiceImpl.PERFORMANCE_LOG_NAME); - @Autowired - @Qualifier("repositoryService") - private RepositoryService repositoryService; - - @Autowired - private LookupTableHelper lookupTableHelper; - - @Autowired - private CertificationCaseHelper caseHelper; - - @Autowired - private BaseHelper baseHelper; - - @Autowired - private NameResolutionHelper nameResolutionHelper; - - @Autowired - private PrismContext prismContext; + @Autowired private LookupTableHelper lookupTableHelper; + @Autowired private CertificationCaseHelper caseHelper; + @Autowired private BaseHelper baseHelper; + @Autowired private NameResolutionHelper nameResolutionHelper; + @Autowired private PrismContext prismContext; + @Autowired + @Qualifier("repositoryService") + private RepositoryService repositoryService; public PrismObject getObjectAttempt(Class type, String oid, - Collection> options, - OperationResult result) + Collection> options, OperationResult result) throws ObjectNotFoundException, SchemaException { LOGGER_PERFORMANCE.debug("> get object {}, oid={}", type.getSimpleName(), oid); PrismObject objectType = null; @@ -232,17 +224,15 @@ public PrismObject searchShadowOwnerAttempt(String shad query.setString("oid", shadowOid); query.setResultTransformer(GetObjectResult.RESULT_STYLE.getResultTransformer()); - List focuses = query.list(); + @SuppressWarnings({"unchecked", "raw"}) + List focuses = query.list(); LOGGER.trace("Found {} focuses, transforming data to JAXB types.", focuses != null ? focuses.size() : 0); if (focuses == null || focuses.isEmpty()) { // account shadow owner was not found return null; - } - - if (focuses.size() > 1) { - LOGGER.warn("Found {} owners for shadow oid {}, returning first owner.", - new Object[]{focuses.size(), shadowOid}); + } else if (focuses.size() > 1) { + LOGGER.warn("Found {} owners for shadow oid {}, returning first owner.", focuses.size(), shadowOid); } GetObjectResult focus = focuses.get(0); @@ -270,7 +260,8 @@ public PrismObject listAccountShadowOwnerAttempt(String accountOid, Op query.setString("oid", accountOid); query.setResultTransformer(GetObjectResult.RESULT_STYLE.getResultTransformer()); - List users = query.list(); + @SuppressWarnings({"unchecked", "raw"}) + List users = query.list(); LOGGER.trace("Found {} users, transforming data to JAXB types.", users != null ? users.size() : 0); if (users == null || users.isEmpty()) { @@ -376,7 +367,8 @@ public SearchResultList> searchObjectsAtte QueryEngine2 engine = new QueryEngine2(getConfiguration(), prismContext); rQuery = engine.interpret(query, type, options, false, session); - List queryResult = rQuery.list(); + @SuppressWarnings({"unchecked", "raw"}) + List queryResult = rQuery.list(); LOGGER.trace("Found {} objects, translating to JAXB.", queryResult != null ? queryResult.size() : 0); List> list = queryResultToPrismObjects(queryResult, type, options, session, result); @@ -439,6 +431,7 @@ public SearchResultList searchContainersAttempt(Cla RQuery rQuery = engine.interpret(query, type, options, false, session); if (cases) { + @SuppressWarnings({"unchecked", "raw"}) List items = rQuery.list(); LOGGER.trace("Found {} items (cases), translating to JAXB.", items.size()); Map> campaignsCache = new HashMap<>(); @@ -449,6 +442,7 @@ public SearchResultList searchContainersAttempt(Cla } } else { assert workItems; + @SuppressWarnings({"unchecked", "raw"}) List items = rQuery.list(); LOGGER.trace("Found {} work items, translating to JAXB.", items.size()); Map> casesCache = new HashMap<>(); @@ -482,7 +476,8 @@ private PrismObject updateLoadedObject(GetObjectResult Holder> partialValueHolder, Session session, OperationResult operationResult) throws SchemaException { - String xml = RUtil.getXmlFromByteArray(result.getFullObject(), getConfiguration().isUseZip()); + byte[] fullObject = result.getFullObject(); + String xml = RUtil.getXmlFromByteArray(fullObject, getConfiguration().isUseZip()); PrismObject prismObject; try { // "Postel mode": be tolerant what you read. We need this to tolerate (custom) schema changes @@ -501,7 +496,7 @@ private PrismObject updateLoadedObject(GetObjectResult type.getSimpleName(), oid, e.getClass().getName(), e.getMessage(), xml, e); throw e; } - + attachDiagDataIfRequested(prismObject, fullObject, options); if (FocusType.class.isAssignableFrom(prismObject.getCompileTimeClass())) { if (SelectorOptions.hasToLoadPath(FocusType.F_JPEG_PHOTO, options)) { //todo improve, use user.hasPhoto flag and take options into account [lazyman] @@ -557,7 +552,8 @@ private void applyShadowAttributeDefinitions(Class anyValue query.setParameter("oid", object.getOid()); query.setParameter("ownerType", RObjectExtensionType.ATTRIBUTES); - List values = query.list(); + @SuppressWarnings({"unchecked", "raw"}) + List values = query.list(); if (values == null || values.isEmpty()) { return; } @@ -578,7 +574,7 @@ private void applyShadowAttributeDefinitions(Class anyValue if (item.getDefinition() == null) { RValueType rValType = (RValueType) value[2]; if (rValType == RValueType.PROPERTY) { - PrismPropertyDefinition def = new PrismPropertyDefinitionImpl(name, type, object.getPrismContext()); + PrismPropertyDefinition def = new PrismPropertyDefinitionImpl<>(name, type, object.getPrismContext()); item.applyDefinition(def, true); } else if (rValType == RValueType.REFERENCE) { PrismReferenceDefinition def = new PrismReferenceDefinitionImpl(name, type, object.getPrismContext()); @@ -604,7 +600,8 @@ public List> listResourceObjectShadowsAtte query.setString("oid", resourceOid); query.setResultTransformer(GetObjectResult.RESULT_STYLE.getResultTransformer()); - List shadows = query.list(); + @SuppressWarnings({"unchecked", "raw"}) + List shadows = query.list(); LOGGER.debug("Query returned {} shadows, transforming to JAXB types.", shadows != null ? shadows.size() : 0); if (shadows != null) { @@ -905,4 +902,16 @@ public RepositoryQueryDiagResponse executeQueryDiagnosticsRequest(RepositoryQuer baseHelper.cleanupSessionAndResult(session, result); } } + + void attachDiagDataIfRequested(PrismValue value, byte[] fullObject, Collection> options) { + if (GetOperationOptions.isAttachDiagData(SelectorOptions.findRootOptions(options))) { + value.setUserData(RepositoryService.KEY_DIAG_DATA, new RepositoryObjectDiagnosticData(getLength(fullObject))); + } + } + + private void attachDiagDataIfRequested(Item item, byte[] fullObject, Collection> options) { + if (GetOperationOptions.isAttachDiagData(SelectorOptions.findRootOptions(options))) { + item.setUserData(RepositoryService.KEY_DIAG_DATA, new RepositoryObjectDiagnosticData(getLength(fullObject))); + } + } } diff --git a/samples/tasks/task-check-object-integrity.xml b/samples/tasks/task-check-object-integrity.xml new file mode 100644 index 00000000000..18cf0777db9 --- /dev/null +++ b/samples/tasks/task-check-object-integrity.xml @@ -0,0 +1,32 @@ + + + + + Object size check + + + + + + + runnable + http://midpoint.evolveum.com/xml/ns/public/model/object-integrity-check/handler-3 + single + \ No newline at end of file