Skip to content

Commit

Permalink
User-friendly vs technical message for CommonException
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Dec 7, 2017
1 parent b7abe77 commit 04efb3f
Show file tree
Hide file tree
Showing 39 changed files with 278 additions and 108 deletions.
Expand Up @@ -17,6 +17,7 @@
package com.evolveum.midpoint.common;

import com.evolveum.midpoint.util.LocalizableMessage;
import com.evolveum.midpoint.util.exception.CommonException;

import java.util.Locale;

Expand All @@ -34,4 +35,9 @@ public interface LocalizationService {
default String translate(LocalizableMessage msg) {
return translate(msg, Locale.getDefault());
}

/**
* Fills-in message and localizedMessage based on userFriendlyMessage, if needed.
*/
<T extends CommonException> T translate(T e);
}
Expand Up @@ -20,6 +20,7 @@
import com.evolveum.midpoint.util.LocalizableMessage;
import com.evolveum.midpoint.util.LocalizableMessageList;
import com.evolveum.midpoint.util.SingleLocalizableMessage;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
Expand Down Expand Up @@ -180,4 +181,21 @@ private Object[] translateParams(Object[] params, Locale locale) {

return translated;
}

@Override
public <T extends CommonException> T translate(T e) {
if (e == null) {
return null;
}
if (e.getUserFriendlyMessage() == null) {
return e;
}
if (e.getTechnicalMessage() == null) {
e.setTechnicalMessage(translate(e.getUserFriendlyMessage(), Locale.US));
}
if (e.getLocalizedUserFriendlyMessage() == null) {
e.setLocalizedUserFriendlyMessage(translate(e.getUserFriendlyMessage(), Locale.getDefault()));
}
return e;
}
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2010-2017 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.evolveum.midpoint.common;

/**
* For use in tests ONLY.
*
* @author mederly
*/
public class LocalizationTestUtil {

private static LocalizationService localizationService = new LocalizationServiceImpl();

public static LocalizationService getLocalizationService() {
return localizationService;
}
}
Expand Up @@ -17,6 +17,8 @@

import com.evolveum.midpoint.util.LocalizableMessage;

import java.util.Objects;

