diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/multivalue/MultiValueChoosePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/multivalue/MultiValueChoosePanel.java index ebab7aa9d1f..78a9620a3b5 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/multivalue/MultiValueChoosePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/form/multivalue/MultiValueChoosePanel.java @@ -61,7 +61,7 @@ public class MultiValueChoosePanel extends SimplePanel
  • item) target.add(this); } + + /** + * A custom code in form of hook that can be run on event of + * choosing new object with this chooser component + * */ + protected void choosePerformedHook(AjaxRequestTarget target, T object){} + } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.html index 7cd664bcaab..4f962c5b6be 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.html @@ -49,6 +49,9 @@

    +

    diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java index 2e8ae1e4754..39831ef130e 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java @@ -20,6 +20,7 @@ import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.schema.SchemaRegistry; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.AuthorizationConstants; @@ -31,6 +32,7 @@ import com.evolveum.midpoint.web.component.AjaxSubmitButton; import com.evolveum.midpoint.web.component.assignment.*; import com.evolveum.midpoint.web.component.form.*; +import com.evolveum.midpoint.web.component.form.multivalue.MultiValueChoosePanel; import com.evolveum.midpoint.web.component.prism.*; import com.evolveum.midpoint.web.component.progress.ProgressReporter; import com.evolveum.midpoint.web.component.progress.ProgressReportingAwarePage; @@ -65,6 +67,7 @@ import org.apache.wicket.model.PropertyModel; import org.apache.wicket.util.string.StringValue; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -86,7 +89,8 @@ public class PageRole extends PageAdminRoles implements ProgressReportingAwarePa private static final String OPERATION_LOAD_ROLE = DOT_CLASS + "loadRole"; private static final String OPERATION_CREATE_ROLE_WRAPPER = DOT_CLASS + "createRoleWrapper"; private static final String OPERATION_SAVE_ROLE = DOT_CLASS + "saveRole"; - private static final String OPERATION_LOAD_OWNER = "getOwner"; + private static final String OPERATION_LOAD_OWNER = DOT_CLASS + "getOwner"; + private static final String OPERATION_LOAD_APPROVERS = DOT_CLASS + "loadApprovers"; private static final String ID_MAIN_FORM = "mainForm"; private static final String ID_BUTTON_BACK = "backButton"; @@ -108,6 +112,7 @@ public class PageRole extends PageAdminRoles implements ProgressReportingAwarePa private static final String ID_OWNER_WRAPPER = "ownerRefWrapper"; private static final String ID_OWNER_EDIT = "ownerRefEdit"; private static final String ID_OWNER_LABEL = "ownerRefLabel"; + private static final String ID_APPROVER_REF = "approverRef"; private static final String ID_INDUCEMENTS = "inducementsPanel"; private static final String ID_ASSIGNMENTS = "assignmentsPanel"; @@ -118,6 +123,7 @@ public class PageRole extends PageAdminRoles implements ProgressReportingAwarePa private static final String ID_INPUT_SIZE = "col-md-6"; private IModel> model; + private IModel> approversModel; private IModel extensionModel; private ObjectWrapper roleWrapper; @@ -149,6 +155,14 @@ protected ContainerWrapper load() { } }; + approversModel = new LoadableModel>(false) { + + @Override + protected List load() { + return loadApprovers(); + } + }; + initLayout(); } @@ -250,6 +264,34 @@ private ContainerWrapper loadRoleWrapper(){ return extensionContainer; } + private List loadApprovers(){ + List approverList = new ArrayList<>(); + List refList = new ArrayList<>(); + ObjectType helper; + OperationResult result = new OperationResult(OPERATION_LOAD_APPROVERS); + + RoleType actRole = model.getObject().asObjectable(); + + if(actRole != null){ + refList.addAll(actRole.getApproverRef()); + } + + if(!refList.isEmpty()){ + for(ObjectReferenceType ref: refList){ + String oid = ref.getOid(); + helper = WebModelUtils.loadObject(ObjectType.class, oid, null, result, this).asObjectable(); + approverList.add(helper); + } + } + result.computeStatus(); + + if(approverList.isEmpty()){ + approverList.add(new UserType()); + } + + return approverList; + } + private boolean isEditingRole(){ StringValue oid = getPageParameters().get(OnePageParameterEncoder.PARAMETER); return oid != null && StringUtils.isNotEmpty(oid.toString()); @@ -319,6 +361,70 @@ public void onClick(AjaxRequestTarget target) { }; ownerRefContainer.add(editOwnerRef); + MultiValueChoosePanel approverRef = new MultiValueChoosePanel(ID_APPROVER_REF, approversModel, + createStringResource("PageRoleEditor.label.approverRef"), ID_LABEL_SIZE, ID_INPUT_SIZE, false, ObjectType.class) { + + @Override + protected IModel createTextModel(final IModel model) { + return prepareApproverRefLabel(model); + } + + @Override + protected ObjectType createNewEmptyItem() { + return new UserType(); + } + + @Override + protected ObjectQuery createChooseQuery() { +// TODO + return super.createChooseQuery(); + } + + @Override + protected void replaceIfEmpty(Object object) { + boolean added = false; + + List approverList = approversModel.getObject(); + for (ObjectType approver : approverList) { + if (WebMiscUtil.getName(approver) == null || WebMiscUtil.getName(approver).isEmpty()) { + approverList.remove(approver); + approverList.add((ObjectType) object); + added = true; + break; + } + } + + if (!added) { + approverList.add((ObjectType)object); + } + } + + @Override + protected void initDialog(Class type) { + ModalWindow dialog = new ChooseTypeDialog(MODAL_ID_CHOOSE_PANEL, type){ + + @Override + protected void chooseOperationPerformed(AjaxRequestTarget target, ObjectType object){ + choosePerformed(target, object); + } + + @Override + protected WebMarkupContainer createExtraContentContainer(String extraContentId) { + return new UserOrgReferenceChoosePanel(extraContentId, Boolean.FALSE){ + + @Override + protected void onReferenceTypeChangePerformed(AjaxRequestTarget target, Boolean newValue) { + updateTableByTypePerformed(target, Boolean.FALSE.equals(newValue) ? UserType.class : OrgType.class); + } + }; + } + }; + add(dialog); + } + }; + approverRef.setOutputMarkupId(true); + form.add(approverRef); + initModalWindows(); initExtension(form); initAssignmentsAndInducements(form); @@ -461,6 +567,36 @@ public String getObject() { }; } + private IModel prepareApproverRefLabel(final IModel refModel){ + return new AbstractReadOnlyModel() { + + @Override + public String getObject() { + if(refModel == null || refModel.getObject() == null || refModel.getObject().getOid() == null){ + return getString("PageRoleEditor.label.approverRef.placeholder"); + } + + ObjectType object = refModel.getObject(); + + StringBuilder sb = new StringBuilder(); + + if(object instanceof UserType){ + sb.append(WebMiscUtil.getName(object)); + sb.append("- ("); + sb.append(UserType.class.getSimpleName()); + sb.append(")"); + } else if(object instanceof OrgType){ + sb.append(WebMiscUtil.getName(object)); + sb.append("- ("); + sb.append(OrgType.class.getSimpleName()); + sb.append(")"); + } + + return sb.toString(); + } + }; + } + private void initButtons(Form form){ AjaxSubmitButton save = new AjaxSubmitButton(ID_BUTTON_SAVE, createStringResource("PageBase.button.save")) { @@ -541,11 +677,73 @@ private void ownerChoosePerformed(AjaxRequestTarget target, ObjectType newOwner) target.add(getFeedbackPanel(), getOwnerRefContainer()); } + private void handleApproverReferences(PrismObject rolePrism){ + RoleType role = rolePrism.asObjectable(); + + if(isEditingRole()){ + if(approversModel != null && approversModel.getObject() != null){ + for(ObjectType approver: approversModel.getObject()){ + if(approver != null && WebMiscUtil.getName(approver) != null && !WebMiscUtil.getName(approver).isEmpty()){ + if(!isApprover(approver, role.getApproverRef())){ + ObjectReferenceType ref = new ObjectReferenceType(); + ref.setOid(approver.getOid()); + ref.setType(approver instanceof UserType ? UserType.COMPLEX_TYPE : OrgType.COMPLEX_TYPE); + role.getApproverRef().add(ref); + } + } + } + } + } else { + if(approversModel != null && approversModel.getObject() != null){ + for(ObjectType approver: approversModel.getObject()){ + if(approver != null && WebMiscUtil.getName(approver) != null && !WebMiscUtil.getName(approver).isEmpty()){ + ObjectReferenceType ref = new ObjectReferenceType(); + ref.setOid(approver.getOid()); + ref.setType(approver instanceof UserType ? UserType.COMPLEX_TYPE : OrgType.COMPLEX_TYPE); + role.getApproverRef().add(ref); + } + } + } + } + + //Delete approver references deleted during role edition + if(isEditingRole()){ + if(approversModel != null && approversModel.getObject() != null){ + for(ObjectReferenceType ref: role.getApproverRef()){ + if(!isRefInApproverModel(ref)){ + role.getApproverRef().remove(ref); + } + } + } + } + } + + private boolean isRefInApproverModel(ObjectReferenceType reference){ + for(ObjectType approver: approversModel.getObject()){ + if(reference.getOid().equals(approver.getOid())){ + return true; + } + } + return false; + } + + private boolean isApprover(ObjectType approver, List approverList){ + for(ObjectReferenceType ref: approverList){ + if(ref.getOid().equals(approver.getOid())){ + return true; + } + } + + return false; + } + private void savePerformed(AjaxRequestTarget target){ OperationResult result = new OperationResult(OPERATION_SAVE_ROLE); try { WebMiscUtil.revive(model, getPrismContext()); + WebMiscUtil.revive(approversModel, getPrismContext()); PrismObject newRole = model.getObject(); + handleApproverReferences(newRole); ObjectDelta delta = null; if (!isEditingRole()) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.properties b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.properties index ee5334fe7f1..96110091e69 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.properties +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.properties @@ -31,8 +31,11 @@ PageRoleEditor.label.requestable=Requestable PageRoleEditor.label.identifier=Identifier PageRoleEditor.label.ownerRef=Owner PageRoleEditor.label.ownerRef.placeholder=Set Owner +PageRoleEditor.label.approverRef=Approver +PageRoleEditor.label.approverRef.placeholder=Set Approver PageRoleEditor.extension=Extension PageRoleEditor.message.cantCreateExtensionDelta=Can't create delta for role extension PageRoleEditor.message.cantAddOwner=Can't setup the selected owner. PageRoleEditor.message.addOwnerOk=Owner with name: '{0}' was added successfully. +PageRoleEditor.message.addApproverOk=Approver with name: '{0}' was added successfully. diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java index bea532d72b1..9553fdd03ed 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/users/PageOrgUnit.java @@ -580,6 +580,7 @@ private PrismObject buildUnitFromModel(List parent } } } + //We are editing OrgUnit }else if (parentOrgUnitsModel != null && parentOrgUnitsModel.getObject() != null) { for (OrgType parent : parentOrgUnitsModel.getObject()) { diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java index b4712419bae..bffc96fe0d1 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java @@ -28,6 +28,7 @@ import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.prism.path.NameItemPathSegment; +import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableType; import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; @@ -141,7 +142,8 @@ public static boolean hasToLoadPath(QName container, Collection> options) { List> retrieveOptions = filterRetrieveOptions(options); diff --git a/infra/test-util/src/main/resources/test-data/opendj-4000.template/config/config.ldif b/infra/test-util/src/main/resources/test-data/opendj-4000.template/config/config.ldif index 3beff0caa8a..2e7fa172105 100644 --- a/infra/test-util/src/main/resources/test-data/opendj-4000.template/config/config.ldif +++ b/infra/test-util/src/main/resources/test-data/opendj-4000.template/config/config.ldif @@ -258,19 +258,19 @@ ds-cfg-enabled: TRUE ds-cfg-index-entry-limit: 4000 ds-cfg-java-class: org.opends.server.backends.jeb.BackendImpl ds-cfg-writability-mode: enabled -ds-cfg-db-cache-percent: 50 +ds-cfg-db-cache-percent: 1 ds-cfg-db-evictor-lru-only: false ds-cfg-entries-compressed: false -ds-cfg-db-cache-size: 0 megabytes +ds-cfg-db-cache-size: 5 megabytes ds-cfg-db-directory-permissions: 700 ds-cfg-db-cleaner-min-utilization: 50 ds-cfg-db-logging-file-handler-on: true ds-cfg-db-log-file-max: 100 megabytes ds-cfg-db-evictor-nodes-per-scan: 10 -ds-cfg-db-evictor-max-threads: 10 +ds-cfg-db-evictor-max-threads: 2 ds-cfg-db-log-filecache-size: 100 ds-cfg-db-evictor-core-threads: 1 -ds-cfg-db-run-cleaner: true +ds-cfg-db-run-cleaner: false ds-cfg-db-txn-no-sync: false ds-cfg-db-txn-write-no-sync: true modifyTimestamp: 20150309121529Z diff --git a/infra/test-util/src/main/resources/test-data/opendj.template/config/config.ldif b/infra/test-util/src/main/resources/test-data/opendj.template/config/config.ldif index 7800e1438b6..3f565df3cf2 100644 --- a/infra/test-util/src/main/resources/test-data/opendj.template/config/config.ldif +++ b/infra/test-util/src/main/resources/test-data/opendj.template/config/config.ldif @@ -258,19 +258,19 @@ ds-cfg-enabled: TRUE ds-cfg-index-entry-limit: 4000 ds-cfg-java-class: org.opends.server.backends.jeb.BackendImpl ds-cfg-writability-mode: enabled -ds-cfg-db-cache-percent: 50 +ds-cfg-db-cache-percent: 1 ds-cfg-db-evictor-lru-only: false ds-cfg-entries-compressed: false -ds-cfg-db-cache-size: 0 megabytes +ds-cfg-db-cache-size: 5 megabytes ds-cfg-db-directory-permissions: 700 ds-cfg-db-cleaner-min-utilization: 50 ds-cfg-db-logging-file-handler-on: true ds-cfg-db-log-file-max: 100 megabytes ds-cfg-db-evictor-nodes-per-scan: 10 -ds-cfg-db-evictor-max-threads: 10 +ds-cfg-db-evictor-max-threads: 2 ds-cfg-db-log-filecache-size: 100 ds-cfg-db-evictor-core-threads: 1 -ds-cfg-db-run-cleaner: true +ds-cfg-db-run-cleaner: false ds-cfg-db-txn-no-sync: false ds-cfg-db-txn-write-no-sync: true modifyTimestamp: 20150306181507Z diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java index b27f1c33ddd..b02abddcd29 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java @@ -122,8 +122,6 @@ ModelContext previewChanges( /** * Returns an object that defines which roles can be assigned by the currently logged-in user. - * Returns null if there is no information about what a user can or cannot assign. - * Returns object with empty type list if the user is not authorized to assign anything. * * @param focus Object of the operation. The object (usually user) to whom the roles should be assigned. */ diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/RoleSelectionSpecification.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/RoleSelectionSpecification.java index a9bf28b2702..0823fbfffd8 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/RoleSelectionSpecification.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/RoleSelectionSpecification.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.List; +import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.util.DisplayableValue; /** @@ -26,19 +27,76 @@ */ public class RoleSelectionSpecification { - private List> roleTypes = new ArrayList>(); + private List> roleTypes = null; + private ObjectFilter filter = null; + /** + * Returns null if there is no information about role types that can or cannot be assigned. + * Returns empty list list if the user is not authorized to assign anything. + */ public List> getRoleTypes() { return roleTypes; } + public void setNoRoleTypes() { + roleTypes = new ArrayList>(); + } + public void addRoleType(DisplayableValue roleType) { + if (roleTypes == null) { + roleTypes = new ArrayList>(); + } roleTypes.add(roleType); } + + /** + * Returns "additional filter" that should be used to search for assignible roles. + * This filter should be AND-ed with any application level filter. + * It can return null. The null filter means "ALL" (AllFilter). + * If this returns NoneFilter then no roles can be assigned to the user. + */ + public ObjectFilter getFilter() { + return filter; + } + + public void setFilter(ObjectFilter filter) { + this.filter = filter; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((filter == null) ? 0 : filter.hashCode()); + result = prime * result + ((roleTypes == null) ? 0 : roleTypes.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RoleSelectionSpecification other = (RoleSelectionSpecification) obj; + if (filter == null) { + if (other.filter != null) + return false; + } else if (!filter.equals(other.filter)) + return false; + if (roleTypes == null) { + if (other.roleTypes != null) + return false; + } else if (!roleTypes.equals(other.roleTypes)) + return false; + return true; + } @Override public String toString() { - return "RoleSelectionSpecification(" + roleTypes + ")"; + return "RoleSelectionSpecification(" + roleTypes + ": "+filter+")"; } 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 709c208a9e5..a440d3d68fc 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 @@ -1113,22 +1113,26 @@ public RoleSelectionSpecification getAssignableRoleSpecifi AuthorizationDecisionType decision = securityConstraints.findItemDecision(new ItemPath(FocusType.F_ASSIGNMENT), ModelAuthorizationAction.MODIFY.getUrl(), AuthorizationPhaseType.REQUEST); if (decision == AuthorizationDecisionType.ALLOW) { - spec = getAllRoleTypesSpec(result); + getAllRoleTypesSpec(spec, result); result.recordSuccess(); return spec; } if (decision == AuthorizationDecisionType.DENY) { result.recordSuccess(); + spec.setNoRoleTypes(); + spec.setFilter(NoneFilter.createNone()); return spec; } decision = securityConstraints.getActionDecision(ModelAuthorizationAction.MODIFY.getUrl(), AuthorizationPhaseType.REQUEST); if (decision == AuthorizationDecisionType.ALLOW) { - spec = getAllRoleTypesSpec(result); + getAllRoleTypesSpec(spec, result); result.recordSuccess(); return spec; } if (decision == AuthorizationDecisionType.DENY) { result.recordSuccess(); + spec.setNoRoleTypes(); + spec.setFilter(NoneFilter.createNone()); return spec; } @@ -1136,18 +1140,24 @@ public RoleSelectionSpecification getAssignableRoleSpecifi ObjectFilter filter = securityEnforcer.preProcessObjectFilter(ModelAuthorizationAction.ASSIGN.getUrl(), AuthorizationPhaseType.REQUEST, RoleType.class, focus, AllFilter.createAll()); LOGGER.trace("assignableRoleSpec filter: {}", filter); + spec.setFilter(filter); if (filter instanceof NoneFilter) { result.recordSuccess(); + spec.setNoRoleTypes(); return spec; } else if (filter == null || filter instanceof AllFilter) { - spec = getAllRoleTypesSpec(result); + getAllRoleTypesSpec(spec, result); result.recordSuccess(); return spec; } else if (filter instanceof OrFilter) { for (ObjectFilter subfilter: ((OrFilter)filter).getConditions()) { DisplayableValue roleTypeDval = getRoleSelectionSpec(subfilter); if (roleTypeDval == null) { - spec = getAllRoleTypesSpec(result); + // This branch of the OR clause does not have any constraint for roleType + // therefore all role types are possible (regardless of other branches, this is OR) + spec = new RoleSelectionSpecification(); + spec.setFilter(filter); + getAllRoleTypesSpec(spec, result); result.recordSuccess(); return spec; } else { @@ -1157,7 +1167,7 @@ public RoleSelectionSpecification getAssignableRoleSpecifi } else { DisplayableValue roleTypeDval = getRoleSelectionSpec(filter); if (roleTypeDval == null) { - spec = getAllRoleTypesSpec(result); + getAllRoleTypesSpec(spec, result); result.recordSuccess(); return spec; } else { @@ -1172,11 +1182,11 @@ public RoleSelectionSpecification getAssignableRoleSpecifi } } - private RoleSelectionSpecification getAllRoleTypesSpec(OperationResult result) + private RoleSelectionSpecification getAllRoleTypesSpec(RoleSelectionSpecification spec, OperationResult result) throws ObjectNotFoundException, SchemaException, ConfigurationException { ObjectTemplateType objectTemplateType = determineObjectTemplate(RoleType.class, AuthorizationPhaseType.REQUEST, result); if (objectTemplateType == null) { - return null; + return spec; } for(ObjectTemplateItemDefinitionType itemDef: objectTemplateType.getItem()) { ItemPathType ref = itemDef.getRef(); @@ -1191,13 +1201,12 @@ private RoleSelectionSpecification getAllRoleTypesSpec(OperationResult result) if (QNameUtil.match(RoleType.F_ROLE_TYPE, itemName)) { ObjectReferenceType valueEnumerationRef = itemDef.getValueEnumerationRef(); if (valueEnumerationRef == null || valueEnumerationRef.getOid() == null) { - return null; + return spec; } Collection> options = SelectorOptions.createCollection(LookupTableType.F_TABLE, GetOperationOptions.createRetrieve(RetrieveOption.INCLUDE)); PrismObject lookup = cacheRepositoryService.getObject(LookupTableType.class, valueEnumerationRef.getOid(), options, result); - RoleSelectionSpecification spec = new RoleSelectionSpecification(); for (LookupTableTableType row: lookup.asObjectable().getTable()) { PolyStringType polyLabel = row.getLabel(); String key = row.getKey(); @@ -1211,7 +1220,7 @@ private RoleSelectionSpecification getAllRoleTypesSpec(OperationResult result) return spec; } } - return null; + return spec; } private DisplayableValue getRoleSelectionSpec(ObjectFilter filter) throws SchemaException { diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java index eb12bc5713b..867ac1f03e0 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestSecurity.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.model.intest; import static org.testng.AssertJUnit.assertNull; + import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.model.api.ModelAuthorizationAction; @@ -29,7 +30,11 @@ import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.AndFilter; +import com.evolveum.midpoint.prism.query.NoneFilter; +import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.TypeFilter; import com.evolveum.midpoint.prism.util.PrismAsserts; import com.evolveum.midpoint.prism.util.PrismTestUtil; import com.evolveum.midpoint.schema.GetOperationOptions; @@ -540,7 +545,11 @@ public void test200AutzJackNoRole() throws Exception { assertModifyDeny(); assertDeleteDeny(); - assertRoleTypes(userJack); + RoleSelectionSpecification roleSpec = getAssignableRoleSpecification(userJack); + assertNotNull("Null role spec "+roleSpec, roleSpec); + assertRoleTypes(roleSpec); + assertFilter(roleSpec.getFilter(), NoneFilter.class); + } @Test @@ -559,9 +568,11 @@ public void test201AutzJackSuperuserRole() throws Exception { assertDeleteAllow(); RoleSelectionSpecification roleSpec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); - assertNull("Non-null role spec "+roleSpec, roleSpec); + assertNotNull("Null role spec "+roleSpec, roleSpec); + assertNull("Non-null role types in spec "+roleSpec, roleSpec.getRoleTypes()); + assertFilter(roleSpec.getFilter(), null); } - + @Test public void test202AutzJackReadonlyRole() throws Exception { final String TEST_NAME = "test202AutzJackReadonlyRole"; @@ -1269,7 +1280,9 @@ public void run(Task task, OperationResult result) throws Exception { user = getUser(USER_JACK_OID); assertAssignments(user, 2); - assertRoleTypes(getUser(USER_JACK_OID), "application"); + RoleSelectionSpecification spec = getAssignableRoleSpecification(getUser(USER_JACK_OID)); + assertRoleTypes(spec, "application"); + assertFilter(spec.getFilter(), TypeFilter.class); } @Test diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestEditSchema.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestEditSchema.java index 5bb07159201..473f1b78661 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestEditSchema.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/gensync/TestEditSchema.java @@ -349,13 +349,21 @@ public void test156LookupLanguagesAddRowExistingKey() throws Exception { // WHEN TestUtil.displayWhen(TEST_NAME); - modelService.executeChanges(MiscSchemaUtil.createCollection(delta), null, task, result); + boolean exception = false; + try { + modelService.executeChanges(MiscSchemaUtil.createCollection(delta), null, task, result); + } catch (ObjectAlreadyExistsException ex) { + exception = true; + } + AssertJUnit.assertTrue(exception); // THEN TestUtil.displayThen(TEST_NAME); result.computeStatus(); - TestUtil.assertSuccess(result); - + TestUtil.assertFailure(result); + + task = taskManager.createTaskInstance(TestModelServiceContract.class.getName() + "." + TEST_NAME); + result = task.getResult(); PrismObject lookup = getLookupTableAll(LOOKUP_LANGUAGES_OID, task, result); result.computeStatus(); @@ -376,12 +384,18 @@ public void test156LookupLanguagesAddRowExistingKey() throws Exception { assertLookupRow(tableContainer, "gi_GI", "gi", "Gibberish"); assertLookupRow(tableContainer, "gi_GO", null, "Gobbledygook"); - assertLookupRow(tableContainer, "gi_HU", "gi", "Humbug"); + assertLookupRow(tableContainer, "gi_HU", "gi", null); assertSteadyResources(); } - @Test + /** + * disabled because we can't delete container based on it's properties. It's against prism containers + * identification concepts - prism container is identified by object OID and container ID attribute. + * + * @throws Exception + */ + @Test(enabled = false) public void test162LookupLanguagesDeleteRowFullNoId() throws Exception { final String TEST_NAME="test162LookupLanguagesDeleteRowFullNoId"; TestUtil.displayTestTile(this, TEST_NAME); @@ -466,13 +480,14 @@ public void test164LookupLanguagesDeleteRowFullId() throws Exception { PrismContainer tableContainer = lookup.findContainer(LookupTableType.F_TABLE); assertNotNull("Table container missing", tableContainer); - assertEquals("Unexpected table container size", 5, tableContainer.size()); + assertEquals("Unexpected table container size", 6, tableContainer.size()); assertLookupRow(tableContainer, "en_PR", "en", "English (pirate)"); assertLookupRow(tableContainer, "tr_TR", "tr", "Turkish"); assertLookupRow(tableContainer, "gi_GI", "gi", "Gibberish"); assertLookupRow(tableContainer, "gi_GO", null, "Gobbledygook"); - assertLookupRow(tableContainer, "gi_HU", "gi", "Humbug"); + assertLookupRow(tableContainer, "gi_HU", "gi", null); + assertLookupRow(tableContainer, "sk_SK", "sk", "Slovak"); assertSteadyResources(); } @@ -511,17 +526,24 @@ public void test166LookupLanguagesDeleteRowIdOnly() throws Exception { PrismContainer tableContainer = lookup.findContainer(LookupTableType.F_TABLE); assertNotNull("Table container missing", tableContainer); - assertEquals("Unexpected table container size", 4, tableContainer.size()); + assertEquals("Unexpected table container size", 5, tableContainer.size()); assertLookupRow(tableContainer, "en_PR", "en", "English (pirate)"); assertLookupRow(tableContainer, "gi_GI", "gi", "Gibberish"); assertLookupRow(tableContainer, "gi_GO", null, "Gobbledygook"); - assertLookupRow(tableContainer, "gi_HU", "gi", "Humbug"); + assertLookupRow(tableContainer, "gi_HU", "gi", null); + assertLookupRow(tableContainer, "tr_TR", "tr", "Turkish"); assertSteadyResources(); } - - @Test + + /** + * disabled because we can't delete container based on it's properties. It's against prism containers + * identification concepts - prism container is identified by object OID and container ID attribute. + * + * @throws Exception + */ + @Test(enabled = false) public void test168LookupLanguagesDeleteRowByKey() throws Exception { final String TEST_NAME="test168LookupLanguagesDeleteRowByKey"; TestUtil.displayTestTile(this, TEST_NAME); diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java index 6163d4f42d2..43e0bd3f042 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/SqlRepositoryServiceImpl.java @@ -19,16 +19,17 @@ import com.evolveum.midpoint.common.InternalsConfig; import com.evolveum.midpoint.common.crypto.CryptoUtil; import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.delta.PropertyDelta; -import com.evolveum.midpoint.prism.delta.ReferenceDelta; +import com.evolveum.midpoint.prism.delta.*; 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.query.NoneFilter; +import com.evolveum.midpoint.prism.query.ObjectFilter; +import com.evolveum.midpoint.prism.query.ObjectPaging; +import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.repo.api.RepoAddOptions; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.repo.sql.data.common.*; +import com.evolveum.midpoint.repo.sql.data.common.RLookupTable; +import com.evolveum.midpoint.repo.sql.data.common.RObject; import com.evolveum.midpoint.repo.sql.data.common.any.RAnyValue; import com.evolveum.midpoint.repo.sql.data.common.any.RValueType; import com.evolveum.midpoint.repo.sql.data.common.other.RLookupTableRow; @@ -50,10 +51,10 @@ 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; - import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.hibernate.*; +import org.hibernate.criterion.Order; import org.hibernate.criterion.Restrictions; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.internal.SessionFactoryImpl; @@ -62,7 +63,6 @@ import javax.annotation.PostConstruct; import javax.xml.namespace.QName; - import java.lang.reflect.Method; import java.sql.Connection; import java.sql.Driver; @@ -495,9 +495,6 @@ private String addObjectAttempt(PrismObject object, Re object.getCompileTimeClass().getSimpleName(), oid}); object.setOid(oid); - } catch (ObjectAlreadyExistsException ex) { - rollbackTransaction(session, ex, result, true); - throw ex; } catch (ConstraintViolationException ex) { handleConstraintViolationException(session, ex, result); rollbackTransaction(session, ex, result, true); @@ -516,7 +513,7 @@ private String addObjectAttempt(PrismObject object, Re } throw new ObjectAlreadyExistsException("Conflicting object already exists" + (constraintName == null ? "" : " (violated constraint '" + constraintName + "')"), ex); - } catch (SchemaException ex) { + } catch (ObjectAlreadyExistsException | SchemaException ex) { rollbackTransaction(session, ex, result, true); throw ex; } catch (DtoTranslationException | RuntimeException ex) { @@ -556,7 +553,8 @@ private String overwriteAddObjectAttempt(PrismObject o updateFullObject(rObject, object); RObject merged = (RObject) session.merge(rObject); - //add and maybe modify + addLookupTableRows(session, rObject, modifications != null); + //todo handle lookuptable rows merge [lazyman] if (getClosureManager().isEnabled()) { OrgClosureManager.Operation operation; @@ -618,6 +616,7 @@ private String nonOverwriteAddObjectAttempt(PrismObject modifications = createAddParentRefDelta(object); @@ -696,6 +695,9 @@ private void deleteObjectAttempt(Class type, String oi getClosureManager().updateOrgClosure(null, null, session, oid, type, OrgClosureManager.Operation.DELETE, closureContext); session.delete(object); + if (LookupTableType.class.equals(type)) { + deleteLookupTableRows(session, oid); + } session.getTransaction().commit(); } catch (ObjectNotFoundException ex) { @@ -708,6 +710,81 @@ private void deleteObjectAttempt(Class type, String oi } } + /** + * This method removes all lookup table rows for object defined by oid + */ + private void deleteLookupTableRows(Session session, String oid) { + Query query = session.getNamedQuery("delete.lookupTableData"); + query.setParameter("oid", oid); + + query.executeUpdate(); + } + + private void addLookupTableRows(Session session, RObject object, boolean merge) { + if (!(object instanceof RLookupTable)) { + return; + } + + RLookupTable table = (RLookupTable) object; + if (table.getRows() == null) { + return; + } + + if (!merge) { + for (RLookupTableRow row : table.getRows()) { + session.save(row); + } + } else { + //todo implement lookup table rows merge !!!!!!!!! + } + } + + private void updateLookupTableData(Session session, RObject object, Collection modifications) { + if (modifications.isEmpty()) { + return; + } + + Query query = session.getNamedQuery("get.lookupTableLastId"); + query.setString("oid", object.getOid()); + Short lastId = (Short) query.uniqueResult(); + if (lastId == null) { + lastId = 0; + } + + for (ItemDelta delta : modifications) { + if (delta instanceof ContainerDelta && delta.getPath().size() == 1) { + // one "table" container modification + ContainerDelta containerDelta = (ContainerDelta) delta; + if (containerDelta.getValuesToDelete() != null) { + for (PrismContainerValue value : (Collection) containerDelta.getValuesToDelete()) { + query = session.getNamedQuery("delete.lookupTableDataRow"); + query.setString("oid", object.getOid()); + query.setShort("id", RUtil.toShort(value.getId())); + query.executeUpdate(); + } + } + if (containerDelta.getValuesToAdd() != null) { + for (PrismContainerValue value : (Collection) containerDelta.getValuesToAdd()) { + lastId++; + + LookupTableTableType table = new LookupTableTableType(); + table.setupContainerValue(value); + + RLookupTableRow row = RLookupTableRow.toRepo(object.getOid(), table); + row.setId(lastId); + session.save(row); + } + } + if (containerDelta.getValuesToReplace() != null) { + //todo implement lookup table row merge container + } + } else { + // "table" container property modification (container should already exist) + //todo implement lookup table row merge properties + } + } + } + @Override public int countObjects(Class type, ObjectQuery query, OperationResult result) { Validate.notNull(type, "Object type must not be null."); @@ -927,18 +1004,58 @@ private PrismObject updateLoadedObject(GetObjectResult return prismObject; } + private GetOperationOptions findLookupTableGetOption(Collection> options) { + ItemPath path = new ItemPath(LookupTableType.F_TABLE); + + Collection> filtered = SelectorOptions.filterRetrieveOptions(options); + for (SelectorOptions option : filtered) { + ObjectSelector selector = option.getSelector(); + ItemPath selected = selector.getPath(); + + if (path.equals(selected)) { + return option.getOptions(); + } + } + + return null; + } + private void updateLoadedLookupTable(PrismObject object, - Collection> options, - Session session) { + Collection> options, + Session session) { if (!SelectorOptions.hasToLoadPath(LookupTableType.F_TABLE, options)) { return; } LOGGER.debug("Loading lookup table data."); - Query query = session.getNamedQuery("get.lookupTableData"); - query.setString("oid", object.getOid()); - List rows = query.list(); + GetOperationOptions getOption = findLookupTableGetOption(options); + RelationalValueSearchQuery queryDef = getOption == null ? null : getOption.getRelationalValueSearchQuery(); + Criteria criteria = setupLookupTableRowsQuery(session, queryDef, object.getOid()); + if (queryDef != null && queryDef.getPaging() != null) { + ObjectPaging paging = queryDef.getPaging(); + + if (paging.getOffset() != null) { + criteria.setFirstResult(paging.getOffset()); + } + if (paging.getMaxSize() != null) { + criteria.setMaxResults(paging.getMaxSize()); + } + + if (paging.getDirection() != null && paging.getOrderBy() != null) { + String orderBy = paging.getOrderBy().getLocalPart(); + switch (paging.getDirection()) { + case ASCENDING: + criteria.addOrder(Order.asc(orderBy)); + break; + case DESCENDING: + criteria.addOrder(Order.desc(orderBy)); + break; + } + } + } + + List rows = criteria.list(); if (rows == null || rows.isEmpty()) { return; } @@ -951,6 +1068,32 @@ private void updateLoadedLookupTable(PrismObject objec } } + private Criteria setupLookupTableRowsQuery(Session session, RelationalValueSearchQuery queryDef, String oid) { + Criteria criteria = session.createCriteria(RLookupTableRow.class); + criteria.add(Restrictions.eq("ownerOid", oid)); + + if (queryDef != null + && queryDef.getColumn() != null + && queryDef.getSearchType() != null + && StringUtils.isNotEmpty(queryDef.getSearchValue())) { + + String param = queryDef.getColumn().getLocalPart(); + String value = queryDef.getSearchValue(); + switch (queryDef.getSearchType()) { + case EXACT: + criteria.add(Restrictions.eq(param, value)); + break; + case STARTS_WITH: + criteria.add(Restrictions.like(param, value + "%")); + break; + case SUBSTRING: + criteria.add(Restrictions.like(param, "%" + value + "%")); + } + } + + return criteria; + } + private void applyShadowAttributeDefinitions(Class anyValueType, PrismObject object, Session session) throws SchemaException { @@ -1075,7 +1218,9 @@ private void modifyObjectAttempt(Class type, String oi closureContext = getClosureManager().onBeginTransactionModify(session, type, oid, modifications); - // get user + Collection lookupTableModifications = filterLookupTableModifications(type, modifications); + + // get object PrismObject prismObject = getObject(session, type, oid, null, true); // apply diff if (LOGGER.isTraceEnabled()) { @@ -1089,7 +1234,7 @@ private void modifyObjectAttempt(Class type, String oi if (LOGGER.isTraceEnabled()) { LOGGER.trace("OBJECT after:\n{}", prismObject.debugDump()); } - // merge and update user + // merge and update object LOGGER.trace("Translating JAXB to data type."); RObject rObject = createDataObjectFromJAXB(prismObject, PrismIdentifierGenerator.Operation.MODIFY); rObject.setVersion(rObject.getVersion() + 1); @@ -1097,6 +1242,8 @@ private void modifyObjectAttempt(Class type, String oi updateFullObject(rObject, prismObject); session.merge(rObject); + updateLookupTableData(session, rObject, lookupTableModifications); + if (getClosureManager().isEnabled()) { getClosureManager().updateOrgClosure(originalObject, modifications, session, oid, type, OrgClosureManager.Operation.MODIFY, closureContext); } @@ -1129,6 +1276,26 @@ private void modifyObjectAttempt(Class type, String oi } } + private Collection filterLookupTableModifications(Class type, + Collection modifications) { + Collection tableDelta = new ArrayList<>(); + if (!LookupTableType.class.equals(type)) { + return tableDelta; + } + + ItemPath tablePath = new ItemPath(LookupTableType.F_TABLE); + for (ItemDelta delta : modifications) { + ItemPath path = delta.getPath(); + if (path.isSubPathOrEquivalent(tablePath)) { + tableDelta.add(delta); + } + } + + modifications.removeAll(tableDelta); + + return tableDelta; + } + private void cleanupClosureAndSessionAndResult(final OrgClosureManager.Context closureContext, final Session session, final OperationResult result) { if (closureContext != null) { getClosureManager().cleanUpAfterOperation(closureContext, session); diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RLookupTable.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RLookupTable.java index f8787580290..3e78356e7af 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RLookupTable.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RLookupTable.java @@ -3,6 +3,7 @@ import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.repo.sql.data.common.embedded.RPolyString; import com.evolveum.midpoint.repo.sql.data.common.other.RLookupTableRow; +import com.evolveum.midpoint.repo.sql.type.XMLGregorianCalendarType; import com.evolveum.midpoint.repo.sql.util.DtoTranslationException; import com.evolveum.midpoint.repo.sql.util.IdGeneratorResult; import com.evolveum.midpoint.repo.sql.util.RUtil; @@ -10,14 +11,11 @@ import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableTableType; import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableType; -import org.hibernate.annotations.Cascade; import org.hibernate.annotations.ForeignKey; import javax.persistence.*; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import javax.xml.datatype.XMLGregorianCalendar; +import java.util.*; /** * @author Viliam Repan (lazyman) @@ -30,12 +28,14 @@ public class RLookupTable extends RObject { private RPolyString name; private Set rows; - @OneToMany(mappedBy = "owner", orphanRemoval = true) - @Cascade({org.hibernate.annotations.CascadeType.ALL}) + @Override + @Embedded + public RPolyString getName() { + return name; + } + + @Transient public Set getRows() { - if (rows == null) { - rows = new HashSet<>(); - } return rows; } @@ -43,12 +43,6 @@ public void setRows(Set rows) { this.rows = rows; } - @Override - @Embedded - public RPolyString getName() { - return name; - } - @Override public void setName(RPolyString name) { this.name = name; @@ -61,13 +55,23 @@ public static void copyFromJAXB(LookupTableType jaxb, RLookupTable repo, PrismCo repo.setName(RPolyString.copyFromJAXB(jaxb.getName())); List rows = jaxb.getTable(); + if (!rows.isEmpty()) { + repo.setRows(new HashSet()); + } + for (LookupTableTableType row : rows) { RLookupTableRow rRow = new RLookupTableRow(); rRow.setOwner(repo); + rRow.setTransient(generatorResult.isTransient(row.asPrismContainerValue())); rRow.setId(RUtil.toShort(row.getId())); rRow.setKey(row.getKey()); rRow.setLabel(RPolyString.copyFromJAXB(row.getLabel())); rRow.setLastChangeTimestamp(row.getLastChangeTimestamp()); + if (rRow.getLastChangeTimestamp() == null) { + XMLGregorianCalendar cal = XMLGregorianCalendarType.asXMLGregorianCalendar(new Date()); + rRow.setLastChangeTimestamp(cal); + row.setLastChangeTimestamp(cal); + } rRow.setValue(row.getValue()); repo.getRows().add(rRow); diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RObject.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RObject.java index d9b9e22b69d..81b16334fd8 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RObject.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RObject.java @@ -70,7 +70,9 @@ @NamedQuery(name = "getDefinition.ROExtReference", query = "select c.name, c.type, c.valueType from ROExtReference as c where c.ownerOid = :oid and c.ownerType = :ownerType"), @NamedQuery(name = "isAnySubordinateAttempt.oneLowerOid", query = "select count(*) from ROrgClosure o where o.ancestorOid=:aOid and o.descendantOid=:dOid"), @NamedQuery(name = "isAnySubordinateAttempt.moreLowerOids", query = "select count(*) from ROrgClosure o where o.ancestorOid=:aOid and o.descendantOid in (:dOids)"), - @NamedQuery(name = "get.lookupTableData", query = "select r from RLookupTableRow r where r.ownerOid = :oid"), + @NamedQuery(name = "get.lookupTableLastId", query = "select max(r.id) from RLookupTableRow r where r.ownerOid = :oid"), + @NamedQuery(name = "delete.lookupTableData", query = "delete RLookupTableRow r where r.ownerOid = :oid"), + @NamedQuery(name = "delete.lookupTableDataRow", query = "delete RLookupTableRow r where r.ownerOid = :oid and r.id = :id"), }) @Entity @Table(name = "m_object", indexes = { diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/other/RLookupTableRow.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/other/RLookupTableRow.java index 26ce954eced..31499151725 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/other/RLookupTableRow.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/other/RLookupTableRow.java @@ -6,6 +6,7 @@ import com.evolveum.midpoint.repo.sql.data.common.container.Container; import com.evolveum.midpoint.repo.sql.data.common.embedded.RPolyString; import com.evolveum.midpoint.repo.sql.data.common.id.RContainerId; +import com.evolveum.midpoint.repo.sql.type.XMLGregorianCalendarType; import com.evolveum.midpoint.repo.sql.util.RUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableTableType; import org.hibernate.annotations.ForeignKey; @@ -14,6 +15,7 @@ import javax.persistence.*; import javax.xml.datatype.XMLGregorianCalendar; import java.sql.Timestamp; +import java.util.Date; /** * @author Viliam Repan (lazyman) @@ -66,7 +68,7 @@ public Short getId() { } @Id - @Column(name = "row_key") + @Column(name = "row_key", unique = true) public String getKey() { return key; } @@ -161,4 +163,21 @@ public LookupTableTableType toJAXB() { return row; } + + public static RLookupTableRow toRepo(String ownerOid, LookupTableTableType table) { + RLookupTableRow row = new RLookupTableRow(); + row.setOwnerOid(ownerOid); + row.setId(RUtil.toShort(table.getId())); + row.setKey(table.getKey()); + row.setLabel(RPolyString.copyFromJAXB(table.getLabel())); + row.setLastChangeTimestamp(table.getLastChangeTimestamp()); + if (row.getLastChangeTimestamp() == null) { + XMLGregorianCalendar cal = XMLGregorianCalendarType.asXMLGregorianCalendar(new Date()); + row.setLastChangeTimestamp(cal); + table.setLastChangeTimestamp(cal); + } + row.setValue(table.getValue()); + + return row; + } } diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index a2374fc743d..8759822dce9 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2015 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,6 +44,7 @@ import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.query.AndFilter; import com.evolveum.midpoint.prism.query.EqualFilter; +import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.query.RefFilter; import com.evolveum.midpoint.prism.util.PrismAsserts; @@ -888,5 +889,16 @@ protected void assertPassword(ShadowType shadow, String expectedPassword) throws protector.decrypt(passwordValue); assertEquals("Wrong password in "+shadow, expectedPassword, passwordValue.getClearValue()); } + + protected void assertFilter(ObjectFilter filter, Class expectedClass) { + if (expectedClass == null) { + assertNull("Expected that filter is null, but it was "+filter, filter); + } else { + assertNotNull("Expected that filter is of class "+expectedClass.getName()+", but it was null", filter); + if (!(expectedClass.isAssignableFrom(filter.getClass()))) { + AssertJUnit.fail("Expected that filter is of class "+expectedClass.getName()+", but it was "+filter); + } + } + } }