/*
* Copyright (C) NetStruxr, Inc. All rights reserved.
*
* This software is published under the terms of the NetStruxr
* Public Software License version 0.5, a copy of which has been
* included with this distribution in the LICENSE.NPL file. */
package er.extensions.validation;
import java.util.NoSuchElementException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EOUtilities;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSKeyValueCoding;
import com.webobjects.foundation.NSMutableDictionary;
import com.webobjects.foundation.NSValidation;
import er.extensions.foundation.ERXStringUtilities;
import er.extensions.localization.ERXLocalizer;
/**
* This is more of a legacy object that was used until
* we had {@link ERXValidationFactory ERXValidationFactory} in place.
* The only place where this is used is when handling
* {@link com.webobjects.foundation.NSValidation.ValidationException ValidationExceptions}
* that have not been converted by the ERXValidationFactory. This class is
* also used to handle formatter exceptions that are thrown number formatters in
* WOComponents.
*/
public class ERXValidation {
private static final Logger log = LoggerFactory.getLogger("er.validation.ERValidation");
/** holds the static constant for pushing an incorrect value onto an eo */
public final static boolean PUSH_INCORRECT_VALUE_ON_EO=true;
/** holds the static constant for not pushing an incorrect value onto an eo */
public final static boolean DO_NOT_PUSH_INCORRECT_VALUE_ON_EO=false;
/** holds the default constant for pushing on values onto eos, defaults to false */
private static boolean pushChangesDefault = DO_NOT_PUSH_INCORRECT_VALUE_ON_EO;
/**
* Sets pushing changes onto enterprise objects when a
* validation exception occurs.
* @param val sets whether incorrect values should be pushed
* onto an object
*/
public static void setPushChangesDefault(boolean val) {
pushChangesDefault = val;
}
/**
* Processes a validation exception to make it look better.
* The resulting exception message is set in the errorMessages
* dictionary.
*
* @param e validation exception.
* @param value that failed validation.
* @param keyPath that failed validation.
* @param errorMessages dictionary to place the formatted message into.
* @param displayPropertyKeyPath key used in the case of the formatter exception
* to calculate the pretty display name.
* @param localizer to use to localize the exception.
*/
public static void validationFailedWithException(Throwable e,
Object value,
String keyPath,
NSMutableDictionary errorMessages,
String displayPropertyKeyPath,
ERXLocalizer localizer) {
validationFailedWithException(e,value,keyPath,errorMessages,displayPropertyKeyPath,localizer,null);
}
/**
* Processes a validation exception to make it look better.
* The resulting exception message is set in the errorMessages
* dictionary. This method uses the default value for pushing values
* onto the eo.
*
* @param e validation exception.
* @param value that failed validation.
* @param keyPath that failed validation.
* @param errorMessages dictionary to place the formatted message into.
* @param displayPropertyKeyPath key used in the case of the formatter exception
* to calculate the pretty display name.
* @param localizer to use to localize the exception.
* @param entity that the validation exception is happening too.
*/
public static void validationFailedWithException(Throwable e,
Object value,
String keyPath,
NSMutableDictionary errorMessages,
String displayPropertyKeyPath,
ERXLocalizer localizer,
EOEntity entity) {
validationFailedWithException(e,value,keyPath,errorMessages, displayPropertyKeyPath, localizer, entity, pushChangesDefault);
}
/**
* Processes a validation exception to make it look better.
* The resulting exception message is set in the errorMessages
* dictionary.
*
* @param e validation exception.
* @param value that failed validation.
* @param keyPath that failed validation.
* @param errorMessages dictionary to place the formatted message into.
* @param displayPropertyKeyPath key used in the case of the formatter exception
* to calculate the pretty display name.
* @param localizer to use to localize the exception.
* @param entity that the validation exception is happening too.
* @param pushChanges boolean to flag if the bad values should be pushed onto the
* eo.
*/
public static void validationFailedWithException(Throwable e,
Object value,
String keyPath,
NSMutableDictionary errorMessages,
String displayPropertyKeyPath,
ERXLocalizer localizer,
EOEntity entity,
boolean pushChanges) {
if (log.isDebugEnabled())
log.debug("ValidationFailedWithException: {} message: {}", e.getClass(), e.getMessage());
String key = null;
String newErrorMessage=e.getMessage();
if (e instanceof NSValidation.ValidationException && ((NSValidation.ValidationException)e).key() != null
&& ((NSValidation.ValidationException)e).object() != null) {
NSValidation.ValidationException nve = (NSValidation.ValidationException)e;
key = nve.key();
Object eo=nve.object();
// this because exceptions raised by formatters have the failing VALUE in this key..
// strip the exception name
//newErrorMessage=newErrorMessage.substring(newErrorMessage.indexOf(":")+1);
//newErrorMessage=newErrorMessage.substring(newErrorMessage.indexOf(":")+1);
if (eo instanceof EOEnterpriseObject) {
// the exception is coming from EREnterpriseObject
// WE PUSH THE WRONG VALUE INTO THE EO ANYWAY!
if (pushChanges) {
try {
((EOEnterpriseObject)eo).takeValueForKeyPath(value, key);
} catch(NSKeyValueCoding.UnknownKeyException ex) {
// AK: as we could have custom components that have non-existant keys
// we of course can't push a value, so we discard the resulting exception
} catch(NoSuchElementException ex) {
// AK: as we could have custom components that have non-existant keys
// we of course can't push a value, so we discard the resulting exception
} catch(Exception ex) {
log.error("Can't push value to key '{}': {}", key, value, ex);
}
}
entity = EOUtilities.entityForObject(((EOEnterpriseObject)eo).editingContext(),(EOEnterpriseObject)eo);
} else {
//the exception is coming from a formatter
key = NSArray.componentsSeparatedByString(displayPropertyKeyPath,".").lastObject();
newErrorMessage="<b>"+key+"</b>:"+newErrorMessage;
}
} else {
key = keyPath;
}
if (key != null && newErrorMessage != null) {
String displayName = localizedDisplayNameForKey(entity != null ? entity.classDescriptionForInstances() : null, key, localizer);
errorMessages.setObjectForKey(newErrorMessage, displayName);
} else {
if(key != null) {
//log.warn("NULL message for key:'"+key+"': " + ((EOGeneralAdaptorException)e).userInfo() , e);
log.warn("NULL message for key:'{}'", key, e);
} else {
log.warn("NULL key for message:'{}'", newErrorMessage, e);
}
}
}
/**
* Calculates a localized display name for a given entity and key using the supplied localizer
* @param ecd class description the key belongs to
* @param key to localize
* @param localizer to use for localizing the content
* @return the localized display name
*/
public static String localizedDisplayNameForKey(EOClassDescription ecd, String key, ERXLocalizer localizer) {
String displayName;
if (localizer != null) {
if (ecd != null) {
displayName = localizer.localizedDisplayNameForKey(ecd, key);
} else {
displayName = localizer.localizedStringForKeyWithDefault(key);
}
} else {
if (ecd != null) {
displayName = ecd.displayNameForKey(key);
} else {
displayName = ERXStringUtilities.displayNameForKey(key);
}
}
return displayName;
}
}