/**
* Superclass for all common midPoint exceptions.
*
Expand All @@ -25,13 +27,37 @@
*/
public abstract class CommonException extends Exception {

LocalizableMessage userFriendlyMessage;
/**
* User-friendly localizable detail message.
*/
protected LocalizableMessage userFriendlyMessage;

/**
* User-friendly message in system locale. This value should correspond to userFriendlyMessage translated into system locale.
*/
protected String localizedUserFriendlyMessage;

/**
* Technical version of the message. Normally it is the value of userFriendlyMessage translated to English.
* However in some cases technicalMessage might be a bit more technical than userFriendlyMessage/localizedUserFriendlyMessage.
*
* Note that we don't use super.detailMessage for this purpose mainly because it's not settable. We need to set this value
* when the message is created from the user-friendly LocalizableMessage already present in the exception.
* (see LocalizationService.translate(CommonException e)).
*
* So, super.detailMessage should not be relied on in any way. It is basically the same as technicalMessage, differing only
* in rare cases like if a CommonException is initialized from LocalizableMessage (userFriendlyMessage) but is not
* translated by the LocalizationService afterwards. In this situation super.detailMessage is initialized
* from the (potentially non-null) fallback message, while the technicalMessage is null.
*/
private String technicalMessage;

public CommonException() {
}

public CommonException(String message) {
super(message);
public CommonException(String technicalMessage) {
super(technicalMessage);
this.technicalMessage = technicalMessage;
}

public CommonException(LocalizableMessage userFriendlyMessage) {
Expand All @@ -43,25 +69,27 @@ public CommonException(Throwable cause) {
super(cause);
}

public CommonException(String message, Throwable cause) {
super(message, cause);
public CommonException(String technicalMessage, Throwable cause) {
super(technicalMessage, cause);
this.technicalMessage = technicalMessage;
}

public CommonException(LocalizableMessage userFriendlyMessage, Throwable cause) {
super(userFriendlyMessage.getFallbackMessage(), cause);
this.userFriendlyMessage = userFriendlyMessage;
}

public CommonException(String message, Throwable cause, LocalizableMessage userFriendlyMessage) {
super(message, cause);
public CommonException(String technicalMessage, Throwable cause, LocalizableMessage userFriendlyMessage) {
super(technicalMessage, cause);
this.userFriendlyMessage = userFriendlyMessage;
this.technicalMessage = technicalMessage;
}

/**
* Returns a human-readable message that describes the type or class of errors
* that the exception represents. E.g. "Communication error", "Policy violation", etc.
*
* TOTO: switch return value to a localized message
* TODO: switch return value to a localized message
*/
public abstract String getErrorTypeMessage();

Expand All @@ -74,16 +102,49 @@ public LocalizableMessage getUserFriendlyMessage() {
return userFriendlyMessage;
}

public void setUserFriendlyMessage(LocalizableMessage userFriendlyMessage) {
this.userFriendlyMessage = userFriendlyMessage;
@Override
public String getMessage() {
return technicalMessage != null ? technicalMessage : super.getMessage();
}

@Override
public String getLocalizedMessage() {
return localizedUserFriendlyMessage != null ? localizedUserFriendlyMessage : getMessage();
}

// should return null if "real" technical message is not set -- this makes it different from getMessage()
public String getTechnicalMessage() {
return technicalMessage;
}

public void setTechnicalMessage(String technicalMessage) {
this.technicalMessage = technicalMessage;
}

// should return null if "real" localized user friendly message is not set -- this makes it different from getLocalizedMessage()
public String getLocalizedUserFriendlyMessage() {
return getLocalizedMessage();
}

public void setLocalizedUserFriendlyMessage(String localizedUserFriendlyMessage) {
this.localizedUserFriendlyMessage = localizedUserFriendlyMessage;
}

@Override
public String toString() {
if (userFriendlyMessage == null) {
return super.toString();
} else {
return super.toString() + " [" + userFriendlyMessage.shortDump() + "]";
String technicalMessage = getMessage();
String localizedUserFriendlyMessage = getLocalizedMessage(); // this one is used by super.toString
String technicalMessagePart;
if (technicalMessage != null && !Objects.equals(technicalMessage, localizedUserFriendlyMessage)) {
technicalMessagePart = " [" + technicalMessage + "]";
} else {
technicalMessagePart = "";
}
// TODO consider if we really want to display short dump of userFriendlyMessage even if localized and/or english message is present
return super.toString() + technicalMessagePart + " [" + userFriendlyMessage.shortDump() + "]";
}
}
}
Expand Up @@ -16,10 +16,10 @@
package com.evolveum.midpoint.model.api.context;

import java.util.Collection;
import java.util.Set;

import javax.xml.namespace.QName;

import com.evolveum.midpoint.common.LocalizationService;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.delta.DeltaSetTriple;
import com.evolveum.midpoint.schema.result.OperationResult;
Expand Down Expand Up @@ -103,5 +103,6 @@ public interface EvaluatedAssignment<F extends FocusType> extends DebugDumpable

void triggerRule(@NotNull EvaluatedPolicyRule rule, Collection<EvaluatedPolicyRuleTrigger<?>> triggers);

void triggerConstraintLegacy(EvaluatedPolicyRuleTrigger trigger) throws PolicyViolationException;
void triggerConstraintLegacy(EvaluatedPolicyRuleTrigger trigger,
LocalizationService localizationService) throws PolicyViolationException;
}
Expand Up @@ -21,6 +21,7 @@

import javax.xml.namespace.QName;

import com.evolveum.midpoint.common.LocalizationService;
import org.apache.commons.lang.BooleanUtils;

import com.evolveum.midpoint.model.api.ModelService;
Expand Down Expand Up @@ -94,9 +95,10 @@ public abstract class AbstractSearchExpressionEvaluator<V extends PrismValue,D e
private ModelService modelService;

protected AbstractSearchExpressionEvaluator(SearchObjectExpressionEvaluatorType expressionEvaluatorType,
D outputDefinition, Protector protector, ObjectResolver objectResolver,
ModelService modelService, PrismContext prismContext, SecurityContextManager securityContextManager) {
super(expressionEvaluatorType, securityContextManager);
D outputDefinition, Protector protector, ObjectResolver objectResolver,
ModelService modelService, PrismContext prismContext, SecurityContextManager securityContextManager,
LocalizationService localizationService) {
super(expressionEvaluatorType, securityContextManager, localizationService);
this.outputDefinition = outputDefinition;
this.prismContext = prismContext;
this.protector = protector;
Expand Down
Expand Up @@ -25,6 +25,7 @@

import javax.xml.namespace.QName;

import com.evolveum.midpoint.common.LocalizationService;
import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
Expand Down Expand Up @@ -69,21 +70,28 @@
public abstract class AbstractValueTransformationExpressionEvaluator<V extends PrismValue, D extends ItemDefinition, E extends TransformExpressionEvaluatorType>
implements ExpressionEvaluator<V,D> {

private SecurityContextManager securityContextManager;
protected SecurityContextManager securityContextManager;
protected LocalizationService localizationService;

private E expressionEvaluatorType;

private static final Trace LOGGER = TraceManager.getTrace(AbstractValueTransformationExpressionEvaluator.class);

protected AbstractValueTransformationExpressionEvaluator(E expressionEvaluatorType, SecurityContextManager securityContextManager) {
protected AbstractValueTransformationExpressionEvaluator(E expressionEvaluatorType,
SecurityContextManager securityContextManager, LocalizationService localizationService) {
this.expressionEvaluatorType = expressionEvaluatorType;
this.securityContextManager = securityContextManager;
this.localizationService = localizationService;
}

public E getExpressionEvaluatorType() {
return expressionEvaluatorType;
}

public LocalizationService getLocalizationService() {
return localizationService;
}

/* (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)
*/
Expand Down Expand Up @@ -418,8 +426,11 @@ private PrismValueDeltaSetTriple<V> evaluateRelativeExpression(final List<Source
contextDescription, task, result);
} catch (ExpressionEvaluationException e) {
throw new TunnelException(
new ExpressionEvaluationException(e.getMessage() + "("+dumpSourceValues(sourceVariables)+") in "+contextDescription,
e, ExceptionUtil.getUserFriendlyMessage(e)));
localizationService.translate(
new ExpressionEvaluationException(
e.getMessage() + "("+dumpSourceValues(sourceVariables)+") in "+contextDescription,
e,
ExceptionUtil.getUserFriendlyMessage(e))));
} catch (ObjectNotFoundException e) {
throw new TunnelException(new ObjectNotFoundException(e.getMessage()+
"("+dumpSourceValues(sourceVariables)+") in "+contextDescription,e));
Expand Down
Expand Up @@ -19,6 +19,7 @@

import javax.xml.namespace.QName;

import com.evolveum.midpoint.common.LocalizationService;
import com.evolveum.midpoint.model.api.ModelService;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;
Expand Down Expand Up @@ -51,8 +52,9 @@ public class AssignmentTargetSearchExpressionEvaluator

public AssignmentTargetSearchExpressionEvaluator(SearchObjectRefExpressionEvaluatorType expressionEvaluatorType,
PrismContainerDefinition<AssignmentType> outputDefinition, Protector protector, ObjectResolver objectResolver,
ModelService modelService, PrismContext prismContext, SecurityContextManager securityContextManager) {
super(expressionEvaluatorType, outputDefinition, protector, objectResolver, modelService, prismContext, securityContextManager);
ModelService modelService, PrismContext prismContext, SecurityContextManager securityContextManager,
LocalizationService localizationService) {
super(expressionEvaluatorType, outputDefinition, protector, objectResolver, modelService, prismContext, securityContextManager, localizationService);
}

protected PrismContainerValue<AssignmentType> createPrismValue(String oid, QName targetTypeQName, List<ItemDelta<PrismContainerValue<AssignmentType>, PrismContainerDefinition<AssignmentType>>> additionalAttributeDeltas, ExpressionEvaluationContext params) {
Expand Down
Expand Up @@ -26,12 +26,10 @@
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.crypto.Protector;
import com.evolveum.midpoint.repo.common.expression.AbstractObjectResolvableExpressionEvaluator;
import com.evolveum.midpoint.repo.common.expression.AbstractObjectResolvableExpressionEvaluatorFactory;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluator;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluatorFactory;
import com.evolveum.midpoint.repo.common.expression.ExpressionFactory;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectResolver;
import com.evolveum.midpoint.security.api.SecurityContextManager;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand All @@ -45,14 +43,15 @@
* @author semancik
*
*/
public class AssignmentTargetSearchExpressionEvaluatorFactory extends AbstractObjectResolvableExpressionEvaluator {
public class AssignmentTargetSearchExpressionEvaluatorFactory extends AbstractObjectResolvableExpressionEvaluatorFactory {

private final PrismContext prismContext;
private final Protector protector;
private final ModelService modelService;
private final SecurityContextManager securityContextManager;

public AssignmentTargetSearchExpressionEvaluatorFactory(ExpressionFactory expressionFactory, PrismContext prismContext, Protector protector, ModelService modelService, SecurityContextManager securityContextManager) {
public AssignmentTargetSearchExpressionEvaluatorFactory(ExpressionFactory expressionFactory, PrismContext prismContext,
Protector protector, ModelService modelService, SecurityContextManager securityContextManager) {
super(expressionFactory);
this.prismContext = prismContext;
this.protector = protector;
Expand Down Expand Up @@ -93,7 +92,7 @@ public <V extends PrismValue,D extends ItemDefinition> ExpressionEvaluator<V,D>
throw new SchemaException("assignment expression evaluator cannot handle elements of type " + evaluatorTypeObject.getClass().getName()+" in "+contextDescription);
}
AssignmentTargetSearchExpressionEvaluator expressionEvaluator = new AssignmentTargetSearchExpressionEvaluator((SearchObjectRefExpressionEvaluatorType)evaluatorTypeObject,
(PrismContainerDefinition<AssignmentType>) outputDefinition, protector, getObjectResolver(), modelService, prismContext, securityContextManager);
(PrismContainerDefinition<AssignmentType>) outputDefinition, protector, getObjectResolver(), modelService, prismContext, securityContextManager, getLocalizationService());
return (ExpressionEvaluator<V,D>) expressionEvaluator;
}

Expand Down

0 comments on commit 04efb3f

Please sign in to comment.