You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by Apache Wiki <wi...@apache.org> on 2009/06/08 07:19:50 UTC

[Myfaces Wiki] Update of "Extensions/Validator/ConceptOverview/Constraint Aspects" by GerhardPetracek

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Myfaces Wiki" for change notification.

The following page has been changed by GerhardPetracek:
http://wiki.apache.org/myfaces/Extensions/Validator/ConceptOverview/Constraint_Aspects

New page:
= Constraint Aspects/Parameters =

This feature is available in MyFaces ExtVal in the 3rd release.[[BR]]
Before the official release you can use it via the snapshot version.

== The Problem ==
{{{
//not typesafe:
@Required(parameters = {@Param(key= "severity", value = "warn"), @Param(key= "display", value = "global")})
}}}
... this version allows you to add general information to a constraint. You can think about it as an extension point for constraints.

Constraint aspects allow to provide a typesafe alternative. So you can provide an ExtVal add-on without knowing the concrete constraint implementation.[[BR]]
Only a central logic (e.g. an add-on) has to know what information might be available as parameter at the constraint and how to use this information.[[BR]]
The final usage is quite easy (see the next example).

So you can have add-on-X which provides new features and constraints Y (they don't know each other). But you can use the features of add-on-X with constraints Y (if they have an attribute of the type '''Class<? extends ValidationParameter>[]''')

=== How to use constraint parameters ===

Example usage of an ExtVal constraint + validation parameters:
{{{
@Required(parameters = {ViolationSeverity.Warn.class, DisplayGlobal.class})
}}}

'''That's it!!!'''

You can see - the final usage is typesafe, shorter and the constraint isn't aware of the specific values behind.[[BR]]
So if you have existing constraints you just have to add an attribute of the type '''Class<? extends ValidationParameter>[]''' and your constraint can automatically use any feature provided via a parameter implementation of ExtVal or an ExtVal add-on.

----
Stop reading here if you don't like to implement a custom parameter or if you don't like to query information of a parameter
----

Before you continue reading - constraint aspects don't replace "domain-attributes".[[BR]]
E.g. the values of min and max of @Length are attributes of the constraint which might be different at every usage.[[BR]]
Furthermore, they aren't interesting for other constraints like @Equals.[[BR]]
So it doesn't make sense to use a generic concept to replace such attributes.[[BR]]

Anyway, there are use-cases for shared features. ExtVal uses this mechanism e.g. for severities. Constraint aspects are interesting for features which allow a small set of possible values and which are interesting for different constraints of the whole application.[[BR]]
'''Without''' a generic solution you have to introduce one attribute per feature for every use-case at every constraint. And the implementation which uses these information have to be aware of all types of constraints (esp.: if you don't have a fix attribute name for it).

Constraint aspects allow you to extend the functionality of existing constraints.[[BR]]
Furthermore, they allow to introduce shared features. The implementations to process the information provided by the aspects/parameters aren't aware of the attribute name of the parameter nor of the concrete type of the constraint, parameter,... That means you provide a generic aspect attribute mechanism once and use it for different constraints and features.

== More Examples ==
You can query the parameters of a constraint at any time.
(You just need access to the constraint.)

Example for a custom constraint:
{{{
public @interface MyConstraint {
  Class<? extends ValidationParameter>[] params() default ViolationSeverity.Error.class;
}
}}}
The important part is: Class< ? extends ValidationParameter >[[BR]]
You can choose any attribute-name! (An array isn't required)[[BR]]
A parameter implementation has to implement this marker interface. The values within the implementation are marked via '''@ParameterValue'''. Optionally you can provide '''@ParameterKey'''. If you don't specify an explicit key, the interface extending the ValidationParameter interface is the key.

== Examples for possible parameter implementation styles ==

=== Parameter implementation - style 1 ===
Direct implementation (just an interface - no concrete class) + grouped values

{{{
public interface ViolationSeverity {
  interface Warn extends ValidationParameter {
    @ParameterKey
    public Class KEY = ViolationSeverity.class;

    @ParameterValue
    FacesMessage.Severity SEVERITY = FacesMessage.SEVERITY_WARN;
  }

  interface Error extends ValidationParameter {
    @ParameterKey
    public Class KEY = ViolationSeverity.class;

    @ParameterValue
    FacesMessage.Severity SEVERITY = FacesMessage.SEVERITY_ERROR;
  }
  // the other severities ...
}
}}}

=== Parameter implementation - style 2 ===
Direct implementation (just an interface - no concrete class) + key that doesn't introduce a class dependency

{{{
public interface AllowClientSideValidation extends ValidationParameter {
  @ParameterKey
  public String key = "client_side_validation_support";

  @ParameterValue
  boolean value = true;
}

public interface RestrictClientSideValidation extends ValidationParameter {
  @ParameterKey
  public String key = "client_side_validation_support";

  @ParameterValue
  boolean value = false;
}
}}}

=== Parameter implementation - style 3 ===
Class with implicit key + mixed value types + multiple values with the same type

{{{
public interface Priority extends ValidationParameter {
  @ParameterValue
  Integer getValue();

  @ParameterValue(id = ShortDescription.class)
  String getShortDescription();

  @ParameterValue(id = LongDescription.class)
  String getLongDescription();

  interface ShortDescription{}
  interface LongDescription{}
}

public class HighPriority implements Priority {
  public Integer getValue() {
    return 1;
  }

  public String getShortDescription() {
    return "do it asap";
  }

  public String getLongDescription() {
    return "do it immediately";
  }
}

public class LowPriority implements Priority {
  public Integer getValue() {
    return 3;
  }

  public String getShortDescription() {
    return "not that important";
  }

  public String getLongDescription() {
    return "the topic is not that important";
  }
}
}}}

=== Using the constraint and these parameter implementations ===

{{{
@MyConstraint(params = {ViolationSeverity.Warn.class, AllowClientSideValidation.class, HighPriority.class})
}}}

=== Query the information ===
{{{
ValidationParameterExtractor extractor = ExtValUtils.getValidationParameterExtractor();

//extract all available parameters - returns a list
extractor().extract(myConstraint)

//query the severity - returns a list
extractor().extract(myConstraint, ViolationSeverity.class, FacesMessage.Severity.class)

//query all information of the priority (independent of the type) - returns a list
extractor().extract(myConstraint, Priority.class)

//query information of the priority - the result is filtered by type - returns a list
extractor().extract(myConstraint, Priority.class, Integer.class)

//query all descriptions of the priority - returns a list
extractor().extract(myConstraint, Priority.class, String.class)

//query a specific description - returns a single result
extractor().extract(myConstraint, Priority.class, String.class, Priority.ShortDescription.class)
}}}

As you see the extractor is a generic impl. which allows an easier usage of the constraint aspects.[[BR]]
You can see the signatures of the methods at: [http://svn.apache.org/repos/asf/myfaces/extensions/validator/trunk/core/src/main/java/org/apache/myfaces/extensions/validator/core/validation/parameter/ValidationParameterExtractor.java ValidationParameterExtractor.java]

This concept isn't bound to ExtVal. ExtVal just provides one possible implementation which allows different parameter styles which are quite flexible in view of key/value aggregation and much more...