diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java index d1ff7fd5a3e..40720175647 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismPropertyPanel.java @@ -31,9 +31,7 @@ import com.evolveum.midpoint.web.component.input.ExpressionValuePanel; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.util.InfoTooltipBehavior; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType; import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; @@ -261,7 +259,11 @@ public boolean isVisible() { @Override protected void populateItem(final ListItem item) { BasePanel panel; - if (item.getModelObject().getItem().getItemDefinition().getTypeName().equals(ExpressionType.COMPLEX_TYPE)){ + ItemWrapper itemWrapper = item.getModelObject().getItem(); + if (itemWrapper.getPath().containsName(AssignmentType.F_CONSTRUCTION) && + itemWrapper.getPath().containsName(ConstructionType.F_ASSOCIATION) && + itemWrapper.getPath().containsName(ResourceObjectAssociationType.F_OUTBOUND) && + itemWrapper.getPath().containsName(MappingType.F_EXPRESSION)){ ExpressionWrapper expressionWrapper = (ExpressionWrapper)item.getModelObject().getItem(); panel = new ExpressionValuePanel("value", new PropertyModel(item.getModel(), "value.value"), expressionWrapper.getConstruction(), pageBase); 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 f8a1aef1446..74ebf445f4b 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 @@ -102,6 +102,8 @@ public class SqlRepositoryServiceImpl extends SqlBaseService implements RepositoryService { public static final String PERFORMANCE_LOG_NAME = SqlRepositoryServiceImpl.class.getName() + ".performance"; + public static final String CONTENTION_LOG_NAME = SqlRepositoryServiceImpl.class.getName() + ".contention"; + public static final int CONTENTION_LOG_DEBUG_THRESHOLD = 3; private static final Trace LOGGER = TraceManager.getTrace(SqlRepositoryServiceImpl.class); private static final Trace LOGGER_PERFORMANCE = TraceManager.getTrace(PERFORMANCE_LOG_NAME); diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/BaseHelper.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/BaseHelper.java index 21ef9caf0f5..b5b8e76e341 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/BaseHelper.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/helpers/BaseHelper.java @@ -53,6 +53,7 @@ public class BaseHelper { private static final Trace LOGGER = TraceManager.getTrace(BaseHelper.class); + private static final Trace CONTENTION_LOGGER = TraceManager.getTrace(SqlRepositoryServiceImpl.CONTENTION_LOG_NAME); @Autowired private SessionFactory sessionFactory; @@ -202,15 +203,22 @@ public int logOperationAttempt(String oid, String operation, int attempt, @NotNu try { waitTime = backoffComputer.computeDelay(attempt); } catch (BackoffComputer.NoMoreRetriesException e) { - LOGGER.error("A serialization-related problem occurred, maximum attempts (" + attempt + ") reached.", ex); + CONTENTION_LOGGER.error("A serialization-related problem occurred, maximum attempts ({}) reached.", attempt, ex); + LOGGER.error("A serialization-related problem occurred, maximum attempts ({}) reached.", attempt, ex); if (result != null) { result.recordFatalError("A serialization-related problem occurred.", ex); } throw new SystemException(ex.getMessage() + " [attempts: " + attempt + "]", ex); } - LOGGER.debug("A serialization-related problem occurred when {} object with oid '{}', retrying after " - + "{} ms (this is retry {} of {})\n{}: {}", operation, oid, waitTime, - attempt, LOCKING_MAX_RETRIES, ex.getClass().getSimpleName(), ex.getMessage()); + String message = "A serialization-related problem occurred when {} object with oid '{}', retrying after " + + "{} ms (this is retry {} of {})\n{}: {}"; + Object[] objects = { operation, oid, waitTime, attempt, LOCKING_MAX_RETRIES, ex.getClass().getSimpleName(), ex.getMessage() }; + if (attempt >= SqlRepositoryServiceImpl.CONTENTION_LOG_DEBUG_THRESHOLD) { + CONTENTION_LOGGER.debug(message, objects); + } else { + CONTENTION_LOGGER.trace(message, objects); + } + LOGGER.debug(message, objects); if (waitTime > 0) { try { Thread.sleep(waitTime); diff --git a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java index 2836d060f7f..009a997d003 100644 --- a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java +++ b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskManagerQuartzImpl.java @@ -118,6 +118,7 @@ public class TaskManagerQuartzImpl implements TaskManager, BeanFactoryAware { private static final String DOT_INTERFACE = TaskManager.class.getName() + "."; private static final String DOT_IMPL_CLASS = TaskManagerQuartzImpl.class.getName() + "."; private static final String CLEANUP_TASKS = DOT_INTERFACE + "cleanupTasks"; + public static final String CONTENTION_LOG_NAME = TaskManagerQuartzImpl.class.getName() + ".contention"; @Autowired private TaskManagerConfiguration configuration; diff --git a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/work/WorkStateManager.java b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/work/WorkStateManager.java index 3ea269f6441..71f5102b207 100644 --- a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/work/WorkStateManager.java +++ b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/work/WorkStateManager.java @@ -35,6 +35,7 @@ import com.evolveum.midpoint.task.api.TaskExecutionStatus; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.task.quartzimpl.TaskManagerConfiguration; +import com.evolveum.midpoint.task.quartzimpl.TaskManagerQuartzImpl; import com.evolveum.midpoint.task.quartzimpl.TaskQuartzImpl; import com.evolveum.midpoint.task.quartzimpl.work.segmentation.content.WorkBucketContentHandler; import com.evolveum.midpoint.task.quartzimpl.work.segmentation.content.WorkBucketContentHandlerRegistry; @@ -78,6 +79,7 @@ public class WorkStateManager { private static final Trace LOGGER = TraceManager.getTrace(WorkStateManager.class); + private static final Trace CONTENTION_LOGGER = TraceManager.getTrace(TaskManagerQuartzImpl.CONTENTION_LOG_NAME); @Autowired private TaskManager taskManager; @Autowired private RepositoryService repositoryService; @@ -169,6 +171,7 @@ private WorkBucketType findSelfAllocatedBucket(Context ctx) { private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTime, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, InterruptedException { long start = System.currentTimeMillis(); + int globalAttempt = 0; // just for statistics WorkSegmentationStrategy workStateStrategy = strategyFactory.createStrategy(ctx.coordinatorTask.getWorkManagement()); setOrUpdateEstimatedNumberOfBuckets(ctx.coordinatorTask, workStateStrategy, result); @@ -179,6 +182,7 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi waitForConflictLessUpdate: // this cycle exits when coordinator task update succeeds for (;;) { TaskWorkStateType coordinatorWorkState = getWorkStateOrNew(ctx.coordinatorTask.getTaskPrismObject()); + globalAttempt++; GetBucketResult response = workStateStrategy.getBucket(coordinatorWorkState); LOGGER.trace("getWorkBucketMultiNode: workStateStrategy returned {} for worker task {}, coordinator {}", response, ctx.workerTask, ctx.coordinatorTask); try { @@ -198,6 +202,7 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi bucketsReplacePrecondition(coordinatorWorkState.getBucket()), null, result); repositoryService.modifyObject(TaskType.class, ctx.workerTask.getOid(), bucketsAddDeltas(newBucketsResponse.newBuckets.subList(selected, selected+1)), null, result); + CONTENTION_LOGGER.trace("New bucket(s) acquired after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask); return newBucketsResponse.newBuckets.get(selected); } else if (response instanceof FoundExisting) { FoundExisting existingResponse = (FoundExisting) response; @@ -207,20 +212,26 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi WorkBucketType foundBucket = existingResponse.bucket.clone(); repositoryService.modifyObject(TaskType.class, ctx.workerTask.getOid(), bucketsAddDeltas(singletonList(foundBucket)), null, result); + CONTENTION_LOGGER.trace("Existing bucket acquired after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask); return foundBucket; } else if (response instanceof NothingFound) { if (((NothingFound) response).definite || freeBucketWaitTime == 0L) { markWorkComplete(ctx.coordinatorTask, result); // TODO also if response is not definite? + CONTENTION_LOGGER.trace("'No bucket' found after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask); return null; } else { long waitDeadline = freeBucketWaitTime >= 0 ? start + freeBucketWaitTime : Long.MAX_VALUE; long toWait = waitDeadline - System.currentTimeMillis(); if (toWait <= 0) { markWorkComplete(ctx.coordinatorTask, result); // TODO also if response is not definite? + CONTENTION_LOGGER.trace("'No bucket' found (wait time elapsed) after {} ms (attempt #{}) in {}", System.currentTimeMillis() - start, globalAttempt, ctx.workerTask); return null; } //System.out.println("*** No free work bucket -- waiting ***"); - dynamicSleep(Math.min(toWait, getFreeBucketWaitInterval()), ctx); + long sleepFor = Math.min(toWait, getFreeBucketWaitInterval()); + CONTENTION_LOGGER.trace("Entering waiting for free bucket (waiting for {}) - after {} ms (attempt #{}) in {}", + sleepFor, System.currentTimeMillis() - start, globalAttempt, ctx.workerTask); + dynamicSleep(sleepFor, ctx); ctx.reloadCoordinatorTask(result); ctx.reloadWorkerTask(result); if (reclaimWronglyAllocatedBuckets(ctx.coordinatorTask, result)) { @@ -239,11 +250,16 @@ private WorkBucketType getWorkBucketMultiNode(Context ctx, long freeBucketWaitTi try { delay = backoffComputer.computeDelay(retry); } catch (BackoffComputer.NoMoreRetriesException e1) { - throw new SystemException( - "Couldn't allocate work bucket because of repeated database conflicts (retry limit reached); coordinator task = " + ctx.coordinatorTask, e1); + String message = + "Couldn't allocate work bucket because of repeated database conflicts (retry limit reached); coordinator task = " + + ctx.coordinatorTask; + CONTENTION_LOGGER.error(message, e1); + throw new SystemException(message, e1); } - LOGGER.info("getWorkBucketMultiNode: conflict; continuing as retry #{}; waiting {} ms in {}, worker {}", - retry, delay, ctx.coordinatorTask, ctx.workerTask, e); + String message = "getWorkBucketMultiNode: conflict; continuing as retry #{}; waiting {} ms in {}, worker {}"; + Object[] objects = { retry, delay, ctx.coordinatorTask, ctx.workerTask, e }; + CONTENTION_LOGGER.debug(message, objects); + LOGGER.info(message, objects); // todo change to trace dynamicSleep(delay, ctx); ctx.reloadCoordinatorTask(result); ctx.reloadWorkerTask(result); @@ -320,6 +336,7 @@ private boolean reclaimWronglyAllocatedBuckets(Task coordinatorTask, OperationRe } LOGGER.trace("Reclaiming wrongly allocated buckets found {} buckets to reclaim in {}", reclaiming, coordinatorTask); if (reclaiming > 0) { + CONTENTION_LOGGER.debug("Reclaiming wrongly allocated buckets found {} buckets to reclaim in {}", reclaiming, coordinatorTask); repositoryService.modifyObject(TaskType.class, coordinatorTask.getOid(), bucketsReplaceDeltas(newState.getBucket()), bucketsReplacePrecondition(originalState.getBucket()), null, result); diff --git a/samples/objects/function-library-mail-templates.xml b/samples/objects/function-library-mail-templates.xml new file mode 100644 index 00000000000..664f6449b16 --- /dev/null +++ b/samples/objects/function-library-mail-templates.xml @@ -0,0 +1,61 @@ + + + + mailTemplates + Velocity mail templates for various languages + + en + + username + xsd:string + + + xsd:string + + + sk + + username + xsd:string + + + xsd:string + + + default + + username + xsd:string + + + xsd:string + + diff --git a/samples/objects/system-configuration-multilanguage-notifier.xml b/samples/objects/system-configuration-multilanguage-notifier.xml new file mode 100644 index 00000000000..758089bf18e --- /dev/null +++ b/samples/objects/system-configuration-multilanguage-notifier.xml @@ -0,0 +1,85 @@ + + + + System Configuration + + + + + + + Welcome new user + + + + + iam@localhost + + + + + + + + mail + + + + + mail-notifications.log + + + sms-notifications.log + + + + + +