diff --git a/dist/javadoc/pom.xml b/dist/javadoc/pom.xml index d31a73f9253..d3e75596994 100644 --- a/dist/javadoc/pom.xml +++ b/dist/javadoc/pom.xml @@ -57,7 +57,9 @@ maven-javadoc-plugin + ${maven-javadoc-plugin.version} + ${project.source.version} true true @@ -104,8 +106,8 @@ - org.apache.maven.plugins maven-javadoc-plugin + ${maven-javadoc-plugin.version} javadoc-jar diff --git a/dist/midpoint-api/pom.xml b/dist/midpoint-api/pom.xml index 82d76970773..6435c28efde 100644 --- a/dist/midpoint-api/pom.xml +++ b/dist/midpoint-api/pom.xml @@ -79,7 +79,9 @@ maven-javadoc-plugin + ${maven-javadoc-plugin.version} + ${project.source.version} true com.evolveum.*:* @@ -116,8 +118,8 @@ - org.apache.maven.plugins maven-javadoc-plugin + ${maven-javadoc-plugin.version} javadoc-jar diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/wrapper/ShadowWrapperFactoryImpl.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/wrapper/ShadowWrapperFactoryImpl.java index 332ed02748d..bfb6a2e6412 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/wrapper/ShadowWrapperFactoryImpl.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/factory/wrapper/ShadowWrapperFactoryImpl.java @@ -6,6 +6,11 @@ */ package com.evolveum.midpoint.gui.impl.factory.wrapper; +import com.evolveum.midpoint.gui.api.prism.wrapper.ShadowWrapper; +import com.evolveum.midpoint.util.logging.Trace; + +import com.evolveum.midpoint.util.logging.TraceManager; + import org.springframework.stereotype.Component; import com.evolveum.midpoint.gui.api.prism.ItemStatus; @@ -23,9 +28,14 @@ @Component public class ShadowWrapperFactoryImpl extends PrismObjectWrapperFactoryImpl { + private static final transient Trace LOGGER = TraceManager.getTrace(ShadowWrapperFactoryImpl.class); + @Override public PrismObjectWrapper createObjectWrapper(PrismObject object, ItemStatus status) { - return new ShadowWrapperImpl(object, status); + LOGGER.trace("create shadow wrapper"); + ShadowWrapper shadowWrapper = new ShadowWrapperImpl(object, status); + LOGGER.trace("Shadow wrapper created: {}", shadowWrapper); + return shadowWrapper; } @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/panel/ShadowPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/panel/ShadowPanel.java index 75c08c2513d..6ff9aff84b1 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/panel/ShadowPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/impl/prism/panel/ShadowPanel.java @@ -59,36 +59,47 @@ private void initLayout() { try { + long attributesStart = System.currentTimeMillis(); ItemPanelSettingsBuilder attributesSettingsBuilder = new ItemPanelSettingsBuilder() .visibilityHandler(itemWrapper -> checkShadowContainerVisibility(itemWrapper, getModel())); Panel attributesPanel = getPageBase().initItemPanel(ID_ATTRIBUTES, ShadowAttributesType.COMPLEX_TYPE, PrismContainerWrapperModel.fromContainerWrapper(getModel(), ShadowType.F_ATTRIBUTES), attributesSettingsBuilder.build()); add(attributesPanel); + long attributesEnd = System.currentTimeMillis(); + LOGGER.trace("Attributes finished in {} ms", attributesEnd - attributesStart); + long associationStart = System.currentTimeMillis(); ItemPanelSettingsBuilder associationBuilder = new ItemPanelSettingsBuilder() .visibilityHandler(itemWrapper -> checkShadowContainerVisibility(itemWrapper, getModel())); Panel associationsPanel = getPageBase().initItemPanel(ID_ASSOCIATIONS, ShadowAssociationType.COMPLEX_TYPE, PrismContainerWrapperModel.fromContainerWrapper(getModel(), ShadowType.F_ASSOCIATION), associationBuilder.build()); associationsPanel.add(new VisibleBehaviour(() -> checkAssociationsVisibility())); add(associationsPanel); + long associationEnd = System.currentTimeMillis(); + LOGGER.trace("Association finished in {} ms", associationEnd - associationStart); - + long activationStart = System.currentTimeMillis(); ItemPanelSettingsBuilder activationBuilder = new ItemPanelSettingsBuilder() .visibilityHandler(itemWrapper -> checkShadowContainerVisibility(itemWrapper, getModel())); Panel activationPanel = getPageBase().initItemPanel(ID_ACTIVATION, ActivationType.COMPLEX_TYPE, PrismContainerWrapperModel.fromContainerWrapper(getModel(), ShadowType.F_ACTIVATION), activationBuilder.build()); activationPanel.add(new VisibleBehaviour(() -> isActivationSupported())); add(activationPanel); + long activationEnd = System.currentTimeMillis(); + LOGGER.trace("Activation finished in {} ms", activationEnd - activationStart); + long passwordStart = System.currentTimeMillis(); ItemPanelSettingsBuilder passwordSettingsBuilder = new ItemPanelSettingsBuilder() .visibilityHandler(itemWrapper -> checkShadowContainerVisibility(itemWrapper, getModel())); Panel passwordPanel = getPageBase().initItemPanel(ID_PASSWORD, PasswordType.COMPLEX_TYPE, PrismContainerWrapperModel.fromContainerWrapper(getModel(), ItemPath.create(ShadowType.F_CREDENTIALS, CredentialsType.F_PASSWORD)), passwordSettingsBuilder.build()); passwordPanel.add(new VisibleBehaviour(() -> isCredentialsSupported())); add(passwordPanel); + long passwordEnd = System.currentTimeMillis(); + LOGGER.trace("Password finished in {} ms", passwordEnd - passwordStart); } catch (SchemaException e) { getSession().error("Cannot create panels for shadow, reason: " + e.getMessage()); - LOGGER.error("Cannot create panels for shadow, reason: {}", e.getMessage(), e); + LOGGER.trace("Cannot create panels for shadow, reason: {}", e.getMessage(), e); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/DropDownChoicePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/DropDownChoicePanel.java index 972458b5ed0..3afc9f23eba 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/DropDownChoicePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/DropDownChoicePanel.java @@ -29,8 +29,6 @@ public class DropDownChoicePanel extends InputPanel { private static final long serialVersionUID = 1L; private static final String ID_INPUT = "input"; - private boolean sortChoices = true; - public DropDownChoicePanel(String id, IModel model, IModel> choices) { this(id, model, choices, false); } @@ -66,16 +64,6 @@ protected String getNullValidDisplayValue() { return DropDownChoicePanel.this.getNullValidDisplayValue(); } - @Override - public IModel> getChoicesModel() { - IModel> choices = super.getChoicesModel(); - if (sortChoices) { - return Model.ofList(WebComponentUtil.sortDropDownChoices(choices, renderer)); - } else { - return choices; - } - } - @Override public String getModelValue() { T object = this.getModelObject(); @@ -108,12 +96,4 @@ public IModel getModel() { protected String getNullValidDisplayValue() { return getString("DropDownChoicePanel.notDefined"); } - - public boolean isSortChoices() { - return sortChoices; - } - - public void setSortChoices(boolean sortChoices) { - this.sortChoices = sortChoices; - } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java index f9a654282a8..e36665c2fe7 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/FocusProjectionsTabPanel.java @@ -475,27 +475,6 @@ private void addSelectedAccountPerformed(AjaxRequestTarget target, List> createEmptyShadowWrapperModel() { - ShadowType shadow = new ShadowType(); - ShadowWrapper wrapper = null; - Task task = getPageBase().createSimpleTask("create empty shadow wrapper"); - try { - getPageBase().getPrismContext().adopt(shadow); - wrapper = ((PageAdminFocus) getPage()).loadShadowWrapper(shadow.asPrismContainer(), task, task.getResult()); - } catch (SchemaException e) { - getPageBase().showResult(task.getResult(), "pageAdminFocus.message.couldntCreateShadowWrapper"); - LOGGER.error("Couldn't create shadow wrapper", e); - } - final ShadowWrapper ret = wrapper; - return new IModel>() { - - @Override - public PrismContainerWrapper getObject() { - return ret; - } - }; - } - private List createShadowMenu() { List items = new ArrayList<>(); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java index eba74e97bc5..892a0c2b455 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java @@ -136,6 +136,8 @@ public void continueEditing(AjaxRequestTarget target) { } private List loadShadowWrappers(boolean noFetch) { + LOGGER.trace("Loading shadow wrapper"); + long start = System.currentTimeMillis(); List list = new ArrayList<>(); PrismObjectWrapper focusWrapper = getObjectModel().getObject(); @@ -152,17 +154,22 @@ private List loadShadowWrappers(boolean noFetch) { LOGGER.trace("Skiping reference for shadow with null oid"); continue; // default value } + long shadowTimestampBefore = System.currentTimeMillis(); OperationResult subResult = task.getResult().createMinorSubresult(OPERATION_LOAD_SHADOW); PrismObject projection = getPrismObjectForWrapper(ShadowType.class, reference.getOid(), noFetch, task, subResult, createLoadOptionForShadowWrapper()); + long shadowTimestampAfter = System.currentTimeMillis(); + LOGGER.trace("Got shadow: {} in {}", projection, shadowTimestampAfter - shadowTimestampBefore); if(projection == null) { // showResult(subResult, "pageAdminFocus.message.couldntLoadShadowProjection"); LOGGER.error("Couldn't load shadow projection"); continue; } + long timestampWrapperStart = System.currentTimeMillis(); try { + ShadowWrapper wrapper = loadShadowWrapper(projection, task, subResult); wrapper.setLoadWithNoFetch(noFetch); @@ -178,7 +185,11 @@ private List loadShadowWrappers(boolean noFetch) { showResult(subResult, "pageAdminFocus.message.couldntCreateShadowWrapper"); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't create shadow wrapper", e); } + long timestampWrapperEnd = System.currentTimeMillis(); + LOGGER.trace("Load wrapper in {}", timestampWrapperEnd - timestampWrapperStart); } + long end = System.currentTimeMillis(); + LOGGER.trace("Load projctions in {}", end - start); return list; } @@ -198,6 +209,8 @@ public ShadowWrapper loadShadowWrapper(PrismObject projection, Task } public void loadFullShadow(PrismObjectValueWrapper shadowWrapperValue, AjaxRequestTarget target) { + LOGGER.trace("Loading full shadow"); + long start = System.currentTimeMillis(); if(shadowWrapperValue.getRealValue() == null) { error(getString("pageAdminFocus.message.couldntCreateShadowWrapper")); LOGGER.error("Couldn't create shadow wrapper, because RealValue is null in " + shadowWrapperValue); @@ -206,9 +219,12 @@ public void loadFullShadow(PrismObjectValueWrapper shadowWrapperValu String oid = shadowWrapperValue.getRealValue().getOid(); Task task = createSimpleTask(OPERATION_LOAD_SHADOW); OperationResult result = task.getResult(); + long loadStart = System.currentTimeMillis(); PrismObject projection = getPrismObjectForWrapper(ShadowType.class, oid, false, task, result, createLoadOptionForShadowWrapper()); + long loadEnd = System.currentTimeMillis(); + LOGGER.trace("Load projection in {} ms", loadEnd - loadStart); if (projection == null) { result.recordFatalError(getString("PageAdminFocus.message.loadFullShadow.fatalError", shadowWrapperValue.getRealValue())); showResult(result); @@ -216,6 +232,7 @@ public void loadFullShadow(PrismObjectValueWrapper shadowWrapperValu return; } + long wrapperStart = System.currentTimeMillis(); ShadowWrapper shadowWrapperNew; try { shadowWrapperNew = loadShadowWrapper(projection, task, result); @@ -233,6 +250,10 @@ public void loadFullShadow(PrismObjectValueWrapper shadowWrapperValu error(getString("pageAdminFocus.message.couldntCreateShadowWrapper")); LOGGER.error("Couldn't create shadow wrapper", e); } + long wrapperEnd = System.currentTimeMillis(); + LOGGER.trace("Wrapper loaded in {} ms", wrapperEnd - wrapperStart); + long end = System.currentTimeMillis(); + LOGGER.trace("Got full shadow in {} ms", end - start); } // @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageEvaluateMapping.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageEvaluateMapping.java index 30fc9ece540..9dc42b630ce 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageEvaluateMapping.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageEvaluateMapping.java @@ -7,6 +7,24 @@ package com.evolveum.midpoint.web.page.admin.configuration; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; + import com.evolveum.midpoint.gui.api.model.NonEmptyModel; import com.evolveum.midpoint.gui.api.model.NonEmptyWrapperModel; import com.evolveum.midpoint.schema.result.OperationResult; @@ -25,27 +43,7 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingEvaluationRequestType; import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingEvaluationResponseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.ajax.form.OnChangeAjaxBehavior; -import org.apache.wicket.markup.html.form.DropDownChoice; -import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.Model; -import org.apache.wicket.model.PropertyModel; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; - -/** - * @author mederly - */ @PageDescriptor(url = "/admin/config/evaluateMapping", action = { @AuthorizationAction(actionUri = PageAdminConfiguration.AUTH_CONFIGURATION_ALL, label = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_LABEL, description = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_DESCRIPTION), @@ -113,12 +111,7 @@ protected void onSubmit(AjaxRequestTarget target) { final DropDownChoice sampleChoice = new DropDownChoice<>(ID_MAPPING_SAMPLE, Model.of(""), - new IModel>() { - @Override - public List getObject() { - return SAMPLES; - } - }, + (IModel>) () -> SAMPLES, new StringResourceChoiceRenderer("PageEvaluateMapping.sample")); sampleChoice.setNullValid(true); sampleChoice.add(new OnChangeAjaxBehavior() { @@ -135,17 +128,14 @@ protected void onUpdate(AjaxRequestTarget target) { } private String readResource(String name) { - InputStream is = PageEvaluateMapping.class.getResourceAsStream(name); - if (is != null) { - try { + try (InputStream is = PageEvaluateMapping.class.getResourceAsStream(name)) { + if (is != null) { return IOUtils.toString(is, StandardCharsets.UTF_8); - } catch (IOException e) { - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't read sample from resource {}", e, name); - } finally { - IOUtils.closeQuietly(is); + } else { + LOGGER.warn("Resource {} containing sample couldn't be found", name); } - } else { - LOGGER.warn("Resource {} containing sample couldn't be found", name); + } catch (IOException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't read sample from resource {}", e, name); } return null; } @@ -201,6 +191,4 @@ private void executeMappingPerformed(AjaxRequestTarget target) { showResult(result); target.add(this); } - - } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageImportObject.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageImportObject.java index 9fb200911a2..158f1a82933 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageImportObject.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageImportObject.java @@ -7,27 +7,13 @@ package com.evolveum.midpoint.web.page.admin.configuration; -import com.evolveum.midpoint.gui.api.model.LoadableModel; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -import com.evolveum.midpoint.task.api.Task; -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.web.application.AuthorizationAction; -import com.evolveum.midpoint.web.application.PageDescriptor; -import com.evolveum.midpoint.web.component.AjaxButton; -import com.evolveum.midpoint.web.component.AjaxSubmitButton; -import com.evolveum.midpoint.web.component.input.DataLanguagePanel; -import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; -import com.evolveum.midpoint.web.component.AceEditor; -import com.evolveum.midpoint.web.page.admin.configuration.component.ImportOptionsPanel; -import com.evolveum.midpoint.web.security.MidPointApplication; -import com.evolveum.midpoint.web.security.WebApplicationConfiguration; -import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ImportOptionsType; +import static org.apache.commons.lang3.BooleanUtils.isTrue; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ModelExecuteOptionsType; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; @@ -46,12 +32,26 @@ import org.apache.wicket.util.file.File; import org.jetbrains.annotations.NotNull; -import java.io.FileInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.List; - -import static org.apache.commons.lang3.BooleanUtils.isTrue; +import com.evolveum.midpoint.gui.api.model.LoadableModel; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.task.api.Task; +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.web.application.AuthorizationAction; +import com.evolveum.midpoint.web.application.PageDescriptor; +import com.evolveum.midpoint.web.component.AceEditor; +import com.evolveum.midpoint.web.component.AjaxButton; +import com.evolveum.midpoint.web.component.AjaxSubmitButton; +import com.evolveum.midpoint.web.component.input.DataLanguagePanel; +import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; +import com.evolveum.midpoint.web.page.admin.configuration.component.ImportOptionsPanel; +import com.evolveum.midpoint.web.security.MidPointApplication; +import com.evolveum.midpoint.web.security.WebApplicationConfiguration; +import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ImportOptionsType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ModelExecuteOptionsType; /** * @author lazyman @@ -87,9 +87,9 @@ public class PageImportObject extends PageAdminConfiguration { private static final Integer INPUT_FILE = 1; private static final Integer INPUT_XML = 2; - private LoadableModel optionsModel; - private IModel fullProcessingModel; - private IModel xmlEditorModel; + private final LoadableModel optionsModel; + private final IModel fullProcessingModel; + private final IModel xmlEditorModel; private String dataLanguage; @@ -124,7 +124,7 @@ private void initLayout() { mainForm.add(buttonBar); final IModel groupModel = new Model<>(INPUT_FILE); - RadioGroup importRadioGroup = new RadioGroup(ID_IMPORT_RADIO_GROUP, groupModel); + RadioGroup importRadioGroup = new RadioGroup<>(ID_IMPORT_RADIO_GROUP, groupModel); importRadioGroup.add(new AjaxFormChoiceComponentUpdatingBehavior() { @Override @@ -135,10 +135,10 @@ protected void onUpdate(AjaxRequestTarget target) { }); mainForm.add(importRadioGroup); - Radio fileRadio = new Radio(ID_FILE_RADIO, new Model(INPUT_FILE), importRadioGroup); + Radio fileRadio = new Radio<>(ID_FILE_RADIO, new Model<>(INPUT_FILE), importRadioGroup); importRadioGroup.add(fileRadio); - Radio xmlRadio = new Radio(ID_XML_RADIO, new Model(INPUT_XML), importRadioGroup); + Radio xmlRadio = new Radio<>(ID_XML_RADIO, new Model<>(INPUT_XML), importRadioGroup); importRadioGroup.add(xmlRadio); WebMarkupContainer inputAce = new WebMarkupContainer(ID_INPUT_ACE); @@ -267,8 +267,9 @@ private boolean validateInput(boolean raw) { } private static class InputDescription { - private InputStream inputStream; - private String dataLanguage; + private final InputStream inputStream; + private final String dataLanguage; + InputDescription(InputStream inputStream, String dataLanguage) { this.inputStream = inputStream; this.dataLanguage = dataLanguage; @@ -313,7 +314,7 @@ private InputDescription getInputDescription(boolean editor) throws Exception { } } - private void clearOldFeedback(){ + private void clearOldFeedback() { getSession().getFeedbackMessages().clear(); getFeedbackMessages().clear(); } @@ -348,18 +349,14 @@ private void savePerformed(boolean raw, String operationName, AjaxRequestTarget result.recordFatalError(getString("PageImportObject.message.savePerformed.fatalError"), ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't import file", ex); } finally { - if (stream != null) { - IOUtils.closeQuietly(stream); - } - + IOUtils.closeQuietly(stream); } + showResult(result); - if (result.isFatalError()){ + if (result.isFatalError()) { target.add(getFeedbackPanel()); } else { target.add(PageImportObject.this); } } - - } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageTraceView.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageTraceView.java index 8b50d28bddd..4341dcd26ec 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageTraceView.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageTraceView.java @@ -116,7 +116,6 @@ private void initLayout() { GenericTraceVisualizationType.class, ID_CLOCKWORK_EXECUTION, createClockworkLevels(), new PropertyModel<>(model, TraceViewDto.F_CLOCKWORK_EXECUTION), this, false); - clockworkExecutionChoice.setSortChoices(false); clockworkExecutionChoice.setOutputMarkupId(true); mainForm.add(clockworkExecutionChoice); @@ -124,7 +123,6 @@ GenericTraceVisualizationType.class, ID_CLOCKWORK_EXECUTION, createClockworkLeve GenericTraceVisualizationType.class, ID_CLOCKWORK_CLICK, createClockworkLevels(), new PropertyModel<>(model, TraceViewDto.F_CLOCKWORK_CLICK), this, false); - clockworkClickChoice.setSortChoices(false); clockworkClickChoice.setOutputMarkupId(true); mainForm.add(clockworkClickChoice); @@ -132,7 +130,6 @@ GenericTraceVisualizationType.class, ID_CLOCKWORK_CLICK, createClockworkLevels() GenericTraceVisualizationType.class, ID_MAPPING_EVALUATION, createMappingLevels(), new PropertyModel<>(model, TraceViewDto.F_MAPPING_EVALUATION), this, false); - mappingEvaluationChoice.setSortChoices(false); mappingEvaluationChoice.setOutputMarkupId(true); mainForm.add(mappingEvaluationChoice); @@ -140,7 +137,6 @@ GenericTraceVisualizationType.class, ID_MAPPING_EVALUATION, createMappingLevels( GenericTraceVisualizationType.class, ID_FOCUS_LOAD, createStandardLevels(), new PropertyModel<>(model, TraceViewDto.F_FOCUS_LOAD), this, false); - focusLoadChoice.setSortChoices(false); focusLoadChoice.setOutputMarkupId(true); mainForm.add(focusLoadChoice); @@ -148,7 +144,6 @@ GenericTraceVisualizationType.class, ID_FOCUS_LOAD, createStandardLevels(), GenericTraceVisualizationType.class, ID_PROJECTION_LOAD, createStandardLevels(), new PropertyModel<>(model, TraceViewDto.F_PROJECTION_LOAD), this, false); - projectionLoadChoice.setSortChoices(false); projectionLoadChoice.setOutputMarkupId(true); mainForm.add(projectionLoadChoice); @@ -156,7 +151,6 @@ GenericTraceVisualizationType.class, ID_PROJECTION_LOAD, createStandardLevels(), GenericTraceVisualizationType.class, ID_FOCUS_CHANGE, createStandardLevels(), new PropertyModel<>(model, TraceViewDto.F_FOCUS_CHANGE), this, false); - focusChangeChoice.setSortChoices(false); focusChangeChoice.setOutputMarkupId(true); mainForm.add(focusChangeChoice); @@ -164,7 +158,6 @@ GenericTraceVisualizationType.class, ID_FOCUS_CHANGE, createStandardLevels(), GenericTraceVisualizationType.class, ID_PROJECTION_CHANGE, createStandardLevels(), new PropertyModel<>(model, TraceViewDto.F_PROJECTION_CHANGE), this, false); - projectionChangeChoice.setSortChoices(false); projectionChangeChoice.setOutputMarkupId(true); mainForm.add(projectionChangeChoice); @@ -172,7 +165,6 @@ GenericTraceVisualizationType.class, ID_PROJECTION_CHANGE, createStandardLevels( GenericTraceVisualizationType.class, ID_OTHERS, createOthersLevels(), new PropertyModel<>(model, TraceViewDto.F_OTHERS), this, false); - otherChoice.setSortChoices(false); otherChoice.setOutputMarkupId(true); mainForm.add(otherChoice); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/PageDebugDownloadBehaviour.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/PageDebugDownloadBehaviour.java index e6dc982998c..7ca47323019 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/PageDebugDownloadBehaviour.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/component/PageDebugDownloadBehaviour.java @@ -6,11 +6,27 @@ */ package com.evolveum.midpoint.web.page.admin.configuration.component; +import static com.evolveum.midpoint.prism.SerializationOptions.createSerializeForExport; + +import java.io.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.wicket.RestartResponseException; +import org.apache.wicket.util.file.File; +import org.apache.wicket.util.file.Files; + import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.schema.*; +import com.evolveum.midpoint.schema.GetOperationOptionsBuilder; +import com.evolveum.midpoint.schema.ResultHandler; +import com.evolveum.midpoint.schema.SchemaConstantsGenerated; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.util.exception.SchemaException; @@ -24,20 +40,6 @@ import com.evolveum.midpoint.web.security.WebApplicationConfiguration; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.wicket.RestartResponseException; -import org.apache.wicket.util.file.File; -import org.apache.wicket.util.file.Files; - -import java.io.*; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -import static com.evolveum.midpoint.prism.SerializationOptions.createSerializeForExport; - /** * @author lazyman */ @@ -130,15 +132,13 @@ protected File initFile() { LoggingUtils.logUnexpectedException(LOGGER, "Couldn't init download link", ex); result.recordFatalError(getPage().createStringResource("PageDebugDownloadBehaviour.message.initFile.fatalError").getString(), ex); } finally { - if (writer != null) { - IOUtils.closeQuietly(writer); - } + IOUtils.closeQuietly(writer); } if (!WebComponentUtil.isSuccessOrHandledError(result)) { page.showResult(result); page.getSession().error(page.getString("pageDebugList.message.createFileException")); - LOGGER.debug("Removing file '{}'.", new Object[]{file.getAbsolutePath()}); + LOGGER.debug("Removing file '{}'.", new Object[] { file.getAbsolutePath() }); Files.remove(file); throw new RestartResponseException(PageDebugList.class); @@ -165,7 +165,7 @@ private Writer createWriter(File file) throws IOException { return new OutputStreamWriter(stream); } - private void dumpObjectsToStream(final Writer writer, OperationResult result) throws Exception { + private void dumpObjectsToStream(final Writer writer, OperationResult result) throws Exception { final PageBase page = getPage(); ResultHandler handler = (object, parentResult) -> { @@ -174,7 +174,7 @@ private void dumpObjectsToStream(final Writer writer, Ope writer.write('\t'); writer.write(xml); writer.write('\n'); - } catch (IOException|SchemaException ex) { + } catch (IOException | SchemaException ex) { throw new SystemException(ex.getMessage(), ex); } return true; diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageNewReport.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageNewReport.java index 2c6d392a4f8..dd880dd1034 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageNewReport.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/reports/PageNewReport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2015 Evolveum and contributors + * Copyright (c) 2010-2020 Evolveum and contributors * * This work is dual-licensed under the Apache License 2.0 * and European Union Public License. See LICENSE file for details. @@ -7,21 +7,10 @@ package com.evolveum.midpoint.web.page.admin.reports; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -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.web.application.AuthorizationAction; -import com.evolveum.midpoint.web.application.PageDescriptor; -import com.evolveum.midpoint.web.component.AceEditor; -import com.evolveum.midpoint.web.component.AjaxSubmitButton; -import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; -import com.evolveum.midpoint.web.page.admin.PageAdmin; -import com.evolveum.midpoint.web.page.admin.configuration.PageAdminConfiguration; -import com.evolveum.midpoint.web.page.admin.reports.dto.ReportDto; -import com.evolveum.midpoint.web.security.MidPointApplication; -import com.evolveum.midpoint.web.security.WebApplicationConfiguration; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; @@ -41,21 +30,29 @@ import org.apache.wicket.model.Model; import org.apache.wicket.util.file.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +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.web.application.AuthorizationAction; +import com.evolveum.midpoint.web.application.PageDescriptor; +import com.evolveum.midpoint.web.component.AceEditor; +import com.evolveum.midpoint.web.component.AjaxSubmitButton; +import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; +import com.evolveum.midpoint.web.page.admin.PageAdmin; +import com.evolveum.midpoint.web.page.admin.configuration.PageAdminConfiguration; +import com.evolveum.midpoint.web.page.admin.reports.dto.ReportDto; +import com.evolveum.midpoint.web.security.MidPointApplication; +import com.evolveum.midpoint.web.security.WebApplicationConfiguration; -/** - * @author lazyman - */ @PageDescriptor(url = "/admin/reports/create", action = { @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_REPORTS_ALL_URL, label = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_LABEL, description = PageAdminConfiguration.AUTH_CONFIGURATION_ALL_DESCRIPTION), @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_REPORTS_REPORT_CREATE_URL, label = "PageNewReport.auth.reports.label", - description = "PageNewReport.auth.reports.description")}) + description = "PageNewReport.auth.reports.description") }) public class PageNewReport extends PageAdmin { private static final Trace LOGGER = TraceManager.getTrace(PageNewReport.class); @@ -80,7 +77,7 @@ public class PageNewReport extends PageAdmin { private static final Integer INPUT_FILE = 1; private static final Integer INPUT_XML = 2; - private Model xmlEditorModel; + private final Model xmlEditorModel; public PageNewReport() { xmlEditorModel = new Model<>(null); @@ -101,9 +98,8 @@ private void initLayout() { mainForm.add(buttonBar); final IModel groupModel = new Model<>(INPUT_FILE); - RadioGroup importRadioGroup = new RadioGroup(ID_IMPORT_RADIO_GROUP, groupModel); + RadioGroup importRadioGroup = new RadioGroup<>(ID_IMPORT_RADIO_GROUP, groupModel); importRadioGroup.add(new AjaxFormChoiceComponentUpdatingBehavior() { - @Override protected void onUpdate(AjaxRequestTarget target) { target.add(input); @@ -112,27 +108,26 @@ protected void onUpdate(AjaxRequestTarget target) { }); mainForm.add(importRadioGroup); - Radio fileRadio = new Radio(ID_FILE_RADIO, new Model(INPUT_FILE), importRadioGroup); + Radio fileRadio = new Radio<>(ID_FILE_RADIO, new Model<>(INPUT_FILE), importRadioGroup); importRadioGroup.add(fileRadio); - Radio xmlRadio = new Radio(ID_XML_RADIO, new Model(INPUT_XML), importRadioGroup); + Radio xmlRadio = new Radio<>(ID_XML_RADIO, new Model<>(INPUT_XML), importRadioGroup); importRadioGroup.add(xmlRadio); WebMarkupContainer inputAce = new WebMarkupContainer(ID_INPUT_ACE); - addVisibileForInputType(inputAce, INPUT_XML, groupModel); + addVisibleForInputType(inputAce, INPUT_XML, groupModel); input.add(inputAce); - AceEditor aceEditor = new AceEditor(ID_ACE_EDITOR, xmlEditorModel); aceEditor.setOutputMarkupId(true); inputAce.add(aceEditor); WebMarkupContainer inputFileLabel = new WebMarkupContainer(ID_INPUT_FILE_LABEL); - addVisibileForInputType(inputFileLabel, INPUT_FILE, groupModel); + addVisibleForInputType(inputFileLabel, INPUT_FILE, groupModel); input.add(inputFileLabel); WebMarkupContainer inputFile = new WebMarkupContainer(ID_INPUT_FILE); - addVisibileForInputType(inputFile, INPUT_FILE, groupModel); + addVisibleForInputType(inputFile, INPUT_FILE, groupModel); input.add(inputFile); FileUploadField fileInput = new FileUploadField(ID_FILE_INPUT); @@ -141,14 +136,12 @@ protected void onUpdate(AjaxRequestTarget target) { initButtons(buttonBar, groupModel); } - private void addVisibileForInputType(Component comp, final Integer type, final IModel groupModel) { + private void addVisibleForInputType(Component comp, final Integer type, final IModel groupModel) { comp.add(new VisibleEnableBehaviour() { - @Override public boolean isVisible() { return type.equals(groupModel.getObject()); } - }); } @@ -166,7 +159,7 @@ protected void onError(AjaxRequestTarget target) { target.add(getFeedbackPanel()); } }; - addVisibileForInputType(saveFileButton, INPUT_FILE, inputType); + addVisibleForInputType(saveFileButton, INPUT_FILE, inputType); buttonBar.add(saveFileButton); AjaxSubmitButton saveXmlButton = new AjaxSubmitButton(ID_IMPORT_XML_BUTTON, @@ -182,7 +175,7 @@ protected void onError(AjaxRequestTarget target) { target.add(getFeedbackPanel()); } }; - addVisibileForInputType(saveXmlButton, INPUT_XML, inputType); + addVisibleForInputType(saveXmlButton, INPUT_XML, inputType); buttonBar.add(saveXmlButton); } @@ -227,12 +220,8 @@ private void importReportFromFilePerformed(AjaxRequestTarget target) { result.recordFatalError(getString("PageImportObject.message.savePerformed.fatalError"), ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't import file", ex); } finally { - if (stream != null) { - IOUtils.closeQuietly(stream); - } - if (newFile != null) { - FileUtils.deleteQuietly(newFile); - } + IOUtils.closeQuietly(stream); + FileUtils.deleteQuietly(newFile); } showResult(result); diff --git a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/util/ItemDeltaItem.java b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/util/ItemDeltaItem.java index 67cbda3a9b2..df7c915c49d 100644 --- a/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/util/ItemDeltaItem.java +++ b/infra/prism-api/src/main/java/com/evolveum/midpoint/prism/util/ItemDeltaItem.java @@ -235,6 +235,7 @@ public ItemDeltaItem f public ItemDeltaItem findIdi(@NotNull ItemPath path, @Nullable DefinitionResolver additionalDefinitionResolver) throws SchemaException { if (path.isEmpty()) { + //noinspection unchecked return (ItemDeltaItem) this; } @@ -381,12 +382,12 @@ public boolean isStructuredProperty() { // Assumes that this IDI represents structured property public ItemDeltaItem,PrismPropertyDefinition> resolveStructuredProperty( - ItemPath resolvePath, PrismPropertyDefinition outputDefinition, ItemPath outputPath, + ItemPath resolvePath, PrismPropertyDefinition outputDefinition, PrismContext prismContext) { ItemDeltaItem,PrismPropertyDefinition> thisIdi = (ItemDeltaItem,PrismPropertyDefinition>)this; PrismProperty outputPropertyNew = resolveStructuredPropertyItem((PrismProperty) thisIdi.getItemNew(), resolvePath, outputDefinition); PrismProperty outputPropertyOld = resolveStructuredPropertyItem((PrismProperty) thisIdi.getItemOld(), resolvePath, outputDefinition); - PropertyDelta outputDelta = resolveStructuredPropertyDelta((PropertyDelta) thisIdi.getDelta(), resolvePath, outputDefinition, outputPath, prismContext); + PropertyDelta outputDelta = resolveStructuredPropertyDelta((PropertyDelta) thisIdi.getDelta(), resolvePath, outputDefinition, prismContext); return new ItemDeltaItem<>(outputPropertyOld, outputDelta, outputPropertyNew, outputDefinition); } @@ -403,11 +404,13 @@ private PrismProperty resolveStructuredPropertyItem(PrismProperty PropertyDelta resolveStructuredPropertyDelta(PropertyDelta sourceDelta, ItemPath resolvePath, - PrismPropertyDefinition outputDefinition, ItemPath outputPath, PrismContext prismContext) { + PrismPropertyDefinition outputDefinition, PrismContext prismContext) { if (sourceDelta == null) { return null; } - PropertyDelta outputDelta = (PropertyDelta) outputDefinition.createEmptyDelta(outputPath); + // Path in output delta has no meaning anyway. The delta will never be applied, as it references sub-property object. + //noinspection unchecked + PropertyDelta outputDelta = (PropertyDelta) outputDefinition.createEmptyDelta(ItemPath.EMPTY_PATH); Collection> outputValuesToAdd = resolveStructuredDeltaSet(sourceDelta.getValuesToAdd(), resolvePath, prismContext); if (outputValuesToAdd != null) { outputDelta.addValuesToAdd(outputValuesToAdd); diff --git a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/lex/dom/DomLexicalProcessor.java b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/lex/dom/DomLexicalProcessor.java index 8dc80a55c50..7ae1ef4d79d 100644 --- a/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/lex/dom/DomLexicalProcessor.java +++ b/infra/prism-impl/src/main/java/com/evolveum/midpoint/prism/impl/lex/dom/DomLexicalProcessor.java @@ -6,6 +6,30 @@ */ package com.evolveum.midpoint.prism.impl.lex.dom; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.Validate; +import org.apache.commons.lang3.StringUtils; +import org.codehaus.staxmate.dom.DOMConverter; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.impl.ParserElementSource; import com.evolveum.midpoint.prism.impl.lex.LexicalProcessor; @@ -13,36 +37,15 @@ import com.evolveum.midpoint.prism.impl.xnode.*; import com.evolveum.midpoint.prism.marshaller.XNodeProcessorEvaluationMode; import com.evolveum.midpoint.prism.schema.SchemaRegistry; -import com.evolveum.midpoint.prism.xnode.*; +import com.evolveum.midpoint.prism.xnode.MapXNode; +import com.evolveum.midpoint.prism.xnode.RootXNode; +import com.evolveum.midpoint.prism.xnode.XNode; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang.Validate; -import org.codehaus.staxmate.dom.DOMConverter; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import javax.xml.namespace.QName; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamConstants; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.*; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class DomLexicalProcessor implements LexicalProcessor { @@ -98,8 +101,10 @@ private XMLInputFactory getXMLInputFactory() { // code taken from Validator class @Override - public void readObjectsIteratively(@NotNull ParserSource source, @NotNull ParsingContext parsingContext, - RootXNodeHandler handler) throws SchemaException, IOException { + public void readObjectsIteratively(@NotNull ParserSource source, + @NotNull ParsingContext parsingContext, RootXNodeHandler handler) + throws SchemaException, IOException { + InputStream is = source.getInputStream(); XMLStreamReader stream = null; try { @@ -131,7 +136,8 @@ public void readObjectsIteratively(@NotNull ParserSource source, @NotNull Parsin String lineInfo = stream != null ? " on line " + stream.getLocation().getLineNumber() : ""; - throw new SchemaException("Exception while parsing XML" + lineInfo + ": " + ex.getMessage(), ex); + throw new SchemaException( + "Exception while parsing XML" + lineInfo + ": " + ex.getMessage(), ex); } finally { if (source.closeStreamAfterParsing()) { IOUtils.closeQuietly(is); @@ -139,8 +145,10 @@ public void readObjectsIteratively(@NotNull ParserSource source, @NotNull Parsin } } - private boolean readSingleObjectIteratively(XMLStreamReader stream, Map rootNamespaceDeclarations, - DOMConverter domConverter, RootXNodeHandler handler) throws XMLStreamException, SchemaException { + private boolean readSingleObjectIteratively( + XMLStreamReader stream, Map rootNamespaceDeclarations, + DOMConverter domConverter, RootXNodeHandler handler) + throws XMLStreamException, SchemaException { Document objectDoc = domConverter.buildDocument(stream); Element objectElement = DOMUtil.getFirstChildElement(objectDoc); DOMUtil.setNamespaceDeclarations(objectElement, rootNamespaceDeclarations); @@ -148,7 +156,7 @@ private boolean readSingleObjectIteratively(XMLStreamReader stream, Map readObjects(Document document) throws SchemaException{ + private List readObjects(Document document) throws SchemaException { Element root = DOMUtil.getFirstChildElement(document); QName objectsMarker = schemaRegistry.getPrismContext().getObjectsElementName(); if (objectsMarker != null && !QNameUtil.match(DOMUtil.getQName(root), objectsMarker)) { @@ -180,7 +188,9 @@ public RootXNodeImpl read(Element rootElement) throws SchemaException { return xroot; } - private void extractCommonMetadata(Element element, QName xsiType, XNodeImpl xnode) throws SchemaException { + private void extractCommonMetadata(Element element, QName xsiType, XNodeImpl xnode) + throws SchemaException { + if (xsiType != null) { xnode.setTypeQName(xsiType); xnode.setExplicitTypeDeclaration(true); @@ -254,7 +264,7 @@ private MapXNodeImpl parseElementContentToMap(Element element) throws SchemaExce MapXNodeImpl xmap = new MapXNodeImpl(); // Attributes - for (Attr attr: DOMUtil.listApplicationAttributes(element)) { + for (Attr attr : DOMUtil.listApplicationAttributes(element)) { QName attrQName = DOMUtil.getQName(attr); XNodeImpl subnode = parseAttributeValue(attr); xmap.put(attrQName, subnode); @@ -263,7 +273,7 @@ private MapXNodeImpl parseElementContentToMap(Element element) throws SchemaExce // Sub-elements QName lastElementName = null; List lastElements = null; - for (Element childElement: DOMUtil.listChildElements(element)) { + for (Element childElement : DOMUtil.listChildElements(element)) { QName childName = DOMUtil.getQName(childElement); if (!match(childName, lastElementName)) { parseSubElementsGroupAsMapEntry(xmap, lastElementName, lastElements); @@ -315,7 +325,7 @@ private boolean elementsAreCompatible(List elements) { } private QName getHierarchyRoot(QName name) { - ItemDefinition def = schemaRegistry.findItemDefinitionByElementName(name); + ItemDefinition def = schemaRegistry.findItemDefinitionByElementName(name); if (def == null || !def.isHeterogeneousListItem()) { return name; } else { @@ -355,7 +365,7 @@ private void parseSubElementsGroupAsMapEntry(MapXNodeImpl xmap, QName elementNam /** * Parses elements that should form the list. - * + *

* Either they have the same element name, or they are stored as a sub-elements of "list" parent element. */ @NotNull @@ -365,7 +375,7 @@ private ListXNodeImpl parseElementList(List elements, QName elementName throw new IllegalArgumentException("When !storeElementNames the element name must be specified"); } ListXNodeImpl xlist = new ListXNodeImpl(); - for (Element element: elements) { + for (Element element : elements) { xlist.add(parseElementContent(element, elementName, storeElementNames)); } return xlist; @@ -408,13 +418,14 @@ public boolean canRead(@NotNull File file) { return file.getName().endsWith(".xml"); } + private static final Pattern XML_DETECTION_PATTERN = Pattern.compile("\\A\\s*<\\w+"); + @Override public boolean canRead(@NotNull String dataString) { if (dataString.startsWith(") { return serializeXPrimitiveToElement((PrimitiveXNodeImpl) xnode, elementName); } else if (xnode instanceof RootXNodeImpl) { - return writeXRootToElement((RootXNodeImpl)xnode); + return writeXRootToElement((RootXNodeImpl) xnode); } else if (xnode instanceof ListXNodeImpl) { ListXNodeImpl xlist = (ListXNodeImpl) xnode; if (xlist.size() == 0) { return null; } else if (xlist.size() > 1) { - throw new IllegalArgumentException("Cannot serialize list xnode with more than one item: "+xlist); + throw new IllegalArgumentException("Cannot serialize list xnode with more than one item: " + xlist); } else { return serializeToElement(xlist.get(0), elementName); } } else { - throw new IllegalArgumentException("Cannot serialize "+xnode+" to element"); + throw new IllegalArgumentException("Cannot serialize " + xnode + " to element"); } } @@ -498,6 +509,4 @@ public Element serializeSingleElementMapToElement(MapXNode map) throws SchemaExc Element parent = serializeToElement(xmap, subEntry.getKey()); return DOMUtil.getFirstChildElement(parent); } - - } diff --git a/infra/schema-pure-jaxb/pom.xml b/infra/schema-pure-jaxb/pom.xml index 0040d1d6015..173003ac20f 100644 --- a/infra/schema-pure-jaxb/pom.xml +++ b/infra/schema-pure-jaxb/pom.xml @@ -88,7 +88,7 @@ jaxb2-jdk-11 true - 11 + [11,) diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index baec7735e0d..1e6140b320c 100755 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -13116,7 +13116,7 @@ (abstract) role.

- Use with care. MidPoint will will have to process all the roles that + Use with care. MidPoint will have to process all the roles that have this flag set to true. All the roles will be looked up, autoassign specification will be processed to see if the focus is matching. This will happen all the time for all modification operations. @@ -13181,6 +13181,15 @@ + + + +

+ Restrics autoassignment to concrete focus type. +

+ + + @@ -13621,7 +13630,7 @@ - + Selects some objects from all the objects in midPoint. diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractSearchExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractSearchExpressionEvaluator.java index bd118f135bf..bca0475a538 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractSearchExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AbstractSearchExpressionEvaluator.java @@ -147,19 +147,13 @@ protected List transformSingleValue(ExpressionVariables variables, PlusMinusZ throw new SchemaException("No filter in "+shortDebugDump()); } query = prismContext.getQueryConverter().createObjectQuery(targetTypeClass, filterType); - if (LOGGER.isTraceEnabled()){ - LOGGER.trace("XML query converted to: {}", query.debugDump()); - } + LOGGER.trace("XML query converted to: {}", query.debugDumpLazily()); + query = ExpressionUtil.evaluateQueryExpressions(query, variables, context.getExpressionProfile(), context.getExpressionFactory(), prismContext, context.getContextDescription(), task, result); - if (LOGGER.isTraceEnabled()){ - LOGGER.trace("Expression in query evaluated to: {}", query.debugDump()); - } + LOGGER.trace("Expression in query evaluated to: {}", query.debugDumpLazily()); query = extendQuery(query, context); - - if (LOGGER.isTraceEnabled()){ - LOGGER.trace("Query after extension: {}", query.debugDump()); - } + LOGGER.trace("Query after extension: {}", query.debugDumpLazily()); resultValues = executeSearchUsingCache(targetTypeClass, targetTypeQName, query, additionalAttributeDeltas, context, contextDescription, task, result); @@ -344,10 +338,8 @@ private List executeSearchAttempt(List ra } } - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Assignment expression resulted in {} objects, using query:\n{}", - valueResults.size(), query.debugDump()); - } + LOGGER.trace("Assignment expression resulted in {} objects, using query:\n{}", + valueResults.size(), query.debugDumpLazily()); return valueResults; } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssignmentTargetSearchExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssignmentTargetSearchExpressionEvaluator.java index 02ff397aa26..b4360f7c513 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssignmentTargetSearchExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssignmentTargetSearchExpressionEvaluator.java @@ -30,6 +30,9 @@ import static java.util.Collections.emptyList; /** + * Creates an assignment (or assignments) based on specified conditions for the assignment target. + * Can create target objects on demand. + * * @author Radovan Semancik */ public class AssignmentTargetSearchExpressionEvaluator diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationFromLinkExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationFromLinkExpressionEvaluator.java index 0c3cbe38a09..a0930dab14e 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationFromLinkExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationFromLinkExpressionEvaluator.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import javax.xml.namespace.QName; @@ -51,15 +52,24 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowKindType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import org.apache.commons.collections4.CollectionUtils; +import org.jetbrains.annotations.NotNull; import static com.evolveum.midpoint.schema.GetOperationOptions.createNoFetchCollection; /** - * @author Radovan Semancik + * Creates an association (or associations) based on projections of given role. + * + * I.e. a role has projection (e.g. group) and it also induces a construction of a user account. Using this expression + * evaluator the account can obtain groups that are projections of that particular role. * + * To be used in induced constructions only i.e. not in mappings! + * + * @author Radovan Semancik */ public class AssociationFromLinkExpressionEvaluator - extends AbstractExpressionEvaluator,PrismContainerDefinition, AssociationFromLinkExpressionEvaluatorType> { + extends AbstractExpressionEvaluator, + PrismContainerDefinition, + AssociationFromLinkExpressionEvaluatorType> { private static final Trace LOGGER = TraceManager.getTrace(AssociationFromLinkExpressionEvaluator.class); @@ -71,65 +81,22 @@ public class AssociationFromLinkExpressionEvaluator this.objectResolver = objectResolver; } - /* (non-Javadoc) - * @see com.evolveum.midpoint.common.expression.ExpressionEvaluator#evaluate(java.util.Collection, java.util.Map, boolean, java.lang.String, com.evolveum.midpoint.schema.result.OperationResult) - */ @Override public PrismValueDeltaSetTriple> evaluate(ExpressionEvaluationContext context, OperationResult result) - throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { + throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, + ConfigurationException, SecurityViolationException { + checkEvaluatorProfile(context); String desc = context.getContextDescription(); - AbstractRoleType thisRole; - - Integer assignmentPathIndex = expressionEvaluatorBean.getAssignmentPathIndex(); - if (assignmentPathIndex == null) { - // Legacy ... or default in simple cases - @SuppressWarnings("unchecked") - TypedValue orderOneObjectTypedValue = context.getVariables().get(ExpressionConstants.VAR_ORDER_ONE_OBJECT); - if (orderOneObjectTypedValue == null || orderOneObjectTypedValue.getValue() == null) { - throw new ExpressionEvaluationException("No order one object variable in "+desc+"; the expression may be used in a wrong place. It is only supposed to work in a role."); - } - Object orderOneObject = orderOneObjectTypedValue.getValue(); - if (!(orderOneObject instanceof AbstractRoleType)) { - throw new ExpressionEvaluationException("Order one object variable in "+desc+" is not a role, it is "+orderOneObject.getClass().getName() - +"; the expression may be used in a wrong place. It is only supposed to work in a role."); - } - - thisRole = (AbstractRoleType)orderOneObject; - - } else { - - @SuppressWarnings("unchecked") - TypedValue assignmentPathTypedValue = context.getVariables().get(ExpressionConstants.VAR_ASSIGNMENT_PATH); - if (assignmentPathTypedValue == null || assignmentPathTypedValue.getValue() == null) { - throw new ExpressionEvaluationException("No assignment path variable in "+desc+"; the expression may be used in a wrong place. It is only supposed to work in a role."); - } - - AssignmentPath assignmentPath = (AssignmentPath) assignmentPathTypedValue.getValue(); - if (assignmentPath.isEmpty()) { - throw new ExpressionEvaluationException("Empty assignment path variable in "+desc+"; the expression may be used in a wrong place. It is only supposed to work in a role."); - } - - LOGGER.trace("assignmentPath {}:\n{}", expressionEvaluatorBean.getDescription(), assignmentPath.debugDumpLazily(1)); - - AssignmentPathSegment segment; - try { - segment = assignmentPath.getSegment(assignmentPathIndex); - } catch (IndexOutOfBoundsException e) { - throw new ExpressionEvaluationException("Wrong assignment path index in "+desc+"; Index "+assignmentPathIndex+" cannot be applied to a path of length "+assignmentPath.size(), e); - } - - thisRole = (AbstractRoleType) segment.getSource(); - } - - LOGGER.trace("thisRole {}: {}", expressionEvaluatorBean.getDescription(), thisRole); - - LOGGER.trace("Evaluating association from link on: {}", thisRole); + AbstractRoleType thisRole = getRelevantRole(context); + LOGGER.trace("Evaluating association from link {} on: {}", expressionEvaluatorBean.getDescription(), thisRole); - TypedValue rAssocTargetDefTypedValue = context.getVariables().get(ExpressionConstants.VAR_ASSOCIATION_TARGET_OBJECT_CLASS_DEFINITION); + //noinspection unchecked + TypedValue rAssocTargetDefTypedValue = context.getVariables() + .get(ExpressionConstants.VAR_ASSOCIATION_TARGET_OBJECT_CLASS_DEFINITION); if (rAssocTargetDefTypedValue == null || rAssocTargetDefTypedValue.getValue() == null) { throw new ExpressionEvaluationException("No association target object class definition variable in "+desc+"; the expression may be used in a wrong place. It is only supposed to create an association."); } @@ -149,12 +116,11 @@ public PrismValueDeltaSetTriple> eval QName assocName = context.getMappingQName(); String resourceOid = rAssocTargetDef.getResourceOid(); - Collection> options = null; List candidateShadowOidList = new ArrayList<>(); // Always process the first role (myself) regardless of recursion setting gatherCandidateShadowsFromAbstractRole(thisRole, candidateShadowOidList); if (thisRole instanceof OrgType && matchesForRecursion((OrgType)thisRole)) { - gatherCandidateShadowsFromAbstractRoleRecurse((OrgType)thisRole, candidateShadowOidList, options, desc, context, result); + gatherCandidateShadowsFromAbstractRoleRecurse((OrgType)thisRole, candidateShadowOidList, null, desc, context, result); } LOGGER.trace("Candidate shadow OIDs: {}", candidateShadowOidList); @@ -162,6 +128,64 @@ public PrismValueDeltaSetTriple> eval return ItemDeltaUtil.toDeltaSetTriple(output, null, prismContext); } + private AbstractRoleType getRelevantRole(ExpressionEvaluationContext context) throws ExpressionEvaluationException { + AbstractRoleType thisRole; + Integer assignmentPathIndex = expressionEvaluatorBean.getAssignmentPathIndex(); + if (assignmentPathIndex == null) { + // Legacy ... or default in simple cases + thisRole = getOrderOneObject(context); + } else { + AssignmentPathSegment segment = getSpecifiedAssignmentPathSegment(context, assignmentPathIndex); + thisRole = (AbstractRoleType) segment.getSource(); + } + return thisRole; + } + + @NotNull + private AbstractRoleType getOrderOneObject(ExpressionEvaluationContext context) + throws ExpressionEvaluationException { + @SuppressWarnings("unchecked") + TypedValue orderOneObjectTypedValue = context.getVariables().get(ExpressionConstants.VAR_ORDER_ONE_OBJECT); + if (orderOneObjectTypedValue == null || orderOneObjectTypedValue.getValue() == null) { + throw new ExpressionEvaluationException("No order one object variable in " + context.getContextDescription() + + "; the expression may be used in a wrong place. It is only supposed to work in a role."); + } + Object orderOneObject = orderOneObjectTypedValue.getValue(); + if (orderOneObject instanceof AbstractRoleType) { + return (AbstractRoleType) orderOneObject; + } else { + throw new ExpressionEvaluationException("Order one object variable in " + context.getContextDescription() + + " is not a role, it is "+orderOneObject.getClass().getName() + + "; the expression may be used in a wrong place. It is only supposed to work in a role."); + } + } + + private AssignmentPathSegment getSpecifiedAssignmentPathSegment(ExpressionEvaluationContext context, Integer assignmentPathIndex) + throws ExpressionEvaluationException { + + @SuppressWarnings("unchecked") + TypedValue assignmentPathTypedValue = context.getVariables().get(ExpressionConstants.VAR_ASSIGNMENT_PATH); + if (assignmentPathTypedValue == null || assignmentPathTypedValue.getValue() == null) { + throw new ExpressionEvaluationException("No assignment path variable in " + context.getContextDescription() + + "; the expression may be used in a wrong place. It is only supposed to work in a role."); + } + + AssignmentPath assignmentPath = (AssignmentPath) assignmentPathTypedValue.getValue(); + if (assignmentPath.isEmpty()) { + throw new ExpressionEvaluationException("Empty assignment path variable in " + context.getContextDescription() + + "; the expression may be used in a wrong place. It is only supposed to work in a role."); + } + + LOGGER.trace("assignmentPath {}:\n{}", expressionEvaluatorBean.getDescription(), assignmentPath.debugDumpLazily(1)); + + try { + return assignmentPath.getSegment(assignmentPathIndex); + } catch (IndexOutOfBoundsException e) { + throw new ExpressionEvaluationException("Wrong assignment path index in " + context.getContextDescription() + + "; Index "+assignmentPathIndex+" cannot be applied to a path of length "+assignmentPath.size(), e); + } + } + private void selectMatchingShadows(List candidateShadowsOidList, PrismContainer output, String resourceOid, ShadowKindType kind, String intent, QName assocName, ExpressionEvaluationContext context, OperationResult result) { @@ -199,7 +223,8 @@ private void toAssociation(PrismObject shadow, ShadowAssociationType ResourceAttributeContainer identifiersContainer = ObjectFactory.createResourceAttributeContainer( ShadowAssociationType.F_IDENTIFIERS, shadowAttributesContainer.getDefinition(), prismContext); shadowAssociationType.asPrismContainerValue().add(identifiersContainer); - Collection> shadowIdentifiers = ShadowUtil.getAllIdentifiers(shadow); + Collection> shadowIdentifiers = + Objects.requireNonNull(ShadowUtil.getAllIdentifiers(shadow), "no shadow identifiers"); for (ResourceAttribute shadowIdentifier : shadowIdentifiers) { identifiersContainer.add(shadowIdentifier.clone()); } @@ -208,7 +233,6 @@ private void toAssociation(PrismObject shadow, ShadowAssociationType // Should not happen throw new SystemException(e.getMessage(), e); } - } private void gatherCandidateShadowsFromAbstractRole(AbstractRoleType thisRole, List candidateShadowsOidList) { @@ -240,12 +264,8 @@ private boolean matchesForRecursion(OrgType thisOrg) { return false; } - /* (non-Javadoc) - * @see com.evolveum.midpoint.common.expression.ExpressionEvaluator#shortDebugDump() - */ @Override public String shortDebugDump() { return "associationFromLink"; } - } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationTargetSearchExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationTargetSearchExpressionEvaluator.java index 03fc26165bd..263db51afd6 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationTargetSearchExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/AssociationTargetSearchExpressionEvaluator.java @@ -43,6 +43,8 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; /** + * Creates an association (or associations) based on specified condition for the associated object. + * * @author Radovan Semancik */ public class AssociationTargetSearchExpressionEvaluator diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ConstExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ConstExpressionEvaluator.java index c3a6a655c03..62463348d9a 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ConstExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ConstExpressionEvaluator.java @@ -26,10 +26,13 @@ import org.jetbrains.annotations.NotNull; /** - * @author semancik + * Returns zero set with a single value obtained by resolving given constant. + * Currently limited to single-valued string constants. * + * @author semancik */ -public class ConstExpressionEvaluator extends AbstractExpressionEvaluator { +public class ConstExpressionEvaluator + extends AbstractExpressionEvaluator { private final ConstantsManager constantsManager; @@ -47,6 +50,7 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, String constName = expressionEvaluatorBean.getValue(); String stringValue = constantsManager.getConstantValue(constName); + //noinspection unchecked Item output = outputDefinition.instantiate(); Object value = ExpressionUtil.convertToOutputValue(stringValue, outputDefinition, protector); @@ -55,18 +59,12 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, ((PrismProperty) output).addRealValue(value); } else { throw new UnsupportedOperationException( - "Can only generate values of property, not " + output.getClass()); + "Can only provide values of property, not " + output.getClass()); } return ItemDeltaUtil.toDeltaSetTriple(output, null, prismContext); } - /* - * (non-Javadoc) - * - * @see com.evolveum.midpoint.common.expression.ExpressionEvaluator# - * shortDebugDump() - */ @Override public String shortDebugDump() { return "const:"+ expressionEvaluatorBean.getValue(); diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/FunctionExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/FunctionExpressionEvaluator.java index 693ca2c2c70..85ee1377122 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/FunctionExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/FunctionExpressionEvaluator.java @@ -12,6 +12,8 @@ import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.schema.expression.ExpressionProfile; + import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; @@ -21,20 +23,32 @@ import com.evolveum.midpoint.repo.common.expression.*; import com.evolveum.midpoint.repo.common.expression.evaluator.AbstractExpressionEvaluator; import com.evolveum.midpoint.schema.SchemaConstantsGenerated; -import com.evolveum.midpoint.schema.expression.ExpressionProfile; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.jetbrains.annotations.NotNull; + /** + * Calls specified custom function expression. It is something like a macro: Arguments for the function call + * (expression themselves) are evaluated into triples, which become additional sources for the function expression. + * Then the function expression is evaluated and the output triple is returned as an output triple for the function + * expression evaluation. + * * @author katkav * @author semancik */ public class FunctionExpressionEvaluator extends AbstractExpressionEvaluator { + private static final String OP_EVALUATE = FunctionExpressionEvaluator.class.getSimpleName() + ".evaluate"; + private static final String OP_GET_FUNCTION_TO_EXECUTE = FunctionExpressionEvaluator.class.getSimpleName() + ".getFunctionToExecute"; + private static final String OP_MAKE_EXPRESSION = FunctionExpressionEvaluator.class.getSimpleName() + ".makeExpression"; + private static final String OP_RESOLVE_PARAMETER_VALUE = FunctionExpressionEvaluator.class.getSimpleName() + ".resolveParameterValue"; + private static final String OP_EVALUATE_FUNCTION = FunctionExpressionEvaluator.class.getSimpleName() + ".evaluateFunction"; + private final ObjectResolver objectResolver; FunctionExpressionEvaluator(QName elementName, FunctionExpressionEvaluatorType functionEvaluatorType, D outputDefinition, @@ -48,100 +62,60 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { checkEvaluatorProfile(context); - List expressions; - ObjectReferenceType functionLibraryRef = expressionEvaluatorBean.getLibraryRef(); - if (functionLibraryRef == null) { throw new SchemaException("No functions library defined in "+context.getContextDescription()); } - OperationResult result = parentResult.createMinorSubresult(FunctionExpressionEvaluator.class.getSimpleName() + ".resolveFunctionLibrary"); + OperationResult result = parentResult.createMinorSubresult(OP_EVALUATE); try { - Task task = context.getTask(); + ExpressionType functionExpressionBean = getFunctionExpressionBean(functionLibraryRef, context, result); + Expression functionExpression = createFunctionExpression(functionExpressionBean, context, result); + ExpressionEvaluationContext functionContext = createFunctionEvaluationContext(functionExpressionBean, context, result); - FunctionLibraryType functionLibraryType = objectResolver.resolve(functionLibraryRef, FunctionLibraryType.class, + return evaluateFunctionExpression(functionExpression, functionContext, result); + } catch (Throwable t) { + result.recordFatalError(t); + throw t; + } finally { + result.computeStatusIfUnknown(); + } + } + + private ExpressionType getFunctionExpressionBean(ObjectReferenceType functionLibraryRef, ExpressionEvaluationContext context, + OperationResult parentResult) throws ObjectNotFoundException, SchemaException, CommunicationException, + ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Task task = context.getTask(); + OperationResult result = parentResult.createMinorSubresult(OP_GET_FUNCTION_TO_EXECUTE); + try { + FunctionLibraryType functionLibrary = objectResolver.resolve(functionLibraryRef, FunctionLibraryType.class, null, "resolving value policy reference in generateExpressionEvaluator", task, result); - expressions = functionLibraryType.getFunction(); - if (CollectionUtils.isEmpty(expressions)) { + List allFunctions = functionLibrary.getFunction(); + if (CollectionUtils.isEmpty(allFunctions)) { throw new ObjectNotFoundException( - "No functions defined in referenced function library: " + functionLibraryType + " used in " + context - .getContextDescription()); + "No functions defined in referenced function library: " + functionLibrary + " used in " + + context.getContextDescription()); } - // TODO: this has to be determined from the library archetype - ExpressionProfile expressionProfile = MiscSchemaUtil.getExpressionProfile(); - String functionName = expressionEvaluatorBean.getName(); - if (StringUtils.isEmpty(functionName)) { throw new SchemaException( "Missing function name in " + shortDebugDump() + " in " + context.getContextDescription()); } - List filteredExpressions = expressions.stream() - .filter(expression -> functionName.equals(expression.getName())).collect(Collectors.toList()); - if (filteredExpressions.size() == 0) { - String possibleFunctions = ""; - for (ExpressionType expression : expressions) { - possibleFunctions += expression.getName() + ", "; - } - possibleFunctions = possibleFunctions.substring(0, possibleFunctions.lastIndexOf(",")); + List functionsMatchingName = allFunctions.stream() + .filter(expression -> functionName.equals(expression.getName())) + .collect(Collectors.toList()); + if (functionsMatchingName.isEmpty()) { + String allFunctionNames = allFunctions.stream() + .map(ExpressionType::getName) + .collect(Collectors.joining(", ")); throw new ObjectNotFoundException("No function with name " + functionName + " found in " + shortDebugDump() - + ". Function defined are: " + possibleFunctions + ". In " + context.getContextDescription()); - } - - ExpressionType functionToExecute = determineFunctionToExecute(filteredExpressions); - - OperationResult functionExpressionResult = result - .createMinorSubresult(FunctionExpressionEvaluator.class.getSimpleName() + ".makeExpression"); - ExpressionFactory factory = context.getExpressionFactory(); - - // TODO: expression profile should be determined from the function library archetype - Expression functionExpression; - try { - functionExpression = factory - .makeExpression(functionToExecute, outputDefinition, MiscSchemaUtil.getExpressionProfile(), - "function execution", task, functionExpressionResult); - functionExpressionResult.recordSuccess(); - } catch (SchemaException | ObjectNotFoundException e) { - functionExpressionResult - .recordFatalError("Cannot make expression for " + functionToExecute + ". Reason: " + e.getMessage(), e); - throw e; + + ". Function defined are: " + allFunctionNames + ". In " + context.getContextDescription()); } - ExpressionEvaluationContext functionContext = context.shallowClone(); - ExpressionVariables functionVariables = new ExpressionVariables(); - - for (ExpressionParameterType param : expressionEvaluatorBean.getParameter()) { - ExpressionType valueExpressionType = param.getExpression(); - OperationResult variableResult = result - .createMinorSubresult(FunctionExpressionEvaluator.class.getSimpleName() + ".resolveVariable"); - Expression valueExpression = null; - try { - variableResult.addArbitraryObjectAsParam("valueExpression", valueExpressionType); - D variableOutputDefinition = determineVariableOutputDefinition(functionToExecute, param.getName(), context); - - valueExpression = factory - .makeExpression(valueExpressionType, variableOutputDefinition, MiscSchemaUtil.getExpressionProfile(), - "parameters execution", task, variableResult); - functionExpressionResult.recordSuccess(); - PrismValueDeltaSetTriple evaluatedValue = valueExpression.evaluate(context, result); - V value = ExpressionUtil.getExpressionOutputValue(evaluatedValue, " evaluated value for paramter"); - functionVariables.addVariableDefinition(param.getName(), value, variableOutputDefinition); - variableResult.recordSuccess(); - } catch (SchemaException | ExpressionEvaluationException | ObjectNotFoundException | CommunicationException - | ConfigurationException | SecurityViolationException e) { - variableResult - .recordFatalError("Failed to resolve variable: " + valueExpression + ". Reason: " + e.getMessage()); - throw e; - } - } - - functionContext.setVariables(functionVariables); - - return functionExpression.evaluate(functionContext, result); + return selectFromMatchingFunctions(functionsMatchingName, context); } catch (Throwable t) { result.recordFatalError(t); throw t; @@ -150,15 +124,17 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, } } - private ExpressionType determineFunctionToExecute(List filteredExpressions) { + @NotNull + private ExpressionType selectFromMatchingFunctions(List functionsMatchingName, + ExpressionEvaluationContext context) throws ObjectNotFoundException { - if (filteredExpressions.size() == 1) { - return filteredExpressions.iterator().next(); + if (functionsMatchingName.size() == 1) { + return functionsMatchingName.iterator().next(); } List functionParams = expressionEvaluatorBean.getParameter(); - for (ExpressionType filteredExpression : filteredExpressions) { + for (ExpressionType filteredExpression : functionsMatchingName) { List filteredExpressionParameters = filteredExpression.getParameter(); if (functionParams.size() != filteredExpressionParameters.size()) { continue; @@ -168,14 +144,16 @@ private ExpressionType determineFunctionToExecute(List filteredE } return filteredExpression; } - return null; + String functionName = expressionEvaluatorBean.getName(); + throw new ObjectNotFoundException("No matching function with name " + functionName + " found in " + shortDebugDump() + + ". " + functionsMatchingName.size() + " functions with this name found but none matches the parameters. In " + + context.getContextDescription()); } private boolean compareParameters(List functionParams, List filteredExpressionParameters) { for (ExpressionParameterType functionParam: functionParams ) { boolean found = false; for (ExpressionParameterType filteredExpressionParam : filteredExpressionParameters) { - if (filteredExpressionParam.getName().equals(functionParam.getName())) { found = true; break; @@ -188,27 +166,73 @@ private boolean compareParameters(List functionParams, return true; } - private D determineVariableOutputDefinition(ExpressionType functionToExecute, String paramName, ExpressionEvaluationContext context) throws SchemaException { + private Expression createFunctionExpression(ExpressionType functionToExecute, ExpressionEvaluationContext context, + OperationResult parentResult) throws SecurityViolationException, SchemaException, ObjectNotFoundException { + OperationResult result = parentResult.createMinorSubresult(OP_MAKE_EXPRESSION); + try { + // TODO: expression profile should be determined from the function library archetype + ExpressionProfile expressionProfile = MiscSchemaUtil.getExpressionProfile(); - ExpressionParameterType functionParameter = null; - for (ExpressionParameterType functionParam: functionToExecute.getParameter()) { - if (functionParam.getName().equals(paramName)) { - functionParameter = functionParam; - break; - } + return context.getExpressionFactory() + .makeExpression(functionToExecute, outputDefinition, expressionProfile, + "function execution", context.getTask(), result); + } catch (SchemaException | ObjectNotFoundException e) { + result.recordFatalError("Cannot make expression for " + functionToExecute + ". Reason: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); } + } - if (functionParameter == null) { - throw new SchemaException("Unexpected parameter " + paramName + " for function: " + functionToExecute); + @NotNull + private ExpressionEvaluationContext createFunctionEvaluationContext(ExpressionType functionExpressionBean, + ExpressionEvaluationContext context, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, + SecurityViolationException, ExpressionEvaluationException, CommunicationException, ConfigurationException { + ExpressionEvaluationContext functionContext = context.shallowClone(); + ExpressionVariables functionVariables = new ExpressionVariables(); + + for (ExpressionParameterType param : expressionEvaluatorBean.getParameter()) { + ExpressionType parameterExpressionBean = param.getExpression(); + OperationResult variableResult = parentResult.createMinorSubresult(OP_RESOLVE_PARAMETER_VALUE); + Expression parameterExpression = null; + try { + variableResult.addArbitraryObjectAsParam("parameterExpression", parameterExpressionBean); + D variableOutputDefinition = determineVariableOutputDefinition(functionExpressionBean, param.getName()); + + // TODO: expression profile should be determined somehow + ExpressionProfile expressionProfile = MiscSchemaUtil.getExpressionProfile(); + + parameterExpression = context.getExpressionFactory() + .makeExpression(parameterExpressionBean, variableOutputDefinition, expressionProfile, + "parameter " + param.getName() + " evaluation in " + context.getContextDescription(), + context.getTask(), variableResult); + PrismValueDeltaSetTriple evaluatedValue = parameterExpression.evaluate(context, parentResult); + V value = ExpressionUtil.getExpressionOutputValue(evaluatedValue, "evaluated value for parameter " + param.getName()); + functionVariables.addVariableDefinition(param.getName(), value, variableOutputDefinition); + } catch (SchemaException | ExpressionEvaluationException | ObjectNotFoundException | CommunicationException + | ConfigurationException | SecurityViolationException e) { + variableResult.recordFatalError("Failed to resolve variable: " + parameterExpression + ". Reason: " + e.getMessage()); + throw e; + } finally { + variableResult.computeStatusIfUnknown(); + } } - QName returnType = functionParameter.getType(); + functionContext.setVariables(functionVariables); + return functionContext; + } + private D determineVariableOutputDefinition(ExpressionType functionToExecute, String paramName) throws SchemaException { + ExpressionParameterType functionParameter = functionToExecute.getParameter().stream() + .filter(param -> param.getName().equals(paramName)) + .findFirst() + .orElseThrow(() -> new SchemaException("Unknown parameter " + paramName + " for function: " + functionToExecute)); + + QName returnType = functionParameter.getType(); if (returnType == null) { throw new SchemaException("Cannot determine parameter output definition for " + functionParameter); } - ItemDefinition returnTypeDef = prismContext.getSchemaRegistry().findItemDefinitionByType(returnType); if (returnTypeDef != null) { //noinspection unchecked @@ -222,6 +246,21 @@ private D determineVariableOutputDefinition(ExpressionType functionToExecute, St } } + private PrismValueDeltaSetTriple evaluateFunctionExpression(Expression functionExpression, + ExpressionEvaluationContext functionContext, OperationResult parentResult) throws SchemaException, + ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, + SecurityViolationException { + OperationResult result = parentResult.createMinorSubresult(OP_EVALUATE_FUNCTION); + try { + return functionExpression.evaluate(functionContext, parentResult); + } catch (Throwable t) { + result.recordFatalError(t); + throw t; + } finally { + result.computeStatusIfUnknown(); + } + } + @Override public String shortDebugDump() { return "function: " + expressionEvaluatorBean.getName(); diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java index eb00c8f6769..3f936754e52 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/GenerateExpressionEvaluator.java @@ -15,11 +15,12 @@ import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.delta.ItemDeltaUtil; import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.repo.common.ObjectResolver; import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; import com.evolveum.midpoint.repo.common.expression.ExpressionVariables; -import com.evolveum.midpoint.repo.common.expression.ValuePolicyResolver; +import com.evolveum.midpoint.repo.common.expression.ValuePolicySupplier; import com.evolveum.midpoint.repo.common.expression.evaluator.AbstractExpressionEvaluator; import com.evolveum.midpoint.schema.constants.ExpressionConstants; import com.evolveum.midpoint.schema.result.OperationResult; @@ -32,17 +33,25 @@ import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import static com.evolveum.midpoint.xml.ns._public.common.common_3.GenerateExpressionEvaluatorModeType.POLICY; + +import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; + /** - * @author semancik + * Generates a string value based on given value policy. Puts it into zero set. Plus and minus sets are empty. * + * @author semancik */ -public class GenerateExpressionEvaluator extends AbstractExpressionEvaluator { +public class GenerateExpressionEvaluator + extends AbstractExpressionEvaluator { public static final int DEFAULT_LENGTH = 8; - private ObjectResolver objectResolver; - private ValuePolicyProcessor valuePolicyGenerator; - private ValuePolicyType elementValuePolicy; + private final ObjectResolver objectResolver; + private final ValuePolicyProcessor valuePolicyGenerator; GenerateExpressionEvaluator(QName elementName, GenerateExpressionEvaluatorType generateEvaluatorType, D outputDefinition, Protector protector, ObjectResolver objectResolver, ValuePolicyProcessor valuePolicyGenerator, PrismContext prismContext) { @@ -51,117 +60,113 @@ public class GenerateExpressionEvaluator evaluate(ExpressionEvaluationContext context, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException { checkEvaluatorProfile(context); - ValuePolicyType valuePolicyType = null; + ValuePolicyType valuePolicy = getValuePolicy(context, result); - ObjectReferenceType generateEvaluatorValuePolicyRef = expressionEvaluatorBean.getValuePolicyRef(); - if (generateEvaluatorValuePolicyRef != null) { - if (expressionEvaluatorBean.getValuePolicyRef() != null) { - valuePolicyType = objectResolver.resolve(generateEvaluatorValuePolicyRef, ValuePolicyType.class, - null, "resolving value policy reference in generateExpressionEvaluator", context.getTask(), result); - } - - } - - // if (elementStringPolicy == null) { - // if the policy was changed, the most fresh copy is needed, therefore - // it must be resolved all time the value is generated..if it was not - // resolved each time, the cached policy would be used and so bad values - // would be generated - if (valuePolicyType == null) { - ValuePolicyResolver valuePolicyResolver = context.getValuePolicyResolver(); - if (valuePolicyResolver != null) { - valuePolicyType = valuePolicyResolver.resolve(result); - } - } - - elementValuePolicy = valuePolicyType; - // } else { - // stringPolicyType = elementStringPolicy; - // } - - // - String stringValue = null; - GenerateExpressionEvaluatorModeType mode = expressionEvaluatorBean.getMode(); + //noinspection unchecked Item output = outputDefinition.instantiate(); - if (mode == null || mode == GenerateExpressionEvaluatorModeType.POLICY) { - - ObjectBasedValuePolicyOriginResolver originResolver = getOriginResolver(context); - - // TODO: generate value based on stringPolicyType (if not null) - if (valuePolicyType != null) { - if (isNotEmptyMinLength(valuePolicyType)) { - stringValue = valuePolicyGenerator.generate(output.getPath(), valuePolicyType, DEFAULT_LENGTH, true, originResolver, - context.getContextDescription(), context.getTask(), result); - } else { - stringValue = valuePolicyGenerator.generate(output.getPath(), valuePolicyType, DEFAULT_LENGTH, false, originResolver, - context.getContextDescription(), context.getTask(), result); - } - result.computeStatus(); - if (result.isError()) { - throw new ExpressionEvaluationException("Failed to generate value according to policy: " - + valuePolicyType.getDescription() + ". " + result.getMessage()); - } - } + ItemPath outputPath = output.getPath(); // actually, a name only - if (stringValue == null) { - int length = DEFAULT_LENGTH; - RandomString randomString = new RandomString(length); - stringValue = randomString.nextString(); - } + String stringValue = generateStringValue(valuePolicy, context, outputPath, result); + addValueToOutputProperty(output, stringValue); - } else if (mode == GenerateExpressionEvaluatorModeType.UUID) { - UUID randomUUID = UUID.randomUUID(); - stringValue = randomUUID.toString(); + return ItemDeltaUtil.toDeltaSetTriple(output, null, prismContext); + } - } else { - throw new ExpressionEvaluationException("Unknown mode for generate expression: " + mode); + @NotNull + private String generateStringValue(ValuePolicyType valuePolicy, ExpressionEvaluationContext context, ItemPath outputPath, + OperationResult result) + throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, + CommunicationException, ConfigurationException, SecurityViolationException { + GenerateExpressionEvaluatorModeType mode = defaultIfNull(expressionEvaluatorBean.getMode(), POLICY); + switch (mode) { + case POLICY: + // TODO: generate value based on stringPolicyType (if not null) + if (valuePolicy != null) { + String generatedStringValue = generateStringValueFromPolicy(valuePolicy, context, outputPath, result); + if (generatedStringValue != null) + return generatedStringValue; + } + return new RandomString(DEFAULT_LENGTH).nextString(); + case UUID: + return UUID.randomUUID().toString(); + default: + throw new ExpressionEvaluationException("Unknown mode for generate expression: " + mode); } + } - Object value = ExpressionUtil.convertToOutputValue(stringValue, outputDefinition, protector); - - + private void addValueToOutputProperty(Item output, String stringValue) + throws ExpressionEvaluationException, + SchemaException { if (output instanceof PrismProperty) { + Object value = ExpressionUtil.convertToOutputValue(stringValue, outputDefinition, protector); ((PrismProperty) output).addRealValue(value); } else { throw new UnsupportedOperationException( "Can only generate values of property, not " + output.getClass()); } + } - return ItemDeltaUtil.toDeltaSetTriple(output, null, prismContext); + @Nullable + private String generateStringValueFromPolicy(ValuePolicyType valuePolicy, ExpressionEvaluationContext context, + ItemPath outputPath, OperationResult result) + throws ExpressionEvaluationException, SchemaException, ObjectNotFoundException, CommunicationException, + ConfigurationException, SecurityViolationException { + ObjectBasedValuePolicyOriginResolver originResolver = getOriginResolver(context); + String generatedValue; + if (isNotEmptyMinLength(valuePolicy)) { + generatedValue = valuePolicyGenerator.generate(outputPath, valuePolicy, DEFAULT_LENGTH, true, originResolver, + context.getContextDescription(), context.getTask(), result); + } else { + generatedValue = valuePolicyGenerator.generate(outputPath, valuePolicy, DEFAULT_LENGTH, false, originResolver, + context.getContextDescription(), context.getTask(), result); + } + result.computeStatus(); + if (result.isError()) { + throw new ExpressionEvaluationException("Failed to generate value according to policy: " + + valuePolicy.getDescription() + ". " + result.getMessage()); + } + return generatedValue; + } + + private boolean isNotEmptyMinLength(ValuePolicyType valuePolicy) { + StringPolicyType stringPolicy = valuePolicy.getStringPolicy(); + if (stringPolicy == null) { + return false; + } + Integer minLength = stringPolicy.getLimitations().getMinLength(); + return minLength != null && minLength != 0; + } + + @Nullable + private ValuePolicyType getValuePolicy(ExpressionEvaluationContext context, OperationResult result) + throws ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, + SecurityViolationException, ExpressionEvaluationException { + ObjectReferenceType specifiedValuePolicyRef = expressionEvaluatorBean.getValuePolicyRef(); + if (specifiedValuePolicyRef != null) { + ValuePolicyType resolvedPolicy = objectResolver.resolve(specifiedValuePolicyRef, ValuePolicyType.class, + null, "resolving value policy reference in generateExpressionEvaluator", context.getTask(), result); + if (resolvedPolicy != null) { + return resolvedPolicy; + } + } + + ValuePolicySupplier valuePolicySupplier = context.getValuePolicySupplier(); + if (valuePolicySupplier != null) { + return valuePolicySupplier.get(result); + } + + return null; } // determine object from the variables @SuppressWarnings("unchecked") - private ObjectBasedValuePolicyOriginResolver getOriginResolver(ExpressionEvaluationContext params) throws SchemaException { - ExpressionVariables variables = params.getVariables(); + private ObjectBasedValuePolicyOriginResolver getOriginResolver(ExpressionEvaluationContext context) throws SchemaException { + ExpressionVariables variables = context.getVariables(); if (variables == null) { return null; } @@ -175,8 +180,10 @@ private ObjectBasedValuePolicyOriginResolver getOrigin @Override public String shortDebugDump() { - if (elementValuePolicy != null) { - return "generate: " + elementValuePolicy; + // Here used to be reference to the value policy. However, although expression evaluators are usually not re-evaluated, + // it is not always the case. So the evaluator should not keep state related to evaluation itself. + if (expressionEvaluatorBean.getValuePolicyRef() != null) { + return "generate:" + expressionEvaluatorBean.getValuePolicyRef(); } else { return "generate"; } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/PathExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/PathExpressionEvaluator.java deleted file mode 100644 index 107686df4d7..00000000000 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/PathExpressionEvaluator.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2010-2019 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.model.common.expression.evaluator; - -import java.util.Map; - -import javax.xml.namespace.QName; - -import com.evolveum.midpoint.prism.Item; -import com.evolveum.midpoint.prism.ItemDefinition; -import com.evolveum.midpoint.prism.PrimitiveType; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.prism.PrismPropertyValue; -import com.evolveum.midpoint.prism.PrismValue; -import com.evolveum.midpoint.prism.crypto.Protector; -import com.evolveum.midpoint.prism.delta.ItemDeltaUtil; -import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; -import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.util.DefinitionResolver; -import com.evolveum.midpoint.prism.util.ItemDeltaItem; -import com.evolveum.midpoint.repo.common.ObjectResolver; -import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; -import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluator; -import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; -import com.evolveum.midpoint.repo.common.expression.Source; -import com.evolveum.midpoint.schema.expression.TypedValue; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.QNameUtil; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; - -/** - * @author Radovan Semancik - */ -public class PathExpressionEvaluator implements ExpressionEvaluator { - - private final QName elementName; - private final ItemPath path; - private final ObjectResolver objectResolver; - private final PrismContext prismContext; - private final D outputDefinition; - private final Protector protector; - - PathExpressionEvaluator(QName elementName, ItemPath path, ObjectResolver objectResolver, - D outputDefinition, Protector protector, PrismContext prismContext) { - this.elementName = elementName; - this.path = path; - this.objectResolver = objectResolver; - this.outputDefinition = outputDefinition; - this.prismContext = prismContext; - this.protector = protector; - } - - @Override - public QName getElementName() { - return elementName; - } - - @Override - public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, OperationResult result) - throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, SecurityViolationException { - ExpressionUtil.checkEvaluatorProfileSimple(this, context); - - ItemDeltaItem resolveContext = null; - - ItemPath resolvePath = path; - if (context.getSources() != null && context.getSources().size() == 1) { - Source source = context.getSources().iterator().next(); - if (path.isEmpty()) { - PrismValueDeltaSetTriple outputTriple = (PrismValueDeltaSetTriple) source.toDeltaSetTriple(prismContext); - return outputTriple.clone(); - } - resolveContext = source; - //FIXME quite a hack, but should work for now. - if (QNameUtil.match(path.firstName(), source.getName())) { - resolvePath = path.rest(); - } - } - - Map variablesAndSources = ExpressionUtil.compileVariablesAndSources(context); - - Object first = path.first(); - if (ItemPath.isVariable(first)) { - String variableName = ItemPath.toVariableName(first).getLocalPart(); - TypedValue variableValueAndDefinition = variablesAndSources.get(variableName); - if (variableValueAndDefinition == null) { - throw new ExpressionEvaluationException("No variable with name "+variableName+" in "+ context.getContextDescription()); - } - Object variableValue = variableValueAndDefinition.getValue(); - - if (variableValue == null) { - return null; - } - if (variableValue instanceof Item || variableValue instanceof ItemDeltaItem) { - resolveContext = ExpressionUtil.toItemDeltaItem(variableValue, objectResolver, - "path expression in "+ context.getContextDescription(), result); - } else if (variableValue instanceof PrismPropertyValue){ - PrismValueDeltaSetTriple outputTriple = prismContext.deltaFactory().createPrismValueDeltaSetTriple(); - outputTriple.addToZeroSet((V) variableValue); - return ExpressionUtil.toOutputTriple(outputTriple, outputDefinition, context.getAdditionalConvertor(), null, protector, prismContext); - } else { - throw new ExpressionEvaluationException("Unexpected variable value "+variableValue+" ("+variableValue.getClass()+")"); - } - - resolvePath = path.rest(); - } - - if (resolveContext == null) { - return null; - } - - while (!resolvePath.isEmpty()) { - - if (resolveContext.isContainer()) { - DefinitionResolver defResolver = (parentDef, path) -> { - if (parentDef != null && parentDef.isDynamic()) { - // This is the case of dynamic schema extensions, such as assignment extension. - // Those may not have a definition. In that case just assume strings. - // In fact, this is a HACK. All such schemas should have a definition. - // Otherwise there may be problems with parameter types for caching compiles scripts and so on. - return prismContext.definitionFactory().createPropertyDefinition(path.firstName(), PrimitiveType.STRING.getQname()); - } else { - return null; - } - }; - - try { - resolveContext = resolveContext.findIdi(resolvePath.firstAsPath(), defResolver); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException(e.getMessage()+"; resolving path "+resolvePath.firstAsPath()+" on "+resolveContext, e); - } - - if (resolveContext == null) { - throw new ExpressionEvaluationException("Cannot find item using path "+path+" in "+ context.getContextDescription()); - } - resolvePath = resolvePath.rest(); - - } else if (resolveContext.isStructuredProperty()) { - // The output path does not really matter. The delta will be converted to triple anyway - // But the path cannot be null, oherwise the code will die - resolveContext = resolveContext.resolveStructuredProperty(resolvePath, (PrismPropertyDefinition) outputDefinition, - ItemPath.EMPTY_PATH, prismContext); - break; - - } else if (resolveContext.isNull()){ - break; - - } else { - throw new ExpressionEvaluationException("Cannot resolve path "+resolvePath+" on "+resolveContext+" in "+ context.getContextDescription()); - } - - } - - PrismValueDeltaSetTriple outputTriple = ItemDeltaUtil.toDeltaSetTriple((Item)resolveContext.getItemOld(), - (ItemDelta)resolveContext.getDelta(), prismContext); - - if (outputTriple == null) { - return null; - } - - return ExpressionUtil.toOutputTriple(outputTriple, outputDefinition, context.getAdditionalConvertor(), null, protector, prismContext); - } - - @Override - public String shortDebugDump() { - return "path: "+path; - } -} diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ReferenceSearchExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ReferenceSearchExpressionEvaluator.java index 6be88d75700..f1fe18d5bbd 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ReferenceSearchExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/ReferenceSearchExpressionEvaluator.java @@ -24,6 +24,9 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ReferenceSearchExpressionEvaluatorType; /** + * Creates a generic reference (or references) based on specified condition for the referenced object. + * (It seems to be not much used.) + * * @author Radovan Semancik */ public class ReferenceSearchExpressionEvaluator diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/IdiResolutionContext.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/IdiResolutionContext.java new file mode 100644 index 00000000000..a7f59b0301b --- /dev/null +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/IdiResolutionContext.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 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.model.common.expression.evaluator.path; + +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.ItemDeltaUtil; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.util.DefinitionResolver; +import com.evolveum.midpoint.prism.util.ItemDeltaItem; +import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; +import com.evolveum.midpoint.util.exception.SchemaException; +import org.jetbrains.annotations.NotNull; + +/** + * Standard resolution context containing an IDI. + */ +class IdiResolutionContext extends ResolutionContext { + + @NotNull private final ItemDeltaItem itemDeltaItem; + + private IdiResolutionContext(@NotNull ItemDeltaItem itemDeltaItem) { + this.itemDeltaItem = itemDeltaItem; + } + + static IdiResolutionContext fromIdi(@NotNull ItemDeltaItem itemDeltaItem) { + return new IdiResolutionContext(itemDeltaItem); + } + + static IdiResolutionContext fromAnyObject(Object value) { + return new IdiResolutionContext(ExpressionUtil.toItemDeltaItem(value)); + } + + PrismValueDeltaSetTriple createOutputTriple(PrismContext prismContext) { + //noinspection unchecked + return (PrismValueDeltaSetTriple) ItemDeltaUtil.toDeltaSetTriple( + (Item) itemDeltaItem.getItemOld(), + itemDeltaItem.getDelta(), + prismContext); + } + + @Override + boolean isContainer() { + return itemDeltaItem.isContainer(); + } + + @Override + ResolutionContext stepInto(ItemName step, DefinitionResolver defResolver) throws SchemaException { + //noinspection unchecked + return new IdiResolutionContext(itemDeltaItem.findIdi(step, defResolver)); + } + + @Override + boolean isStructuredProperty() { + return itemDeltaItem.isStructuredProperty(); + } + + @Override + ResolutionContext resolveStructuredProperty(ItemPath pathToResolve, + PrismPropertyDefinition outputDefinition, PrismContext prismContext) { + return new IdiResolutionContext(itemDeltaItem.resolveStructuredProperty(pathToResolve, + outputDefinition, prismContext)); + } + + @Override + boolean isNull() { + return itemDeltaItem.isNull(); + } +} diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluation.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluation.java new file mode 100644 index 00000000000..18166ef9da6 --- /dev/null +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluation.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2020 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.model.common.expression.evaluator.path; + +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.util.DefinitionResolver; +import com.evolveum.midpoint.prism.util.ItemDeltaItem; +import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; +import com.evolveum.midpoint.repo.common.expression.evaluator.ExpressionEvaluatorUtil; +import com.evolveum.midpoint.schema.expression.TypedValue; +import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; +import com.evolveum.midpoint.util.exception.SchemaException; + +import org.jetbrains.annotations.Nullable; + +/** + * Evaluation of the "path" expression. + */ +class PathExpressionEvaluation { + + private final PathExpressionEvaluator evaluator; + private final ExpressionEvaluationContext context; + + /** + * Path to be resolved. Changes during resolution process. + */ + private ItemPath pathToResolve; + + /** + * Context (e.g. prism item or prism value) in which the resolution takes places. + * Changes during resolution process. + */ + private ResolutionContext resolutionContext; + + PathExpressionEvaluation(PathExpressionEvaluator evaluator, ExpressionEvaluationContext context) { + this.evaluator = evaluator; + this.context = context; + } + + PrismValueDeltaSetTriple evaluate() throws ExpressionEvaluationException, SchemaException { + pathToResolve = evaluator.path; + resolutionContext = determineInitialResolveContext(); + if (resolutionContext == null) { + return null; + } + + stepAlongResolvePath(); + return prepareOutputTriple(); + } + + private ResolutionContext determineInitialResolveContext() throws ExpressionEvaluationException { + if (pathToResolve.startsWithVariable()) { + return getInitialResolveContextFromVariable(); + } else if (context.getSources().size() == 1) { + return IdiResolutionContext.fromIdi(context.getSources().iterator().next()); + } else if (context.getDefaultSource() != null) { + return IdiResolutionContext.fromIdi(context.getDefaultSource()); + } else if (context.getSources().isEmpty()) { + throw new IllegalStateException("There is no source to be used for path resolution. In " + + context.getContextDescription()); + } else { + throw new IllegalStateException("There is are multiple sources to be used for path resolution. In " + + context.getContextDescription()); + } + } + + private ResolutionContext getInitialResolveContextFromVariable() throws ExpressionEvaluationException { + String variableName = ItemPath.toVariableName(pathToResolve.first()).getLocalPart(); + pathToResolve = pathToResolve.rest(); + + TypedValue variableValueAndDefinition = ExpressionEvaluatorUtil.findInSourcesAndVariables(context, variableName); + if (variableValueAndDefinition == null) { + throw new ExpressionEvaluationException("No variable with name "+variableName+" in "+ context.getContextDescription()); + } + + Object variableValue = variableValueAndDefinition.getValue(); + if (variableValue == null) { + return null; + } else if (variableValue instanceof Item || variableValue instanceof ItemDeltaItem) { + return IdiResolutionContext.fromAnyObject(variableValue); + } else if (variableValue instanceof PrismValue) { + return new ValueResolutionContext((PrismValue) variableValue, context.getContextDescription()); + } else { + throw new ExpressionEvaluationException("Unexpected variable value "+variableValue+" ("+variableValue.getClass()+")"); + } + } + + @Nullable + private PrismValueDeltaSetTriple prepareOutputTriple() { + PrismValueDeltaSetTriple outputTriple = resolutionContext.createOutputTriple(evaluator.prismContext); + if (outputTriple == null) { + return null; + } else { + return ExpressionEvaluatorUtil.toOutputTriple(outputTriple, evaluator.outputDefinition, + context.getAdditionalConvertor(), null, evaluator.protector, evaluator.prismContext); + } + } + + private void stepAlongResolvePath() throws SchemaException, ExpressionEvaluationException { + + while (!pathToResolve.isEmpty()) { + if (resolutionContext.isContainer()) { + DefinitionResolver defResolver = (parentDef, path) -> { + if (parentDef != null && parentDef.isDynamic()) { + // This is the case of dynamic schema extensions, such as assignment extension. + // Those may not have a definition. In that case just assume strings. + // In fact, this is a HACK. All such schemas should have a definition. + // Otherwise there may be problems with parameter types for caching compiles scripts and so on. + return evaluator.prismContext.definitionFactory().createPropertyDefinition(path.firstName(), PrimitiveType.STRING.getQname()); + } else { + return null; + } + }; + + try { + resolutionContext = resolutionContext.stepInto(pathToResolve.firstToName(), defResolver); + pathToResolve = pathToResolve.rest(); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(e.getMessage()+"; resolving path "+ pathToResolve.firstAsPath()+" on "+ + resolutionContext +"; in "+context.getContextDescription(), e); + } + + if (resolutionContext == null) { + throw new ExpressionEvaluationException("Cannot find item using path "+evaluator.path+" in "+ + context.getContextDescription()); + } + + } else if (resolutionContext.isStructuredProperty()) { + resolutionContext = resolutionContext.resolveStructuredProperty(pathToResolve, + (PrismPropertyDefinition) evaluator.outputDefinition, evaluator.prismContext); + pathToResolve = ItemPath.EMPTY_PATH; + + } else if (resolutionContext.isNull()) { + pathToResolve = ItemPath.EMPTY_PATH; + + } else { + throw new ExpressionEvaluationException("Cannot resolve path "+ pathToResolve +" on "+ resolutionContext +" in "+ context.getContextDescription()); + } + } + } + +} diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluator.java new file mode 100644 index 00000000000..1f85099bf7e --- /dev/null +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluator.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 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.model.common.expression.evaluator.path; + +import javax.xml.namespace.QName; + +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.crypto.Protector; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; +import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluator; +import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; + +/** + * Returns value set triple derived from specified (or default) source by resolving specified path. + * + * @author Radovan Semancik + */ +public class PathExpressionEvaluator implements ExpressionEvaluator { + + private final QName elementName; + final ItemPath path; + final PrismContext prismContext; + final D outputDefinition; + final Protector protector; + + PathExpressionEvaluator(QName elementName, ItemPath path, D outputDefinition, Protector protector, + PrismContext prismContext) { + this.elementName = elementName; + this.path = path; + this.outputDefinition = outputDefinition; + this.prismContext = prismContext; + this.protector = protector; + } + + @Override + public QName getElementName() { + return elementName; + } + + @Override + public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, OperationResult result) + throws SchemaException, ExpressionEvaluationException, SecurityViolationException { + ExpressionUtil.checkEvaluatorProfileSimple(this, context); + + return new PathExpressionEvaluation<>(this, context) + .evaluate(); + } + + @Override + public String shortDebugDump() { + return "path: "+path; + } +} diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/PathExpressionEvaluatorFactory.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluatorFactory.java similarity index 92% rename from model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/PathExpressionEvaluatorFactory.java rename to model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluatorFactory.java index 970463fbb24..3e3433a8940 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/PathExpressionEvaluatorFactory.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/PathExpressionEvaluatorFactory.java @@ -1,10 +1,10 @@ /* - * Copyright (c) 2010-2019 Evolveum and contributors + * Copyright (c) 2010-2020 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.model.common.expression.evaluator; +package com.evolveum.midpoint.model.common.expression.evaluator.path; import java.util.Collection; import java.util.Objects; @@ -66,7 +66,6 @@ public ExpressionEvaluator c ItemPathType path = Objects.requireNonNull( getSingleEvaluatorBean(evaluatorElements, ItemPathType.class, contextDescription), () -> "missing path specification in " + contextDescription); - return new PathExpressionEvaluator<>(ELEMENT_NAME, path.getItemPath(), getObjectResolver(), - outputDefinition, protector, prismContext); + return new PathExpressionEvaluator<>(ELEMENT_NAME, path.getItemPath(), outputDefinition, protector, prismContext); } } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/ResolutionContext.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/ResolutionContext.java new file mode 100644 index 00000000000..f810f19ff16 --- /dev/null +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/ResolutionContext.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 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.model.common.expression.evaluator.path; + +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismPropertyDefinition; +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.util.DefinitionResolver; +import com.evolveum.midpoint.util.exception.SchemaException; + +/** + * Context of (further) resolution. + */ +abstract class ResolutionContext { + + /** + * Converts resolution context into output triple (if there's nothing more to resolve). + */ + abstract PrismValueDeltaSetTriple createOutputTriple(PrismContext prismContext); + + /** + * Is the context of container type i.e. can we step into it? + */ + abstract boolean isContainer(); + + /** + * Resolve next step of the container-type context. + */ + abstract ResolutionContext stepInto(ItemName step, DefinitionResolver defResolver) throws SchemaException; + + /** + * Is the context of "structured property" type i.e. can we try to find the path in it? + */ + abstract boolean isStructuredProperty(); + + /** + * Resolve the last mile in structured property. + */ + abstract ResolutionContext resolveStructuredProperty(ItemPath pathToResolve, + PrismPropertyDefinition outputDefinition, PrismContext prismContext); + + /** + * Is the context null so there's nothing to resolve? + */ + abstract boolean isNull(); +} diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/ValueResolutionContext.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/ValueResolutionContext.java new file mode 100644 index 00000000000..2b04193632c --- /dev/null +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/evaluator/path/ValueResolutionContext.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 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.model.common.expression.evaluator.path; + +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.util.DefinitionResolver; +import com.evolveum.midpoint.util.exception.SchemaException; + +import org.jetbrains.annotations.NotNull; + +/** + * Simplified resolution context holding a single prism value. + */ +class ValueResolutionContext extends ResolutionContext { + + @NotNull private final PrismValue value; + private final String contextDescription; + + ValueResolutionContext(@NotNull PrismValue value, String contextDescription) { + this.value = value; + this.contextDescription = contextDescription; + } + + @Override + PrismValueDeltaSetTriple createOutputTriple(PrismContext prismContext) { + PrismValueDeltaSetTriple outputTriple = prismContext.deltaFactory().createPrismValueDeltaSetTriple(); + //noinspection unchecked + outputTriple.addToZeroSet((V) value); + return outputTriple; + } + + @Override + boolean isContainer() { + return value instanceof PrismContainerValue; + } + + @Override + ResolutionContext stepInto(ItemName step, DefinitionResolver defResolver) throws SchemaException { + assert isContainer(); + Item item = ((PrismContainerValue) value).findItem(step); + if (item != null) { + if (item.size() > 1) { + throw new SchemaException("Cannot resolve " + step + " in " + item + + " because there is more than one value. In " + contextDescription); + } else if (item.hasNoValues()) { + return null; + } else { + return new ValueResolutionContext(item.getAnyValue(), contextDescription); + } + } else { + return null; + } + } + + @Override + boolean isStructuredProperty() { + return value instanceof PrismPropertyValue && value.getRealValue() instanceof Structured; + } + + @Override + ResolutionContext resolveStructuredProperty(ItemPath pathToResolve, PrismPropertyDefinition outputDefinition, + PrismContext prismContext) { + assert isStructuredProperty(); + //noinspection ConstantConditions + Object resolvedRealValue = ((Structured) value.getRealValue()).resolve(pathToResolve); + if (resolvedRealValue != null) { + PrismPropertyValue resolvedPrismValue = prismContext.itemFactory().createPropertyValue(resolvedRealValue); + return new ValueResolutionContext(resolvedPrismValue, contextDescription); + } else { + return null; + } + } + + @Override + boolean isNull() { + return false; + } +} diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionEvaluator.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionEvaluator.java index 938c9901e15..7712984d25f 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionEvaluator.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/expression/script/ScriptExpressionEvaluator.java @@ -34,6 +34,8 @@ import org.jetbrains.annotations.NotNull; /** + * Executes specified script written e.g. in Groovy, JavaScript, Python, etc. Velocity template language is supported as well. + * * @author Radovan Semancik */ public class ScriptExpressionEvaluator diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingBuilder.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingBuilder.java index 2eb5986c1c8..ad01967518b 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingBuilder.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingBuilder.java @@ -62,7 +62,7 @@ public final class MappingBuilder targetContext; private OriginType originType; private ObjectType originObject; - private ConfigurableValuePolicyResolver valuePolicyResolver; + private ConfigurableValuePolicySupplier valuePolicySupplier; private VariableProducer variableProducer; private MappingPreExpression mappingPreExpression; private boolean conditionMaskOld = true; @@ -168,8 +168,8 @@ public MappingBuilder originObject(ObjectType val) { return this; } - public MappingBuilder valuePolicyResolver(ConfigurableValuePolicyResolver val) { - valuePolicyResolver = val; + public MappingBuilder valuePolicySupplier(ConfigurableValuePolicySupplier val) { + valuePolicySupplier = val; return this; } @@ -329,11 +329,6 @@ public MappingBuilder addVariableDefinition(String name, Object value, Cla return this; } - public MappingBuilder stringPolicyResolver(ConfigurableValuePolicyResolver stringPolicyResolver) { - this.valuePolicyResolver = stringPolicyResolver; - return this; - } - public boolean hasVariableDefinition(String varName) { return variables.containsKey(varName); } @@ -428,8 +423,8 @@ public ObjectType getOriginObject() { return originObject; } - public ConfigurableValuePolicyResolver getValuePolicyResolver() { - return valuePolicyResolver; + public ConfigurableValuePolicySupplier getValuePolicySupplier() { + return valuePolicySupplier; } public VariableProducer getVariableProducer() { diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java index 5dfe8cc8c49..838a447e709 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingImpl.java @@ -164,9 +164,9 @@ public class MappingImpl /** * Provider of the value policy (used for "generate" expressions). - * See {@link ExpressionEvaluationContext#valuePolicyResolver}. + * See {@link ExpressionEvaluationContext#valuePolicySupplier}. */ - final ConfigurableValuePolicyResolver valuePolicyResolver; + final ConfigurableValuePolicySupplier valuePolicySupplier; /** * Mapping pre-expression is invoked just before main mapping expression. @@ -335,7 +335,7 @@ public class MappingImpl targetContext = builder.getTargetContext(); originType = builder.getOriginType(); originObject = builder.getOriginObject(); - valuePolicyResolver = builder.getValuePolicyResolver(); + valuePolicySupplier = builder.getValuePolicySupplier(); variableProducer = builder.getVariableProducer(); mappingPreExpression = builder.getMappingPreExpression(); conditionMaskOld = builder.isConditionMaskOld(); @@ -374,7 +374,7 @@ private MappingImpl(MappingImpl prototype) { this.originType = prototype.originType; this.originObject = prototype.originObject; - this.valuePolicyResolver = prototype.valuePolicyResolver; + this.valuePolicySupplier = prototype.valuePolicySupplier; this.mappingPreExpression = prototype.mappingPreExpression; this.conditionMaskOld = prototype.conditionMaskOld; this.conditionMaskNew = prototype.conditionMaskNew; @@ -1044,7 +1044,7 @@ private void computeConditionTriple(OperationResult result) "condition in " + getMappingContextDescription(), task, result); ExpressionEvaluationContext context = new ExpressionEvaluationContext(sources, variables, "condition in " + getMappingContextDescription(), task); - context.setValuePolicyResolver(valuePolicyResolver); + context.setValuePolicySupplier(valuePolicySupplier); context.setExpressionFactory(expressionFactory); context.setDefaultSource(defaultSource); context.setMappingQName(mappingQName); @@ -1063,7 +1063,7 @@ private void evaluateExpression(OperationResult result) context.setDefaultSource(defaultSource); context.setSkipEvaluationMinus(!conditionResultOld); context.setSkipEvaluationPlus(!conditionResultNew); - context.setValuePolicyResolver(valuePolicyResolver); + context.setValuePolicySupplier(valuePolicySupplier); context.setExpressionFactory(expressionFactory); context.setMappingQName(mappingQName); context.setVariableProducer(variableProducer); diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingParser.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingParser.java index 095ded222bb..e97aa88b22c 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingParser.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/mapping/MappingParser.java @@ -85,9 +85,9 @@ private void parseTarget() throws SchemaException { outputPath = path.stripVariableSegment(); } } - if (m.valuePolicyResolver != null) { - m.valuePolicyResolver.setOutputDefinition(outputDefinition); - m.valuePolicyResolver.setOutputPath(outputPath); + if (m.valuePolicySupplier != null) { + m.valuePolicySupplier.setOutputDefinition(outputDefinition); + m.valuePolicySupplier.setOutputPath(outputPath); } } diff --git a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/util/PopulatorUtil.java b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/util/PopulatorUtil.java index 8ac0f41f7d6..e2d3cf722d5 100644 --- a/model/model-common/src/main/java/com/evolveum/midpoint/model/common/util/PopulatorUtil.java +++ b/model/model-common/src/main/java/com/evolveum/midpoint/model/common/util/PopulatorUtil.java @@ -109,7 +109,7 @@ private static MappingBuilder, PrismPropertyDefinition> cre PrismObjectDefinition userDefinition = getUserDefinition(); mappingBuilder.targetContext(userDefinition); - mappingBuilder.stringPolicyResolver((result) -> policy); + mappingBuilder.valuePolicySupplier((result) -> policy); // Default target if (defaultTargetPropertyPath != null) { PrismPropertyDefinition targetDefDefinition = userDefinition.findItemDefinition(defaultTargetPropertyPath); @@ -211,7 +211,7 @@ public MappingImpl, PrismPropertyDefinition> create builder.addVariableDefinition(ExpressionConstants.VAR_SHADOW, account.asPrismObject(), ShadowType.class); builder.addVariableDefinition(ExpressionConstants.VAR_PROJECTION, account.asPrismObject(), ShadowType.class); - builder.stringPolicyResolver((result) -> policy); + builder.valuePolicySupplier((result) -> policy); builder.originType(OriginType.INBOUND); builder.originObject(resource); diff --git a/model/model-impl/pom.xml b/model/model-impl/pom.xml index b033a35168c..5975beb9c93 100644 --- a/model/model-impl/pom.xml +++ b/model/model-impl/pom.xml @@ -146,10 +146,6 @@ com.google.guava guava - - commons-io - commons-io - commons-lang commons-lang 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 3660688c027..65f63ed455c 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 @@ -6,6 +6,20 @@ */ package com.evolveum.midpoint.model.impl.controller; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +import java.io.*; +import java.util.*; +import javax.xml.namespace.QName; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + import com.evolveum.midpoint.audit.api.AuditEventRecord; import com.evolveum.midpoint.audit.api.AuditEventStage; import com.evolveum.midpoint.audit.api.AuditEventType; @@ -26,12 +40,19 @@ import com.evolveum.midpoint.model.impl.util.ModelImplUtils; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.crypto.Protector; -import com.evolveum.midpoint.prism.delta.*; -import com.evolveum.midpoint.prism.path.*; +import com.evolveum.midpoint.prism.delta.ChangeType; +import com.evolveum.midpoint.prism.delta.DiffUtil; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemName; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.*; import com.evolveum.midpoint.prism.util.CloneUtil; -import com.evolveum.midpoint.provisioning.api.*; +import com.evolveum.midpoint.provisioning.api.ChangeNotificationDispatcher; +import com.evolveum.midpoint.provisioning.api.ProvisioningOperationOptions; +import com.evolveum.midpoint.provisioning.api.ProvisioningService; +import com.evolveum.midpoint.provisioning.api.ResourceEventDescription; import com.evolveum.midpoint.repo.api.PreconditionViolationException; import com.evolveum.midpoint.repo.api.RepoAddOptions; import com.evolveum.midpoint.repo.api.RepositoryService; @@ -72,20 +93,6 @@ import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.jetbrains.annotations.NotNull; -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.io.*; -import java.util.*; - -import static java.util.Collections.*; - /** * This used to be an interface, but it was switched to class for simplicity. I * don't expect that the implementation of the controller will be ever replaced. @@ -99,7 +106,7 @@ * * @author lazyman * @author Radovan Semancik - * + *

* Note: don't autowire this bean by implementing class (ModelController), as it is proxied by Spring AOP. * Use its interfaces instead. */ @@ -216,7 +223,7 @@ public PrismObject getObject(Class clazz, String oi throw e; } catch (ObjectNotFoundException e) { OP_LOGGER.debug("MODEL OP error getObject({},{},{}): {}: {}", clazz.getSimpleName(), oid, rawOptions, e.getClass().getSimpleName(), e.getMessage()); - if (GetOperationOptions.isAllowNotFound(rootOptions)){ + if (GetOperationOptions.isAllowNotFound(rootOptions)) { result.getLastSubresult().setStatus(OperationResultStatus.HANDLED_ERROR); } else { ModelImplUtils.recordFatalError(result, e); @@ -242,7 +249,7 @@ private void executeResolveOptions(@NotNull Containerable containerable, Collect if (options == null) { return; } - for (SelectorOptions option: options) { + for (SelectorOptions option : options) { if (GetOperationOptions.isResolve(option.getOptions())) { ObjectSelector selector = option.getSelector(); if (selector != null) { @@ -409,7 +416,7 @@ private Collection> executeChangesNon if (ModelExecuteOptions.isReevaluateSearchFilters(options)) { String m = "ReevaluateSearchFilters option is not fully supported for non-raw operations yet. Filters already present in the object will not be touched."; LOGGER.warn("{} Context = {}", m, context.debugDump()); - result.createSubresult(CLASS_NAME_WITH_DOT+"reevaluateSearchFilters").recordWarning(m); + result.createSubresult(CLASS_NAME_WITH_DOT + "reevaluateSearchFilters").recordWarning(m); } context.setProgressListeners(statusListeners); @@ -440,8 +447,9 @@ private Collection> executeChangesNon cleanupOperationResult(result); return executedDeltas; - } catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException | ExpressionEvaluationException | - CommunicationException|ConfigurationException|PolicyViolationException|SecurityViolationException|RuntimeException e) { + } catch (ObjectAlreadyExistsException | ObjectNotFoundException | SchemaException + | ExpressionEvaluationException | CommunicationException | ConfigurationException + | PolicyViolationException | SecurityViolationException | RuntimeException e) { ModelImplUtils.recordFatalError(result, e); throw e; @@ -516,7 +524,7 @@ private Collection> executeChangesRaw } else if (delta.isDelete()) { QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); // MID-2218 try { - PrismObject existingObject = null; + PrismObject existingObject; try { existingObject = cacheRepositoryService.getObject(delta.getObjectTypeClass(), delta.getOid(), null, result1); objectToDetermineDetailsForAudit = existingObject; @@ -635,7 +643,7 @@ protected void cleanupOperationResult(OperationResult result) { } private void reevaluateSearchFilters(Class objectTypeClass, String oid, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { - OperationResult result = parentResult.createSubresult(CLASS_NAME_WITH_DOT+"reevaluateSearchFilters"); + OperationResult result = parentResult.createSubresult(CLASS_NAME_WITH_DOT + "reevaluateSearchFilters"); try { PrismObject storedObject = cacheRepositoryService.getObject(objectTypeClass, oid, null, result); PrismObject updatedObject = storedObject.clone(); @@ -654,8 +662,8 @@ private void reevaluateSearchFilters(Class objectTypeC } } result.recordSuccess(); - } catch (SchemaException|ObjectNotFoundException|ObjectAlreadyExistsException|RuntimeException e) { - result.recordFatalError("Couldn't reevaluate search filters: "+e.getMessage(), e); + } catch (SchemaException | ObjectNotFoundException | ObjectAlreadyExistsException | RuntimeException e) { + result.recordFatalError("Couldn't reevaluate search filters: " + e.getMessage(), e); throw e; } } @@ -709,7 +717,7 @@ public void recompute(Class type, String oid, ModelExe private void applyDefinitions(Collection> deltas, ModelExecuteOptions options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException, ExpressionEvaluationException { - for(ObjectDelta delta: deltas) { + for (ObjectDelta delta : deltas) { Class type = delta.getObjectTypeClass(); if (delta.hasCompleteDefinition()) { continue; @@ -828,7 +836,7 @@ public SearchResultList> searchObjects(Cla } catch (Throwable e) { if (exceptionInSearch) { - processSearchException(e, rootOptions, searchProvider, result); + processSearchException(e, searchProvider, result); } else { result.recordFatalError(e); } @@ -865,19 +873,17 @@ private class ContainerOperationContext { isCertCase = AccessCertificationCaseType.class.equals(type); isCaseMgmtWorkItem = CaseWorkItemType.class.equals(type); - if (!isCertCase && !isCaseMgmtWorkItem) { - throw new UnsupportedOperationException("searchContainers/countContainers methods are currently supported only for AccessCertificationCaseType and CaseWorkItemType classes"); - } + if (!isCertCase && !isCaseMgmtWorkItem) { + throw new UnsupportedOperationException("searchContainers/countContainers methods are currently supported only for AccessCertificationCaseType and CaseWorkItemType classes"); + } - if (isCertCase) { - refinedQuery = preProcessSubobjectQuerySecurity(AccessCertificationCaseType.class, AccessCertificationCampaignType.class, query, task, result); - manager = ObjectTypes.ObjectManager.REPOSITORY; - } else //noinspection ConstantConditions - if (isCaseMgmtWorkItem) { - refinedQuery = query; // TODO + if (isCertCase) { + refinedQuery = preProcessSubobjectQuerySecurity(AccessCertificationCaseType.class, AccessCertificationCampaignType.class, query, task, result); manager = ObjectTypes.ObjectManager.REPOSITORY; } else { - throw new IllegalStateException(); + assert isCaseMgmtWorkItem; + refinedQuery = query; // TODO + manager = ObjectTypes.ObjectManager.REPOSITORY; } } } @@ -919,13 +925,16 @@ public SearchResultList searchContainers( } //noinspection SwitchStatementWithTooFewBranches switch (ctx.manager) { - case REPOSITORY: list = cacheRepositoryService.searchContainers(type, query, options, result); break; - default: throw new IllegalStateException(); + case REPOSITORY: + list = cacheRepositoryService.searchContainers(type, query, options, result); + break; + default: + throw new IllegalStateException(); } result.computeStatus(); result.cleanupResult(); - } catch (SchemaException|RuntimeException e) { - processSearchException(e, rootOptions, ctx.manager, result); + } catch (SchemaException | RuntimeException e) { + processSearchException(e, ctx.manager, result); throw e; } finally { QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); @@ -982,21 +991,23 @@ public Integer countContainers( } enterModelMethod(); // outside try-catch because if this ends with an exception, cache is not entered yet - Integer count; + int count; try { - logQuery(query); try { //noinspection SwitchStatementWithTooFewBranches switch (ctx.manager) { - case REPOSITORY: count = cacheRepositoryService.countContainers(type, query, options, result); break; - default: throw new IllegalStateException(); + case REPOSITORY: + count = cacheRepositoryService.countContainers(type, query, options, result); + break; + default: + throw new IllegalStateException(); } result.computeStatus(); result.cleanupResult(); } catch (RuntimeException e) { - processSearchException(e, rootOptions, ctx.manager, result); + processSearchException(e, ctx.manager, result); throw e; } finally { if (LOGGER.isTraceEnabled()) { @@ -1132,15 +1143,22 @@ public SearchResultMetadata searchObjectsIterative(Class< try { switch (searchProvider) { - case REPOSITORY: metadata = cacheRepositoryService.searchObjectsIterative(type, processedQuery, internalHandler, options, true, result); break; - case PROVISIONING: metadata = provisioning.searchObjectsIterative(type, processedQuery, options, internalHandler, task, result); break; - case TASK_MANAGER: metadata = taskManager.searchObjectsIterative(type, processedQuery, options, internalHandler, result); break; - default: throw new AssertionError("Unexpected search provider: " + searchProvider); + case REPOSITORY: + metadata = cacheRepositoryService.searchObjectsIterative(type, processedQuery, internalHandler, options, true, result); + break; + case PROVISIONING: + metadata = provisioning.searchObjectsIterative(type, processedQuery, options, internalHandler, task, result); + break; + case TASK_MANAGER: + metadata = taskManager.searchObjectsIterative(type, processedQuery, options, internalHandler, result); + break; + default: + throw new AssertionError("Unexpected search provider: " + searchProvider); } result.computeStatusIfUnknown(); result.cleanupResult(); } catch (CommunicationException | ConfigurationException | ObjectNotFoundException | SchemaException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error e) { - processSearchException(e, rootOptions, searchProvider, result); + processSearchException(e, searchProvider, result); throw e; } finally { if (LOGGER.isTraceEnabled()) { @@ -1160,14 +1178,22 @@ public SearchResultMetadata searchObjectsIterative(Class< return metadata; } - private void processSearchException(Throwable e, GetOperationOptions rootOptions, - ObjectTypes.ObjectManager searchProvider, OperationResult result) { + private void processSearchException( + Throwable e, ObjectTypes.ObjectManager searchProvider, OperationResult result) { String message; switch (searchProvider) { - case REPOSITORY: message = "Couldn't search objects in repository"; break; - case PROVISIONING: message = "Couldn't search objects in provisioning"; break; - case TASK_MANAGER: message = "Couldn't search objects in task manager"; break; - default: message = "Couldn't search objects"; break; // should not occur + case REPOSITORY: + message = "Couldn't search objects in repository"; + break; + case PROVISIONING: + message = "Couldn't search objects in provisioning"; + break; + case TASK_MANAGER: + message = "Couldn't search objects in task manager"; + break; + default: + message = "Couldn't search objects"; + break; // should not occur } LoggingUtils.logUnexpectedException(LOGGER, message, e); result.recordFatalError(message, e); @@ -1211,7 +1237,8 @@ public Integer countObjects(Class type, ObjectQuery or case TASK_MANAGER: count = taskManager.countObjects(type, processedQuery, parentResult); break; - default: throw new AssertionError("Unexpected objectManager: " + objectManager); + default: + throw new AssertionError("Unexpected objectManager: " + objectManager); } } catch (ConfigurationException | SecurityViolationException | SchemaException | ObjectNotFoundException | CommunicationException | ExpressionEvaluationException | RuntimeException | Error e) { ModelImplUtils.recordFatalError(result, e); @@ -1286,7 +1313,7 @@ public PrismObject searchShadowOwner(String shadowOid, Coll public OperationResult testResource(String resourceOid, Task task) throws ObjectNotFoundException { Validate.notEmpty(resourceOid, "Resource oid must not be null or empty."); enterModelMethod(); - LOGGER.trace("Testing resource OID: {}", new Object[]{resourceOid}); + LOGGER.trace("Testing resource OID: {}", new Object[] { resourceOid }); OperationResult testResult; try { @@ -1327,8 +1354,8 @@ public void importFromResource(String resourceOid, QName objectClass, Task task, Validate.notNull(objectClass, "Object class must not be null."); Validate.notNull(task, "Task must not be null."); enterModelMethod(); - LOGGER.trace("Launching import from resource with oid {} for object class {}.", new Object[]{ - resourceOid, objectClass}); + LOGGER.trace("Launching import from resource with oid {} for object class {}.", new Object[] { + resourceOid, objectClass }); OperationResult result = parentResult.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE); result.addParam("resourceOid", resourceOid); @@ -1342,15 +1369,15 @@ public void importFromResource(String resourceOid, QName objectClass, Task task, resource = getObject(ResourceType.class, resourceOid, null, task, result).asObjectable(); if (resource.getSynchronization() == null || resource.getSynchronization().getObjectSynchronization().isEmpty()) { - OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE+".check"); - subresult.recordWarning("No synchronization settings in "+resource+", import will probably do nothing"); - LOGGER.warn("No synchronization settings in "+resource+", import will probably do nothing"); + OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE + ".check"); + subresult.recordWarning("No synchronization settings in " + resource + ", import will probably do nothing"); + LOGGER.warn("No synchronization settings in " + resource + ", import will probably do nothing"); } else { ObjectSynchronizationType syncType = resource.getSynchronization().getObjectSynchronization().iterator().next(); if (syncType.isEnabled() != null && !syncType.isEnabled()) { - OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE+".check"); - subresult.recordWarning("Synchronization is disabled for "+resource+", import will probably do nothing"); - LOGGER.warn("Synchronization is disabled for "+resource+", import will probably do nothing"); + OperationResult subresult = result.createSubresult(IMPORT_ACCOUNTS_FROM_RESOURCE + ".check"); + subresult.recordWarning("Synchronization is disabled for " + resource + ", import will probably do nothing"); + LOGGER.warn("Synchronization is disabled for " + resource + ", import will probably do nothing"); } } @@ -1400,10 +1427,9 @@ public void importFromResource(String shadowOid, Task task, OperationResult pare result.computeStatus(); } - result.cleanupResult(); - } catch (ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException| RuntimeException | Error ex) { + } catch (ObjectNotFoundException | CommunicationException | ConfigurationException | SecurityViolationException | ExpressionEvaluationException | RuntimeException | Error ex) { ModelImplUtils.recordFatalError(result, ex); throw ex; } finally { @@ -1416,26 +1442,18 @@ public void importFromResource(String shadowOid, Task task, OperationResult pare public void importObjectsFromFile(File input, ImportOptionsType options, Task task, OperationResult parentResult) throws FileNotFoundException { OperationResult result = parentResult.createSubresult(IMPORT_OBJECTS_FROM_FILE); - FileInputStream fis = null; - try { - fis = new FileInputStream(input); + + try (FileInputStream fis = new FileInputStream(input)) { + importObjectsFromStream(fis, PrismContext.LANG_XML, options, task, parentResult); } catch (FileNotFoundException e) { - IOUtils.closeQuietly(fis); String msg = "Error reading from file " + input + ": " + e.getMessage(); result.recordFatalError(msg, e); throw e; - } - try { - importObjectsFromStream(fis, PrismContext.LANG_XML, options, task, parentResult); } catch (RuntimeException e) { result.recordFatalError(e); throw e; - } finally { - try { - fis.close(); - } catch (IOException e) { - LOGGER.error("Error closing file " + input + ": " + e.getMessage(), e); - } + } catch (IOException e) { + LOGGER.error("Error closing file " + input + ": " + e.getMessage(), e); } result.computeStatus(); } @@ -1483,14 +1501,13 @@ public Set discoverConnectors(ConnectorHostType hostType, Task ta throw e; } List connectorList = new ArrayList<>(discoverConnectors); - schemaTransformer.applySchemasAndSecurityToObjectTypes(connectorList, null, null,null, task, result); + schemaTransformer.applySchemasAndSecurityToObjectTypes(connectorList, null, null, null, task, result); result.computeStatus("Connector discovery failed"); exitModelMethod(); result.cleanupResult(); return new HashSet<>(connectorList); } - /* * (non-Javadoc) * @@ -1797,7 +1814,7 @@ public PrismObject getTaskByIdentifier(String identifier, Collection task = taskManager.getTaskTypeByIdentifier(identifier, options, parentResult); GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); task = task.cloneIfImmutable(); - schemaTransformer.applySchemasAndSecurity(task, rootOptions, options,null, null, parentResult); + schemaTransformer.applySchemasAndSecurity(task, rootOptions, options, null, null, parentResult); return task; } @@ -1938,7 +1955,7 @@ private void auditTaskOperation(PrismReferenceValue taskRef, AuditEventType even auditRecord.setTarget(taskRef); ObjectDelta delta; if (AuditEventType.DELETE_OBJECT == event) { - delta = prismContext.deltaFactory().object().createDeleteDelta(TaskType.class, taskRef.getOid()); + delta = prismContext.deltaFactory().object().createDeleteDelta(TaskType.class, taskRef.getOid()); } else { //TODO should we somehow indicate deltas which are executed in taskManager? delta = prismContext.deltaFactory().object().createEmptyModifyDelta(TaskType.class, taskRef.getOid()); @@ -2121,7 +2138,9 @@ public AccessCertificationCampaignType createCampaign(String definitionOid, Task @Override public Collection> mergeObjects(Class type, String leftOid, String rightOid, String mergeConfigurationName, Task task, OperationResult parentResult) - throws ObjectNotFoundException, SchemaException, ConfigurationException, ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, PolicyViolationException, SecurityViolationException { + throws ObjectNotFoundException, SchemaException, ConfigurationException, + ObjectAlreadyExistsException, ExpressionEvaluationException, CommunicationException, + PolicyViolationException, SecurityViolationException { OperationResult result = parentResult.createSubresult(MERGE_OBJECTS); result.addParam("leftOid", leftOid); @@ -2145,7 +2164,6 @@ public Collection> deltas) { - for(ObjectDelta delta: deltas) { + for (ObjectDelta delta : deltas) { delta.accept(this::computePolyStringVisit); } } @@ -2281,14 +2299,14 @@ private void computePolyStringVisit(Visitable visitable) { if (!(visitable instanceof PrismProperty)) { return; } - PrismPropertyDefinition definition = ((PrismProperty)visitable).getDefinition(); + PrismPropertyDefinition definition = ((PrismProperty) visitable).getDefinition(); if (definition == null) { return; } if (!QNameUtil.match(PolyStringType.COMPLEX_TYPE, definition.getTypeName())) { return; } - for (PrismPropertyValue pval : ((PrismProperty)visitable).getValues()) { + for (PrismPropertyValue pval : ((PrismProperty) visitable).getValues()) { PolyString polyString = pval.getValue(); if (polyString.getOrig() == null) { String orig = localizationService.translate(polyString); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelDiagController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelDiagController.java index f3d2bf1bbac..fbe4f86cd0c 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelDiagController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelDiagController.java @@ -11,47 +11,44 @@ import java.io.RandomAccessFile; import java.util.Collection; import java.util.List; - import javax.xml.namespace.QName; -import com.evolveum.midpoint.common.configuration.api.MidpointConfiguration; -import com.evolveum.midpoint.model.api.DataModelVisualizer; -import com.evolveum.midpoint.model.common.SystemObjectCache; -import com.evolveum.midpoint.prism.path.ItemName; -import com.evolveum.midpoint.schema.*; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters; -import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer; -import com.evolveum.midpoint.util.SystemUtil; -import com.evolveum.midpoint.util.exception.*; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import org.apache.commons.io.IOUtils; import org.apache.commons.text.StringSubstitutor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; +import com.evolveum.midpoint.common.configuration.api.MidpointConfiguration; +import com.evolveum.midpoint.model.api.DataModelVisualizer; import com.evolveum.midpoint.model.api.ModelDiagnosticService; +import com.evolveum.midpoint.model.common.SystemObjectCache; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.PrismProperty; +import com.evolveum.midpoint.prism.path.ItemName; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.provisioning.api.ProvisioningService; import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.schema.*; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.security.enforcer.api.AuthorizationParameters; +import com.evolveum.midpoint.security.enforcer.api.SecurityEnforcer; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.RandomString; +import com.evolveum.midpoint.util.SystemUtil; +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.*; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; /** * @author semancik - * */ @Component public class ModelDiagController implements ModelDiagnosticService { @@ -67,8 +64,8 @@ public class ModelDiagController implements ModelDiagnosticService { private static final String USER_FULL_NAME = "Grăfula Fèlix Teleke z Tölökö"; private static final String USER_GIVEN_NAME = "Fëľïx"; private static final String USER_FAMILY_NAME = "Ţæĺêké"; - private static final String[] USER_ORGANIZATION = {"COMITATVS NOBILITVS HVNGARIÆ", "Salsa Verde ğomorula prïvatûła"}; - private static final String[] USER_EMPLOYEE_TYPE = {"Ģŗąfųŀą", "CANTATOR"}; + private static final String[] USER_ORGANIZATION = { "COMITATVS NOBILITVS HVNGARIÆ", "Salsa Verde ğomorula prïvatûła" }; + private static final String[] USER_EMPLOYEE_TYPE = { "Ģŗąfųŀą", "CANTATOR" }; private static final String INSANE_NATIONAL_STRING = "Pørúga ném nå väšȍm apârátula"; @@ -89,7 +86,7 @@ public class ModelDiagController implements ModelDiagnosticService { @Autowired private MidpointConfiguration midpointConfiguration; @Autowired private SystemObjectCache systemObjectCache; - private RandomString randomString; + private final RandomString randomString; ModelDiagController() { randomString = new RandomString(NAME_RANDOM_LENGTH, true); @@ -112,8 +109,8 @@ public OperationResult repositorySelfTest(Task task) { // Give repository chance to run its own self-test if available repositoryService.repositorySelfTest(testResult); - repositorySelfTestUser(task, testResult); - repositorySelfTestLookupTable(task, testResult); + repositorySelfTestUser(testResult); + repositorySelfTestLookupTable(testResult); testResult.computeStatus(); return testResult; @@ -161,10 +158,11 @@ public RepositoryQueryDiagResponse executeRepositoryQuery(RepositoryQueryDiagReq } @Override - public MappingEvaluationResponseType evaluateMapping(MappingEvaluationRequestType request, Task task, - OperationResult parentResult) - throws SchemaException, SecurityViolationException, ExpressionEvaluationException, - ObjectNotFoundException, CommunicationException, SecurityViolationException, ConfigurationException { + public MappingEvaluationResponseType evaluateMapping( + MappingEvaluationRequestType request, Task task, OperationResult parentResult) + throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, + CommunicationException, SecurityViolationException, ConfigurationException { + OperationResult result = parentResult.createSubresult(EXECUTE_REPOSITORY_QUERY); try { securityEnforcer.authorize(AuthorizationConstants.AUTZ_ALL_URL, null, AuthorizationParameters.EMPTY, null, task, result); @@ -192,7 +190,7 @@ public ProvisioningDiag getProvisioningDiag(Task task, OperationResult parentRes return provisioningService.getProvisioningDiag(); } - private void repositorySelfTestUser(Task task, OperationResult testResult) { + private void repositorySelfTestUser(OperationResult testResult) { OperationResult result = testResult.createSubresult(REPOSITORY_SELF_TEST_USER); PrismObject user; @@ -246,7 +244,6 @@ private void repositorySelfTestUser(Task task, OperationResult testResult) { return; } - } finally { try { @@ -287,7 +284,7 @@ private boolean repositorySelfTestUserSearch(String userName, ItemName itemName, } private boolean repositorySelfTestUserGet(String name, String oid, OperationResult result) { - OperationResult subresult = result.createSubresult(result.getOperation()+".getObject"); + OperationResult subresult = result.createSubresult(result.getOperation() + ".getObject"); PrismObject userRetrieved; try { @@ -318,7 +315,7 @@ private void checkUser(PrismObject userRetrieved, String name, Operati checkObjectPropertyPolyString(userRetrieved, UserType.F_ORGANIZATION, subresult, USER_ORGANIZATION); } - private void repositorySelfTestLookupTable(Task task, OperationResult testResult) { + private void repositorySelfTestLookupTable(OperationResult testResult) { OperationResult result = testResult.createSubresult(REPOSITORY_SELF_TEST_LOOKUP_TABLE); PrismObject lookupTable; @@ -371,14 +368,16 @@ private void repositorySelfTestLookupTable(Task task, OperationResult testResult } private boolean repositorySelfTestLookupTableGetKey(OperationResult result, String name, String oid) { - OperationResult subresult = result.createSubresult(result.getOperation()+".getObject.key"); + OperationResult subresult = result.createSubresult(result.getOperation() + ".getObject.key"); try { + // @formatter:off GetOperationOptionsBuilder optionsBuilder = schemaHelper.getOperationOptionsBuilder() .item(LookupTableType.F_ROW) .retrieveQuery() .item(LookupTableRowType.F_KEY) .eq(INSANE_NATIONAL_STRING) .end(); + // @formatter:on PrismObject lookupTableRetrieved = repositoryService.getObject(LookupTableType.class, oid, optionsBuilder.build(), result); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Self-test:lookupTable getObject by row key:\n{}", DebugUtil.debugDump(lookupTableRetrieved)); @@ -393,7 +392,7 @@ private boolean repositorySelfTestLookupTableGetKey(OperationResult result, Stri } private boolean repositorySelfTestLookupTableGet(OperationResult result, String name, String oid) { - OperationResult subresult = result.createSubresult(result.getOperation()+".getObject"); + OperationResult subresult = result.createSubresult(result.getOperation() + ".getObject"); PrismObject lookupTableRetrieved; try { @@ -424,38 +423,42 @@ private void checkLookupTable(PrismObject lookupTable, String n assertPolyStringType("Unexpected label value", INSANE_NATIONAL_STRING, rowType.getLabel(), subresult); } - private void assertSingleSearchResult(String objectTypeMessage, List> foundObjects, OperationResult parentResult) { - OperationResult result = parentResult.createSubresult(parentResult.getOperation()+".numberOfResults"); - assertTrue("Found no "+objectTypeMessage, !foundObjects.isEmpty(), result); - assertTrue("Expected to find a single "+objectTypeMessage+" but found "+foundObjects.size(), foundObjects.size() == 1, result); + private void assertSingleSearchResult(String objectTypeMessage, + List> foundObjects, OperationResult parentResult) { + OperationResult result = parentResult.createSubresult(parentResult.getOperation() + ".numberOfResults"); + assertTrue("Found no " + objectTypeMessage, !foundObjects.isEmpty(), result); + assertTrue("Expected to find a single " + objectTypeMessage + " but found " + foundObjects.size(), foundObjects.size() == 1, result); result.recordSuccessIfUnknown(); } - private void checkObjectProperty(PrismObject object, QName propQName, OperationResult parentResult, T... expectedValues) { + private void checkObjectProperty( + PrismObject object, QName propQName, OperationResult parentResult, T... expectedValues) { String propName = propQName.getLocalPart(); OperationResult result = parentResult.createSubresult(parentResult.getOperation() + ".checkObjectProperty." + propName); PrismProperty prop = object.findProperty(ItemName.fromQName(propQName)); Collection actualValues = prop.getRealValues(); result.addArbitraryObjectCollectionAsParam("actualValues", actualValues); - assertMultivalue("User, property '"+propName+"'", expectedValues, actualValues, result); + assertMultivalue("User, property '" + propName + "'", expectedValues, actualValues, result); result.recordSuccessIfUnknown(); } - private void assertMultivalue(String message, T[] expectedVals, Collection actualVals, OperationResult result) { + private void assertMultivalue(String message, + T[] expectedVals, Collection actualVals, OperationResult result) { if (expectedVals.length != actualVals.size()) { - fail(message+": expected "+expectedVals.length+" values but has "+actualVals.size()+" values: "+actualVals, result); + fail(message + ": expected " + expectedVals.length + " values but has " + + actualVals.size() + " values: " + actualVals, result); return; } - for (T expected: expectedVals) { + for (T expected : expectedVals) { boolean found = false; - for (T actual: actualVals) { + for (T actual : actualVals) { if (expected.equals(actual)) { found = true; break; } } if (!found) { - fail(message+": expected value '"+expected+"' not found in actual values "+actualVals, result); + fail(message + ": expected value '" + expected + "' not found in actual values " + actualVals, result); return; } } @@ -467,39 +470,42 @@ private void checkObjectPropertyPolyString(PrismObject PrismProperty prop = object.findProperty(ItemName.fromQName(propQName)); Collection actualValues = prop.getRealValues(); result.addArbitraryObjectCollectionAsParam("actualValues", actualValues); - assertMultivaluePolyString("User, property '"+propName+"'", expectedValues, actualValues, result); + assertMultivaluePolyString("User, property '" + propName + "'", expectedValues, actualValues, result); result.recordSuccessIfUnknown(); } private void assertMultivaluePolyString(String message, String[] expectedOrigs, Collection actualPolyStrings, OperationResult result) { if (expectedOrigs.length != actualPolyStrings.size()) { - fail(message+": expected "+expectedOrigs.length+" values but has "+actualPolyStrings.size()+" values: "+actualPolyStrings, result); + fail(message + ": expected " + expectedOrigs.length + " values but has " + actualPolyStrings.size() + " values: " + actualPolyStrings, result); return; } - for (String expectedOrig: expectedOrigs) { + for (String expectedOrig : expectedOrigs) { boolean found = false; - for (PolyString actualPolyString: actualPolyStrings) { + for (PolyString actualPolyString : actualPolyStrings) { if (expectedOrig.equals(actualPolyString.getOrig())) { found = true; - assertEquals(message+ ", norm", polyStringNorm(expectedOrig), actualPolyString.getNorm(), result); + assertEquals(message + ", norm", polyStringNorm(expectedOrig), actualPolyString.getNorm(), result); break; } } if (!found) { - fail(message+": expected value '"+expectedOrig+"' not found in actual values "+actualPolyStrings, result); + fail(message + ": expected value '" + expectedOrig + "' not found in actual values " + actualPolyStrings, result); return; } } } - private void assertPolyString(String message, String expectedOrig, PolyString actualPolyString, OperationResult result) { - assertEquals(message+ ", orig", expectedOrig, actualPolyString.getOrig(), result); - assertEquals(message+ ", norm", polyStringNorm(expectedOrig), actualPolyString.getNorm(), result); + // TODO: is it used occasionally? If not let it go + private void assertPolyString(String message, + String expectedOrig, PolyString actualPolyString, OperationResult result) { + assertEquals(message + ", orig", expectedOrig, actualPolyString.getOrig(), result); + assertEquals(message + ", norm", polyStringNorm(expectedOrig), actualPolyString.getNorm(), result); } - private void assertPolyStringType(String message, String expectedName, PolyStringType actualPolyStringType, OperationResult result) { - assertEquals(message+ ", orig", expectedName, actualPolyStringType.getOrig(), result); - assertEquals(message+ ", norm", polyStringNorm(expectedName), actualPolyStringType.getNorm(), result); + private void assertPolyStringType(String message, + String expectedName, PolyStringType actualPolyStringType, OperationResult result) { + assertEquals(message + ", orig", expectedName, actualPolyStringType.getOrig(), result); + assertEquals(message + ", norm", polyStringNorm(expectedName), actualPolyStringType.getNorm(), result); } private String polyStringNorm(String orig) { @@ -514,7 +520,7 @@ private void assertTrue(String message, boolean condition, OperationResult resul private void assertEquals(String message, Object expected, Object actual, OperationResult result) { if (!MiscUtil.equals(expected, actual)) { - fail(message + "; expected "+expected+", actual "+actual, result); + fail(message + "; expected " + expected + ", actual " + actual, result); } } @@ -539,7 +545,6 @@ private PolyString toPolyString(String orig) { return polyString; } - private PrismObjectDefinition getObjectDefinition(Class type) { return prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(type); } @@ -592,9 +597,7 @@ public LogFileContentType getLogFileContent(Long fromPosition, Long maxSize, Tas private LogFileContentType getLogFileFragment(File logFile, Long fromPosition, Long maxSize) throws IOException { LogFileContentType rv = new LogFileContentType(); - RandomAccessFile log = null; - try { - log = new RandomAccessFile(logFile, "r"); + try (RandomAccessFile log = new RandomAccessFile(logFile, "r")) { long currentLength = log.length(); rv.setLogFileSize(currentLength); @@ -624,10 +627,6 @@ private LogFileContentType getLogFileFragment(File logFile, Long fromPosition, L log.readFully(buffer); rv.setContent(new String(buffer)); return rv; - } finally { - if (log != null) { - IOUtils.closeQuietly(log); - } } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java index 9c2387c23df..7d29fcb8869 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/MidpointFunctionsImpl.java @@ -1158,7 +1158,7 @@ public ObjectDeltaType getResourceDelta(ModelContext context, String resourceOid @Override public long getSequenceCounter(String sequenceOid) throws ObjectNotFoundException, SchemaException { - return SequentialValueExpressionEvaluator.getSequenceCounter(sequenceOid, repositoryService, getCurrentResult()); + return SequentialValueExpressionEvaluator.getSequenceCounterValue(sequenceOid, repositoryService, getCurrentResult()); } // orgstruct related methods diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluator.java index 60d99626b1c..624cf4b3428 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluator.java @@ -27,17 +27,26 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SequentialValueExpressionEvaluatorType; +import org.jetbrains.annotations.NotNull; + /** - * @author semancik + * Returns current value of a given sequence object. The value is returned in the zero set. Plus and minus sets are empty. + * The value for a given sequence OID is stored in the model context, so it is returned each time this evaluator (with given + * sequence OID) is invoked. * + * @author semancik */ -public class SequentialValueExpressionEvaluator extends AbstractExpressionEvaluator { +public class SequentialValueExpressionEvaluator + extends AbstractExpressionEvaluator { + @NotNull private final String sequenceOid; private final RepositoryService repositoryService; - SequentialValueExpressionEvaluator(QName elementName, SequentialValueExpressionEvaluatorType sequentialValueEvaluatorType, - D outputDefinition, Protector protector, RepositoryService repositoryService, PrismContext prismContext) { + SequentialValueExpressionEvaluator(QName elementName, @NotNull String sequenceOid, + SequentialValueExpressionEvaluatorType sequentialValueEvaluatorType, D outputDefinition, + Protector protector, RepositoryService repositoryService, PrismContext prismContext) { super(elementName, sequentialValueEvaluatorType, outputDefinition, protector, prismContext); + this.sequenceOid = sequenceOid; this.repositoryService = repositoryService; } @@ -47,35 +56,47 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, SecurityViolationException { checkEvaluatorProfile(context); - long counter = getSequenceCounter(expressionEvaluatorBean.getSequenceRef().getOid(), repositoryService, result); + long counterValue = getSequenceCounterValue(sequenceOid, repositoryService, result); - Object value = ExpressionUtil.convertToOutputValue(counter, outputDefinition, protector); - - //noinspection unchecked - Item output = outputDefinition.instantiate(); - if (output instanceof PrismProperty) { - ((PrismProperty)output).addRealValue(value); - } else { - throw new UnsupportedOperationException("Can only generate values of property, not "+output.getClass()); - } + Object value = ExpressionUtil.convertToOutputValue(counterValue, outputDefinition, protector); + Item output = addValueToOutputProperty(value); return ItemDeltaUtil.toDeltaSetTriple(output, null, prismContext); } - static long getSequenceCounter(String sequenceOid, RepositoryService repositoryService, OperationResult result) throws ObjectNotFoundException, SchemaException { + /** + * Returns sequence counter value for this clockwork run. + * + * Because mappings are evaluated repeatedly, the value is obtained from the repository only for the first time. + * Then it is stored in model context to be reused as needed. + */ + static long getSequenceCounterValue(String sequenceOid, RepositoryService repositoryService, OperationResult result) throws ObjectNotFoundException, SchemaException { ModelContext ctx = ModelExpressionThreadLocalHolder.getLensContextRequired(); - Long counter = ctx.getSequenceCounter(sequenceOid); - if (counter == null) { - counter = repositoryService.advanceSequence(sequenceOid, result); - ctx.setSequenceCounter(sequenceOid, counter); + Long alreadyObtainedValue = ctx.getSequenceCounter(sequenceOid); + if (alreadyObtainedValue != null) { + return alreadyObtainedValue; + } else { + long freshValue = repositoryService.advanceSequence(sequenceOid, result); + ctx.setSequenceCounter(sequenceOid, freshValue); + return freshValue; } + } - return counter; + @NotNull + private Item addValueToOutputProperty(Object value) throws SchemaException { + //noinspection unchecked + Item output = outputDefinition.instantiate(); + if (output instanceof PrismProperty) { + ((PrismProperty)output).addRealValue(value); + } else { + throw new UnsupportedOperationException("Can only provide values of property, not "+output.getClass()); + } + return output; } @Override public String shortDebugDump() { - return "sequentialValue: "+ expressionEvaluatorBean.getSequenceRef().getOid(); + return "sequentialValue: "+ sequenceOid; } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluatorFactory.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluatorFactory.java index be5a259baaf..57b4b23901e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluatorFactory.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/expr/SequentialValueExpressionEvaluatorFactory.java @@ -57,11 +57,11 @@ public ExpressionEvaluator cr SequentialValueExpressionEvaluatorType evaluatorBean = getSingleEvaluatorBeanRequired(evaluatorElements, SequentialValueExpressionEvaluatorType.class, contextDescription); - if (evaluatorBean.getSequenceRef() == null || evaluatorBean.getSequenceRef().getOid() == null) { + if (evaluatorBean.getSequenceRef() != null && evaluatorBean.getSequenceRef().getOid() != null) { + return new SequentialValueExpressionEvaluator<>(ELEMENT_NAME, evaluatorBean.getSequenceRef().getOid(), evaluatorBean, + outputDefinition, protector, repositoryService, prismContext); + } else { throw new SchemaException("Missing sequence reference in sequentialValue expression evaluator in "+contextDescription); } - - return new SequentialValueExpressionEvaluator<>(ELEMENT_NAME, evaluatorBean, outputDefinition, protector, - repositoryService, prismContext); } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/construction/EvaluatedOutboundConstructionImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/construction/EvaluatedOutboundConstructionImpl.java index f8fbe93e173..28305946ea0 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/construction/EvaluatedOutboundConstructionImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/construction/EvaluatedOutboundConstructionImpl.java @@ -22,7 +22,7 @@ import com.evolveum.midpoint.model.impl.lens.projector.mappings.NextRecompute; import com.evolveum.midpoint.prism.util.ObjectDeltaObject; -import com.evolveum.midpoint.repo.common.expression.ConfigurableValuePolicyResolver; +import com.evolveum.midpoint.repo.common.expression.ConfigurableValuePolicySupplier; import com.evolveum.midpoint.schema.constants.ExpressionConstants; import org.jetbrains.annotations.NotNull; @@ -231,7 +231,7 @@ private MappingImpl evalu } } - ConfigurableValuePolicyResolver valuePolicyResolver = new ConfigurableValuePolicyResolver() { + ConfigurableValuePolicySupplier valuePolicySupplier = new ConfigurableValuePolicySupplier() { private ItemDefinition outputDefinition; @Override @@ -240,7 +240,7 @@ public void setOutputDefinition(ItemDefinition outputDefinition) { } @Override - public ValuePolicyType resolve(OperationResult result) { + public ValuePolicyType get(OperationResult result) { if (mappingBuilder.getMappingBean().getExpression() != null) { List> evaluators = mappingBuilder.getMappingBean().getExpression().getExpressionEvaluator(); @@ -263,7 +263,7 @@ public ValuePolicyType resolve(OperationResult result) { return null; } }; - mappingBuilder.valuePolicyResolver(valuePolicyResolver); + mappingBuilder.valuePolicySupplier(valuePolicySupplier); // TODO: other variables? // Set condition masks. There are used as a brakes to avoid evaluating to nonsense values in case user is not present diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java index 13b728991fa..5279cd75715 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/credentials/ProjectionCredentialsProcessor.java @@ -20,7 +20,7 @@ import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.*; import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.repo.common.expression.ConfigurableValuePolicyResolver; +import com.evolveum.midpoint.repo.common.expression.ConfigurableValuePolicySupplier; import com.evolveum.midpoint.schema.CapabilityUtil; import com.evolveum.midpoint.util.LocalizableMessageBuilder; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -163,7 +163,7 @@ private void processProjectionPasswordMapping(LensContext< ItemDeltaItem, PrismPropertyDefinition> focusPasswordIdi = focusContext .getObjectDeltaObject().findIdi(SchemaConstants.PATH_PASSWORD_VALUE); - ConfigurableValuePolicyResolver valuePolicyResolver = (result1) -> SecurityUtil.getPasswordPolicy(securityPolicy); + ConfigurableValuePolicySupplier valuePolicySupplier = (result1) -> SecurityUtil.getPasswordPolicy(securityPolicy); MappingInitializer,PrismPropertyDefinition> initializer = (builder) -> { @@ -172,7 +172,7 @@ private void processProjectionPasswordMapping(LensContext< .implicitTargetPath(SchemaConstants.PATH_PASSWORD_VALUE); builder.defaultTargetDefinition(projPasswordPropertyDefinition); builder.defaultSource(new Source<>(focusPasswordIdi, ExpressionConstants.VAR_INPUT_QNAME)); - builder.valuePolicyResolver(valuePolicyResolver); + builder.valuePolicySupplier(valuePolicySupplier); return builder; }; diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/InboundProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/InboundProcessor.java index da45814fed7..f851928c9b8 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/InboundProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/focus/InboundProcessor.java @@ -714,7 +714,7 @@ private vo .addVariableDefinition(ExpressionConstants.VAR_CONFIGURATION, context.getSystemConfiguration(), context.getSystemConfiguration().getDefinition()) .addVariableDefinition(ExpressionConstants.VAR_OPERATION, context.getFocusContext().getOperation().getValue(), String.class) .variableResolver(variableProducer) - .valuePolicyResolver(createStringPolicyResolver(context)) + .valuePolicySupplier(createStringPolicyResolver(context)) .originType(OriginType.INBOUND) .originObject(resource); @@ -1180,8 +1180,8 @@ private void resolveEntitlementsIfNeeded(ContainerDelta a } } - private ConfigurableValuePolicyResolver createStringPolicyResolver(final LensContext context) { - return new ConfigurableValuePolicyResolver() { + private ConfigurableValuePolicySupplier createStringPolicyResolver(final LensContext context) { + return new ConfigurableValuePolicySupplier() { private ItemDefinition outputDefinition; @Override @@ -1190,7 +1190,7 @@ public void setOutputDefinition(ItemDefinition outputDefinition) { } @Override - public ValuePolicyType resolve(OperationResult result) { + public ValuePolicyType get(OperationResult result) { if (outputDefinition.getItemName().equals(PasswordType.F_VALUE)) { return credentialsProcessor.determinePasswordPolicy(context.getFocusContext()); } else { @@ -1300,7 +1300,7 @@ private void processSpecialPropertyInbound(Collection void collectAutoassignMappings(LensCon if (focalAutoassignSpec == null) { return true; } + + if (!isApplicableFor(focalAutoassignSpec.getSelector(), context.getFocusContext(), objectResult)) { + return true; + } + for (AutoassignMappingType autoMapping: focalAutoassignSpec.getMapping()) { AutoassignMappingType mapping = autoMapping.clone(); setMappingTarget(mapping, new ItemPathType(SchemaConstants.PATH_ASSIGNMENT)); @@ -470,6 +456,19 @@ private void collectAutoassignMappings(LensCon cacheRepositoryService.searchObjectsIterative(AbstractRoleType.class, query, handler, GetOperationOptions.createReadOnlyCollection(), true, result); } + private boolean isApplicableFor(ObjectSelectorType selector, LensFocusContext focusContext, OperationResult result) { + if (selector == null) { + return true; + } + try { + return cacheRepositoryService.selectorMatches(selector, focusContext.getObjectAny(), null, LOGGER, ""); + } catch (SchemaException | SecurityViolationException | ExpressionEvaluationException | CommunicationException | ObjectNotFoundException | ConfigurationException e) { + LOGGER.error("Failed to evaluate selector constraints, selector {}, focusContext {}\nReason: {}", selector, focusContext, e.getMessage(), e); + result.recordFatalError("Failed to evaluate selector constrains, selector: " + selector + ", focusContext: " + focusContext + "\nReason: " + e.getMessage(), e); + throw new SystemException(e); + } + } + private void setMappingTarget(MappingType mapping, ItemPathType path) { VariableBindingDefinitionType target = mapping.getTarget(); if (target == null) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java index 501f38162d4..08a97899805 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/mappings/MappingEvaluator.java @@ -572,7 +572,7 @@ MappingImpl createFocusMapping( return null; } - ConfigurableValuePolicyResolver valuePolicyResolver = new ConfigurableValuePolicyResolver() { + ConfigurableValuePolicySupplier valuePolicySupplier = new ConfigurableValuePolicySupplier() { private ItemDefinition outputDefinition; @Override @@ -581,7 +581,7 @@ public void setOutputDefinition(ItemDefinition outputDefinition) { } @Override - public ValuePolicyType resolve(OperationResult result) { + public ValuePolicyType get(OperationResult result) { // TODO need to switch to ObjectValuePolicyEvaluator if (outputDefinition.getItemName().equals(PasswordType.F_VALUE)) { return credentialsProcessor.determinePasswordPolicy(context.getFocusContext()); @@ -636,7 +636,7 @@ public ValuePolicyType resolve(OperationResult result) { .originType(OriginType.USER_POLICY) .originObject(originObject) .objectResolver(objectResolver) - .valuePolicyResolver(valuePolicyResolver) + .valuePolicySupplier(valuePolicySupplier) .rootNode(focusOdo) .mappingPreExpression(request.getMappingPreExpression()) // Used to populate autoassign assignments .now(now); diff --git a/model/model-impl/src/main/resources/ctx-model.xml b/model/model-impl/src/main/resources/ctx-model.xml index 08399417213..8cc5e075cea 100644 --- a/model/model-impl/src/main/resources/ctx-model.xml +++ b/model/model-impl/src/main/resources/ctx-model.xml @@ -123,7 +123,7 @@ + class="com.evolveum.midpoint.model.common.expression.evaluator.path.PathExpressionEvaluatorFactory"> diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestAutoassign.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestAutoassign.java index 08232a4986f..a772a2bfaae 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestAutoassign.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/rbac/TestAutoassign.java @@ -10,6 +10,10 @@ import javax.xml.datatype.XMLGregorianCalendar; +import com.evolveum.midpoint.prism.path.ItemPath; + +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; + import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ContextConfiguration; @@ -20,11 +24,6 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.test.DummyResourceContoller; -import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleManagementConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; /** * @author semancik @@ -47,9 +46,14 @@ public class TestAutoassign extends AbstractRbacTest { protected static final String ROLE_UNIT_WALKER_OID = "a2bc45fc-bfec-11e7-bdfd-af4b3e689502"; protected static final String ROLE_UNIT_WALKER_TITLE = "Walker"; + protected static final File ROLE_UNIT_RIDER_FILE = new File(AUTOASSIGN_DIR, "role-unit-rider.xml"); + protected static final String ROLE_UNIT_RIDER_OID = "9a60cdc6-f2ad-4414-964b-5fd1dfaec157"; + protected static final String ROLE_UNIT_RIDER_TITLE = "Rider"; + protected static final String UNIT_WORKER = "worker"; protected static final String UNIT_SLEEPER = "sleeper"; protected static final String UNIT_WALKER = "walker"; + protected static final String UNIT_RIDER = "rider"; private static final XMLGregorianCalendar ROLE_SLEEPER_AUTOASSIGN_VALID_TO = XmlTypeConverter.createXMLGregorianCalendar(2222, 1, 2, 3, 4, 5); @@ -62,16 +66,13 @@ public void initSystem(Task initTask, OperationResult initResult) repoAddObjectFromFile(ROLE_UNIT_WORKER_FILE, RoleType.class, initResult); repoAddObjectFromFile(ROLE_UNIT_SLEEPER_FILE, RoleType.class, initResult); repoAddObjectFromFile(ROLE_UNIT_WALKER_FILE, RoleType.class, initResult); + repoAddObjectFromFile(ROLE_UNIT_RIDER_FILE, RoleType.class, initResult); + + repoAddObjectFromFile(ARCHETYPE_EMPLOYEE_FILE, ArchetypeType.class, initResult); - // Temporarily using repository service because of MID-5497 - repositoryService.modifyObject(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), - prismContext.deltaFor(SystemConfigurationType.class) - .item(SystemConfigurationType.F_ROLE_MANAGEMENT, RoleManagementConfigurationType.F_AUTOASSIGN_ENABLED) - .replace(true) - .asItemDeltas(), initResult); -// modifyObjectReplaceProperty(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), -// ItemPath.create(SystemConfigurationType.F_ROLE_MANAGEMENT, RoleManagementConfigurationType.F_AUTOASSIGN_ENABLED), -// initTask, initResult, Boolean.TRUE); + modifyObjectReplaceProperty(SystemConfigurationType.class, SystemObjectsType.SYSTEM_CONFIGURATION.value(), + ItemPath.create(SystemConfigurationType.F_ROLE_MANAGEMENT, RoleManagementConfigurationType.F_AUTOASSIGN_ENABLED), + initTask, initResult, Boolean.TRUE); } /** @@ -239,6 +240,126 @@ public void test114ModifyUnitAddSleeper() throws Exception { ROLE_UNIT_WORKER_TITLE, ROLE_UNIT_WALKER_TITLE, ROLE_UNIT_SLEEPER_TITLE); } + @Test + public void test115ModifyUnitAddRider() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + // WHEN + modifyUserAdd(USER_JACK_OID, UserType.F_ORGANIZATIONAL_UNIT, task, result, + createPolyString(UNIT_RIDER)); + + // THEN + assertSuccess(result); + + assertUserAfter(USER_JACK_OID) + .assertOrganizationalUnits(UNIT_WORKER, UNIT_WALKER, UNIT_SLEEPER, UNIT_RIDER) + .assignments() + .assertAssignments(3) + .assertRole(ROLE_UNIT_WORKER_OID) + .assertRole(ROLE_UNIT_WALKER_OID) + .assertRole(ROLE_UNIT_SLEEPER_OID) + .assertNoRole(ROLE_UNIT_RIDER_OID) + .end() + .links() + .single(); + + assertDummyAccountByUsername(null, USER_JACK_USERNAME) + .assertAttribute(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_TITLE_NAME, + ROLE_UNIT_WORKER_TITLE, ROLE_UNIT_WALKER_TITLE, ROLE_UNIT_SLEEPER_TITLE); + } + + /** + * Prepare user guybrush for autoassignment + */ + @Test + public void test200assignArchetypeGuybrush() throws Exception { + // GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + //WHEN + assignArchetype(USER_GUYBRUSH_OID, ARCHETYPE_EMPLOYEE_OID, task, result); + + //THEN + assertUserAfter(USER_GUYBRUSH_OID) + .assertArchetypeRef(ARCHETYPE_EMPLOYEE_OID) + .assignments() + .assertAssignments(1) + .assertArchetype(ARCHETYPE_EMPLOYEE_OID) + .end(); + + } + + @Test + public void test201addUnitRiderGuybrush() throws Exception { + //GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + //WHEN + modifyUserAdd(USER_GUYBRUSH_OID, UserType.F_ORGANIZATIONAL_UNIT, task, result, createPolyString(UNIT_RIDER)); + + //THEN + assertUserAfter(USER_GUYBRUSH_OID) + .assertOrganizationalUnits(UNIT_RIDER) + .assertArchetypeRef(ARCHETYPE_EMPLOYEE_OID) + .assignments() + .assertAssignments(2) + .assertArchetype(ARCHETYPE_EMPLOYEE_OID) + .assertRole(ROLE_UNIT_RIDER_OID) + .end() + .links() + .single(); + } + + @Test + public void test202addUnitSleeperGuybrush() throws Exception { + //GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + //WHEN + modifyUserAdd(USER_GUYBRUSH_OID, UserType.F_ORGANIZATIONAL_UNIT, task, result, createPolyString(UNIT_SLEEPER)); + + //THEN + assertUserAfter(USER_GUYBRUSH_OID) + .assertOrganizationalUnits(UNIT_RIDER, UNIT_SLEEPER) + .assertArchetypeRef(ARCHETYPE_EMPLOYEE_OID) + .assignments() + .assertAssignments(3) + .assertArchetype(ARCHETYPE_EMPLOYEE_OID) + .assertRole(ROLE_UNIT_RIDER_OID) + .assertRole(ROLE_UNIT_SLEEPER_OID) + .end() + .links() + .single(); + } + + @Test + public void test203removeUnitRiderGuybrush() throws Exception { + //GIVEN + Task task = getTestTask(); + OperationResult result = task.getResult(); + + //WHEN + modifyUserDelete(USER_GUYBRUSH_OID, UserType.F_ORGANIZATIONAL_UNIT, task, result, createPolyString(UNIT_RIDER)); + + //THEN + assertUserAfter(USER_GUYBRUSH_OID) + .assertArchetypeRef(ARCHETYPE_EMPLOYEE_OID) + .assignments() + .assertAssignments(2) + .assertArchetype(ARCHETYPE_EMPLOYEE_OID) + .assertNoRole(ROLE_UNIT_RIDER_OID) + .assertRole(ROLE_UNIT_SLEEPER_OID) + .end() + .links() + .single(); + } + + // TODO: org and relation // TODO: combine autoassign with object template role assign diff --git a/model/model-intest/src/test/resources/mapping/resource-dummy-custom-function-crimson.xml b/model/model-intest/src/test/resources/mapping/resource-dummy-custom-function-crimson.xml index d9fc2446fd1..08aa3f849e0 100644 --- a/model/model-intest/src/test/resources/mapping/resource-dummy-custom-function-crimson.xml +++ b/model/model-intest/src/test/resources/mapping/resource-dummy-custom-function-crimson.xml @@ -112,7 +112,7 @@ location - locality + $locality diff --git a/model/model-intest/src/test/resources/rbac/autoassign/role-unit-rider.xml b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-rider.xml new file mode 100644 index 00000000000..a25c84fe6ee --- /dev/null +++ b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-rider.xml @@ -0,0 +1,48 @@ + + + Unit Rider + + + + account + + ri:title + + + Rider + + + + + + + true + + + UserType + + + + autoassign-rider + true + + organizationalUnit + + + + + + + + diff --git a/model/model-intest/src/test/resources/rbac/autoassign/role-unit-sleeper.xml b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-sleeper.xml index bb2f8d1b9f5..51784033504 100644 --- a/model/model-intest/src/test/resources/rbac/autoassign/role-unit-sleeper.xml +++ b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-sleeper.xml @@ -27,6 +27,9 @@ true + + UserType + autoassign-sleeper true diff --git a/model/model-intest/src/test/resources/rbac/autoassign/role-unit-walker.xml b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-walker.xml index fac2063254c..56d4bbb0878 100644 --- a/model/model-intest/src/test/resources/rbac/autoassign/role-unit-walker.xml +++ b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-walker.xml @@ -27,6 +27,9 @@ true + + UserType + autoassign-walker true diff --git a/model/model-intest/src/test/resources/rbac/autoassign/role-unit-worker.xml b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-worker.xml index c0befb16a17..9f079d52252 100644 --- a/model/model-intest/src/test/resources/rbac/autoassign/role-unit-worker.xml +++ b/model/model-intest/src/test/resources/rbac/autoassign/role-unit-worker.xml @@ -27,6 +27,9 @@ true + + UserType + autoassign-worker true diff --git a/pom.xml b/pom.xml index 940498f073c..a70b516f646 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 2.3.0 6.0.6 8.6.0 - 2.5.8 + 2.5.12 2.1.4 1.5.0.10 6.5.0 @@ -1793,10 +1793,6 @@ - - maven-javadoc-plugin - 3.1.1 - org.apache.maven.plugins maven-checkstyle-plugin @@ -2102,11 +2098,9 @@ jdk-11 - - 11 - + - 11 + [11,)