Author: tchemit Date: 2009-05-04 07:13:44 +0000 (Mon, 04 May 2009) New Revision: 1377 Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidator.java jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidator.java Log: add a UNIQUE_KEY mode in CollectionExpressionFieldValidator Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidator.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidator.java 2009-05-04 01:01:04 UTC (rev 1376) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionFieldExpressionValidator.java 2009-05-04 07:13:44 UTC (rev 1377) @@ -5,6 +5,8 @@ import com.opensymphony.xwork2.validator.validators.FieldExpressionValidator; import java.util.Collection; +import java.util.Set; +import org.apache.commons.lang.builder.HashCodeBuilder; /** * Un validateur basé sur {@link FieldExpressionValidator} qui valide sur une collection de propriéte. @@ -22,7 +24,9 @@ /** toutes les valeurs de la collection doivent etre valides */ ALL, /** aucune valeur de la collection doivent etre valides */ - NONE + NONE, + /** detection de clef unique */ + UNIQUE_KEY } /** le mode de validation sur la liste */ protected Mode mode; @@ -58,6 +62,11 @@ * Note : Pour le moment, on autorise uniquement cela en mode ALL. */ protected String expressionForLast; + /** + * la liste des propriétés d'une entrée de la collection qui définit la + * clef unique (en mode UNIQUE_KEY). + */ + protected String[] keys; /** le context de parcours */ protected WalkerContext c; private boolean useFirst, useLast; @@ -102,6 +111,18 @@ this.expressionForLast = expressionForLast; } + public String[] getKeys() { + return keys; + } + + public void setKeys(String[] keys) { + if (keys != null && keys.length == 1 && keys[0].indexOf(",") != -1) { + this.keys = keys[0].split(","); + } else { + this.keys = keys; + } + } + @Override public void validate(Object object) throws ValidationException { if (mode == null) { @@ -147,6 +168,12 @@ case NONE: answer = validateNoneEntry(col); break; + case UNIQUE_KEY: + if (keys == null || keys.length == 0) { + throw new ValidationException("no unique keys defined"); + } + answer = validateUniqueKey(col); + break; default: // should never come here... @@ -242,6 +269,30 @@ return count == 1; } + protected Boolean validateUniqueKey(Collection<?> col) throws ValidationException { + boolean answer = true; + + Set<Integer> hashCodes = new java.util.HashSet<Integer>(); + int index = -1; + for (Object entry : col) { + index++; + // construction du hash de la clef d'unicite + Integer hash = getUniqueKeyHashCode(entry); + if (!hashCodes.contains(hash)) { + hashCodes.add(hash); + continue; + } + // une entree avec ce hash a deja ete trouvee + // on est donc en violation sur la clef unique + answer = false; + if (log.isDebugEnabled()) { + log.debug("duplicated uniquekey " + hash + " for entry " + index); + } + } + hashCodes.clear(); + return answer; + } + protected boolean validateOneEntry(Object object) throws ValidationException { Boolean answer = Boolean.FALSE; @@ -276,6 +327,7 @@ } catch (ValidationException e) { throw e; } catch (Exception e) { + log.error(e.getMessage(), e); // let this pass, but it will be logged right below } @@ -323,6 +375,26 @@ return (Collection<?>) obj; } + /** + * Calcule pour une entrée donné, le hash de la clef unique + * + * @param o l'entree de la collection dont on va calculer le hash de la clef unique + * @return le hashCode calclé de la clef unique sur l'entrée donné + * @throws ValidationException if any pb to retreave properties values + */ + protected Integer getUniqueKeyHashCode(Object o) throws ValidationException { + // calcul du hash à la volée + HashCodeBuilder builder = new HashCodeBuilder(); + for (String key : this.keys) { + Object property = getFieldValue(key, o); + if (log.isDebugEnabled()) { + log.debug("key " + key + " : " + property); + } + builder.append(property); + } + return builder.toHashCode(); + } + @Override public String getValidatorType() { return "collectionFieldExpression"; Modified: jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidator.java =================================================================== --- jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidator.java 2009-05-04 01:01:04 UTC (rev 1376) +++ jaxx/trunk/jaxx-runtime-validator/src/main/java/jaxx/runtime/validator/field/CollectionUniqueKeyValidator.java 2009-05-04 07:13:44 UTC (rev 1377) @@ -18,18 +18,18 @@ */ public class CollectionUniqueKeyValidator extends FieldExpressionValidator { - public enum Mode { - - /** au moins une entrée de la collection doit etre valide */ - AT_LEAST_ONE, - /** exactement une entrée dela collection doit être valide */ - EXACTLY_ONE, - /** toutes les valeurs de la collection doivent etre valides */ - ALL, - /** aucune valeur de la collection doivent etre valides */ - NONE - } /** + * pour indiquer la propriété qui contient la liste à valider. + * + * Si cette prorpiété n'est pas renseignée alors on utilise la + * {@link #getFieldName()} pour obtenir la collection. + * + * Cela permet d'effectuer une validation si une collection mais portant + * en fait sur un autre champs + * @since 1.5 + */ + protected String collectionFieldName; + /** * la liste des propriétés d'une entrée de la collection qui définit la * clef unique. */ @@ -47,16 +47,16 @@ */ protected String againstIndexExpression; - public String[] getKeys() { - return keys; + public String getCollectionFieldName() { + return collectionFieldName; } - public String getAgainstProperty() { - return againstProperty; + public void setCollectionFieldName(String collectionFieldName) { + this.collectionFieldName = collectionFieldName; } - public String getAgainstIndexExpression() { - return againstIndexExpression; + public String[] getKeys() { + return keys; } public void setKeys(String[] keys) { @@ -67,10 +67,18 @@ } } + public String getAgainstProperty() { + return againstProperty; + } + public void setAgainstProperty(String againstProperty) { this.againstProperty = againstProperty; } + public String getAgainstIndexExpression() { + return againstIndexExpression; + } + public void setAgainstIndexExpression(String againstIndexExpression) { this.againstIndexExpression = againstIndexExpression; } @@ -165,7 +173,11 @@ * @throws ValidationException if any pb to retreave the collection */ protected Collection<?> getCollection(Object object) throws ValidationException { - String fieldName = getFieldName(); + String fieldName = getCollectionFieldName(); + if (fieldName == null || fieldName.trim().isEmpty()) { + // on travaille directement sur le fieldName + fieldName = getFieldName(); + } Object obj = null;