Howto write custom checks/validation for the play-framework - java

I try to write checks for the play-framework and see two different possibilities. I described both and want to know if my understanding is correct (So it's more a tutorial than a question, specially because I didn't get any response that I missed something).
So what possibilities exists.
The simple way: Extending the class Check:
Advantages: Easier to write, easier to read
Disadvantages: You can't parametrized the check, you can only define the message.
The advanced way: Writing an check based on OVal AbstractAnnotationCheck.
Advantages: You can parametrized the check and have a simpler to use annotation
Disadvantages: A little bit more complicated.
Before we have a look on the implementation I want to explain the messages. You can always set the message directly or use a key to refer the message in a message-properties. The last one is the cleaner and recommended way. Every validation get a least 1 parameter: The name of the property which isn't valid. So validation or check specific parameters are always referred with %i$s where i>1. The format of the message string should follows the rules of Formatter but I'm unsure if all features are supported. As far as I know only %s, %d and %f is supported togeter with positioning. So %[argument_index$][flags]conversion where conversion could only be s,d or f.
Lets have a look on two examples:
The simple way I used in my module for optimistic locking:
/**
* Check with proof if the version of the current edited object is lesser
* than the version in db.
* Messagecode: optimisticLocking.modelHasChanged
* Parameter: 1 the request URL.
* Example-Message: The object was changed. Reload and do your changes again.
*
*/
static class OptimisticLockingCheck extends Check {
/**
* {#inheritDoc}
*/
#Override
public boolean isSatisfied(Object model, Object optimisiticLockingViolatedValue) {
//The comparision of version was made in the setter. Here
//we only have to check the flag.
if (((VersionedModel) model).optimisiticLockingViolated) {
final Request request = Request.current();
//The following doesn't work in 1.0 but in 1.1 see https://bugs.launchpad.net/play/+bug/634719
//http://play.lighthouseapp.com/projects/57987-play-framework/tickets/116
//setMessage(checkWithCheck.getMessage(), request != null ? request.url : "");
setMessage("optimisticLocking.modelHasChanged", request != null ? request.url : "");
}
return !((VersionedModel) model).optimisiticLockingViolated;
}
}
You use this Check with the annotation #CheckWith(value=OptimisticLockingCheck.class, message="optimisticLocking.modelHasChanged")
So lets have a closer look how it works. The only thing we have to do is to extends the class play.data.validation.Check and overwrite the isSatisfied method. There you get your model and the value of the properties. All you have to do is to return true if everything is OK or false otherwise. In our case we want to set the current url as a parameter. This
can be easily done by calling setMessage(). We give the message or the message key which is defined in the messages properties and the parameters. Remember we only give 1 parameter but referred as with %2$s, because the first parameter is always the name of the property.
Now the complex way based on the Range-check of play:
First we need to define an Annotation
/**
* This field must be lower than and greater than.
* Message key: validation.range
* $1: field name
* $2: min reference value
* $3: max reference value
*/
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Constraint(checkWith = RangeCheck.class)
public #interface Range {
String message() default RangeCheck.mes;
double min() default Double.MIN_VALUE;
double max() default Double.MAX_VALUE;
}
and then the Check
#SuppressWarnings("serial")
public class RangeCheck extends AbstractAnnotationCheck<Range> {
final static String mes = "validation.range";
double min;
double max;
#Override
public void configure(Range range) {
this.min = range.min();
this.max = range.max();
setMessage(range.message());
}
public boolean isSatisfied(Object validatedObject, Object value, OValContext context, Validator validator) {
requireMessageVariablesRecreation();
if (value == null) {
return true;
}
if (value instanceof String) {
try {
double v = Double.parseDouble(value.toString());
return v >= min && v <= max;
} catch (Exception e) {
return false;
}
}
if (value instanceof Number) {
try {
return ((Number) value).doubleValue() >= min && ((Number) value).doubleValue() <= max;
} catch (Exception e) {
return false;
}
}
return false;
}
#Override
public Map<String, String> createMessageVariables() {
Map<String, String> messageVariables = new TreeMap<String, String>();
messageVariables.put("2-min", Double.toString(min));
messageVariables.put("3-max", Double.toString(max));
return messageVariables;
}
}
OK I think the annotation don't must be explained. Lets have look on the check. In this case it's extends net.sf.oval.configuration.annotation.AbstractAnnotationCheck. We have to write a configure-method where we get the annotation and can copy the parameters. Then we have to define our check. Which is analog to the implementation of the other check. So we only write our condition and return true or false, except one special line! If we used a parametrized message, we must call requireMessageVariablesRecreation(); in our method.
At least we must override the method createMessageVariables. Here we have to get a littlebit play-knowlegde (all the other stuff is described here). You put your messages into an map with a key and value, but play only takes the values (see ValidCheck.java in framework code). So it will be referenced by position. This is the reason I changed the implementation of the RangeCheck using TreeMap instead of HashMap. Furthermore I let the keys start with the index which they can referred.
So I hope this makes it more clear how to write custom validations/checks for play. I hope the description is correct. Therefor the question is my understanding correct?

At least your first example appears to be on the correct path. You can compare it to the documentation provided below, but I'd assume from the complexity of your example that you've already referred to it.
http://www.playframework.org/documentation/1.1/validation#custom
I don't know enough about the play framework to comment on the second example.

Related

How can I use functional programming to do string manipulation?

I'm writing a function where I'm essentially doing the same thing over and over. I have the function listed below
public String buildGarmentsString(List<Garment> garments)
{
StringBuilder garmentString = new StringBuilder(10000);
for(int i=0;i<4;i++)
{
garmentString.append(this.garmentProductId(i,garments.get(i).getProductId()));
garmentString.append(this.garmentColor(i,garments.get(i).getColor()));
for(int j=0;j<garments.get(i).getSizes().size();j++)
{
//check xxsml
if(garments.get(i).getSizes().get(j).getXxsml() >0)
{
garmentString.append(this.garmentSizes(i, Size.xxsml(),garments.get(i).getSizes().get(j).getXxsml()));
}
//check xsml
if(garments.get(i).getSizes().get(j).getXsml() > 0)
{
garmentString.append(this.garmentSizes(i,Size.xsml(),garments.get(i).getSizes().get(j).getXsml()));
}
//check sml
if(garments.get(i).getSizes().get(j).getSml() > 0)
{
garmentString.append(this.garmentSizes(i,Size.sml(),garments.get(i).getSizes().get(j).getSml()));
}
//check med
if(garments.get(i).getSizes().get(j).getMed() > 0)
{
garmentString.append(this.garmentSizes(i,Size.med(),garments.get(i).getSizes().get(j).getMed()));
}
//check lrg
if(garments.get(i).getSizes().get(j).getLrg() > 0)
{
garmentString.append(this.garmentSizes(i,Size.lrg(),garments.get(i).getSizes().get(j).getLrg()));
}
//check xlrg
if(garments.get(i).getSizes().get(j).getXlg() > 0)
{
garmentString.append(this.garmentSizes(i,Size.xlg(),garments.get(i).getSizes().get(j).getXlg()));
}
//check xxlrg
if(garments.get(i).getSizes().get(j).getXxl() >0)
{
garmentString.append(this.garmentSizes(i,Size.xxlg(),garments.get(i).getSizes().get(j).getXxl()));
}
//check xxxlrg
if(garments.get(i).getSizes().get(j).getXxxl() >0)
{
garmentString.append(this.garmentSizes(i,Size.xxxlg(),garments.get(i).getSizes().get(j).getXxxl()));
}
}
}
}
This is my garmentSizes function:
public String garmentSizes(int garmentNumber, String size,int numberToSend)
{
String garmentSizes = "&garment["+garmentNumber+"][sizes]["+size+"]="+numberToSend;
return garmentSizes;
}
I'm trying to figure out how I can get this done with a lot less code. I've read that with functional programming you can do things like pass in functions to parameters to other functions. After doing some reading online, I think I want to do something like this but I'm not sure how or what the best approach would be.
I have done some reading here on stack overflow and I've seen people mention using either the Command pattern or FunctionalJava or LambdaJ for trying to approximate this feature in Java. I've read over the documentation for the two libraries and read the Wikipedia Article on the Command Pattern, but I'm still not sure how I would use any of those to solve my particular problem. Can somebody explain this to me? As somebody that has never done any functional programming this is a bit confusing.
You could use local variables to decrease the amount of repetition. Say bySize = garments.get(i).getSizes().get(j) for example.
instead of size.getXxsml(), size.getXsml() etc. you could use an enum for sizes and loop on sizes.
The whole thing would then look like:
for(int j=0;j<garments.get(i).getSizes().size();j++) {
bySize = garments.get(i).getSizes().get(j);
for (Size s : Size.values()) {
if (bySize.get(s) > 0) {
garmentString.append(garmentSizes(i, s, bySize.get(s)));
}
}
}
The bySize.get(s) method could be implemented either with a switch that directs to the right method or directly in the enum and you could get rid of the getXsml etc. methods.
The only thing which differs between all your checks is this:
getXxsml/xxsml, getXsml/xsml, getSml/sml, etc.
If you could pass these values (as strings) to some upper-level method, and if
that upper-level method could eval i.e. execute these strings, then you can just
have an array of these values and pass that array to that upper-level method.
In Java, you can do something similar with reflection.
All these checks could indeed be simplified to much less
code through the use of reflection.
Look at:
java.lang.Class
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor
and you will see what I mean.
From your code it appears that some Class has the following methods:
xxsml(), xsml(), sml(), med(), ..., xxxlg()
to get the amounts (?) available for each size.
You can design your data better, like this:
Have a "Size" type, that enumerates all sizes (could be Enum or some class with attribute String key)
Have a method that returns a List of all known sizes.
replace the above methods with amountFor(Size) This could be backed by a Map<Size, Integer>
For backward compatibility, you could rewrite the old methods along the lines:
int xxsml() {
return amountFor(Size.XXSML); // assuming you have a singleton instance
// for each well known size
}
Of course, in getGarmentString, you would then loop through the List of all known sizes:
for (Size sz : Size.getAllKnownSizes()) {
if (garments.get(i).getSizes().get(j).amountFor(sz) > 0) {
... do whatever must be done here
}
}

Is it a good practice to return a boolean/value instead of null in case of no-ops?

This observation was made after looking at addNode code in DirectedGraph.java. The coder has used a true and a false to distinguish a no-op from an op. A similar example is the code below custom made simply to ask my question easily. Is it a recommended / good practice to return boolean to differentiate and no-op from an op to give more visibility to the client of code ?
public class FreeMain {
private List<Integer> fooList;
FreeMain ( ) { }
/**
* Lazy init - either set a value of no-op.
*
* #param barList
*/
public void putList(List<Integer> barList) {
if (this.fooList == null) {
this.fooList = barList;
}
}
/**
* Boolean returned as an indication to the user of operation status
*
* #param barList
* #return true if putLists sets the value, false is no-op.
*/
public boolean putListWithBoolean(List<Integer> barList) {
if (this.fooList == null) {
this.fooList = barList;
return true;
}
return false;
}
}
I will set it this way, is the responsibillity of the putList in this case to tell you whether the list you try to put is accepted or not by returning a boolean? In my opinion no, this is because the putList should handle only the single module of replacing the list pointer and not return something.
If you actually want to know whether the conditions are granted or not(or for any ubnormal behavior that could occur), use Exceptions. Then simply catch those exceptions into your main when the putList is used(with try-catch blocks) and do whatever you wish.
For example:
public void putList(List<Integer> barList) throws new MyListException{
if (this.fooList == null) {
this.fooList = barList;
} else {
throw new MyListException("The pointer of fooList can not be changed because the fooList is not null");
}
}
public class MyListException extends Exception {
public MyListException(String s) {
super(s);
}
}
On the other hand, the case that the method would return a true/false is when it should actually handle that module and determine whether a list will be accepted or not by testing the condition. Thus, the method name will be 'isListAccepted()' (a parameter is not needed since it doesnt play any role). However, in java it is noticed (i.e See LinkedList click here) that sometimes methods like public boolean add(E e) returns true/false. This is because those methods are implemented under the collection interface and there are some preconditions in the way the collection works. Additionally, in this case as well oracle documentation says:
public boolean add(E e) Ensures that this collection contains the specified element
(optional operation). Returns true if this collection changed as a result of the
call. (Returns false if this collection does not permit duplicates and
already contains the specified element.)
If a collection refuses to add a particular element for any reason
other than that it already contains the element, it must throw an
exception (rather than returning false).
So based on that, I believe that these operations, handle the module of telling you if your collection has changed or not after their use rather than adding the element(even if they do in some cases).
An example:
private boolean isListAccepted() {
return this.fooList == null;
}
Finally, since I am not sure too about what do you mean with "instead of null in case of no-operations", I am gonna say that: when you use the putList(..) and the condition is not granted, it doesnt return null, but rather it is doing nothing. However, it is always preferable in this case as well to use Exceptions as I already demonstrate(in the first example) so that you will know what went wrong in case you expect the putList() to actually replace the pointer. And this is because you wont always have the chance to spend time searching the code to understand what went wrong. This is not really important with the code example you provided since it is simple but what if you had a putList that was more complex and multiple things could go wrong ?
Overall, i can not say if putListWithBoolean() is a bad practice because it depends on the way it is used(as shown with the java example), while the putList() without exceptions can be considered as a bad practice, because your classes wont be that simple always, and many things could go wrong, so you better know what went wrong and where.

How to check if the page has content?

I would like to avoid activating some page if its content is empty. I do this with some servlet as follow:
#SlingServlet(paths = "/bin/servlet", methods = "GET", resourceTypes = "sling/servlet/default")
public class ValidatorServlet extends SlingAllMethodsServlet {
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
String page = "pathToPage";
PageManager pageManager = request.adaptTo(PageManager.class);
Page currentPage = pageManager.getPage(page);
boolean result = pageHasContent(currentPage);
}
Now how to check, if currentPage has content?
Please note that the following answer was posted in 2013 when CQ/AEM was a lot different to the current version. The following may not work consistently if used. Refer to Tadija Malic's answer below for more on this.
The hasContent() method of the Page class can be used to check whether the page has content or not. It returns true if the page has jcr:content node, else returns false.
boolean result = currentPage != null ? currentPage.hasContent() : false;
In case you would like to check for pages that have not been authored, one possible way is to check if there are any additional nodes that are present under jcr:content.
Node contentNode = currentPage.getContentResource().adaptTo(Node.class);
boolean result = contentNode.hasNodes();
I would create an OSGi service that takes a Page and walks its content tree according to the rules that you set to find out whether the page has meaningful content.
Whether a page has actual content or not is application-specific, so creating your own service will give you full control on that decision.
One way is to create a new page using the same template and then iterating through the node list and calculating the hash of components (or their content depending on what exactly you want to compare). Once you have the hash of an empty page template, then then you can compare any other page hash with that.
Note: this solution needs to be adapted to your own use case. Maybe it is enough for you to check which components are on the page and their order, and maybe you want to compare their configurations as well.
private boolean areHashesEqual(final Resource copiedPageRes, final Resource currentPageRes) {
final Resource currentRes = currentPageRes.getChild(com.day.cq.commons.jcr.JcrConstants.JCR_CONTENT);
return currentRes != null && ModelUtils.getPageHash(copiedPageRes).equals(ModelUtils.getPageHash(currentRes));
}
Model Utils:
public static String getPageHash(final Resource res) {
long pageHash = 0;
final Queue<Resource> components = new ArrayDeque<>();
components.add(res);
while (!components.isEmpty()) {
final Resource currentRes = components.poll();
final Iterable<Resource> children = currentRes.getChildren();
for (final Resource child : children) {
components.add(child);
}
pageHash = ModelUtils.getHash(pageHash, currentRes.getResourceType());
}
return String.valueOf(pageHash);
}
/**
* This method returns product of hashes of all parameters
* #param args
* #return int hash
*/
public static long getHash(final Object... args) {
int result = 0;
for (final Object arg : args) {
if (arg != null) {
result += arg.hashCode();
}
}
return result;
}
Note: using Queue will consider the order of components as well.
This was my approach, but I had a very specific use case. In general, you would want to think if you really want to calculate the hash of every component on every page you want to publish since this will slow down the publishing process.
You can also compare hash in every iteration and break the calculation on the first difference.

StringTemplate: increment value when if condition true

I want to find out if StringTemplate have/support incrementation of a number.
Situation is:
input: is an array of objects which have "isKey() and getName()" getter.
output should be (i=0; IF !obj.getKey() THEN ps.setObject(i++,obj.getName)) ENDIF):
ps.setObject(1,"Name");
ps.setObject(2,"Name");
ps.setObject(3,"Name");
...
Currently I have next ST: <objs:{<if(it.key)><else>ps.setObject(<i>, <it.name;>);<"\n"><endif>}>
And the output in case if 1st is key:
ps.setObject(2,"Name");
ps.setObject(3,"Name");
ps.setObject(4,"Name");
...
Issue now I need to find a way to replace the 'i' with something which will be increment only when if condition is true.
PLS advice who faced this kind of issue!
In general, changing the state in response to ST's getting the state is not a good idea, so numbering non-key fields should happen in your model, before you start with the generation.
Add a getter for nonKeyIndex to the class of your model that hosts the name property. Go through all siblings, and number them as you need (i.e. starting from one and skipping the keys in your numbering). Now you can use this ST to produce the desired output:
<objs:{<if(it.key)><else>ps.setObject(<it.nonKeyIndex>, <it.name;>);<"\n"><endif>}>
Sometimes it may not be possible to add methods such as nonKeyIndex to your model classes. In such cases you should wrap your classes into view classes designed specifically to work with string template, and add the extra properties there:
public class ColumnView {
private final Column c;
private int nonKeyIdx;
public ColumnView(Column c) {this.c = c;}
public String getName() { return c.getName(); }
public boolean getKey() { return c.getKey(); }
public int getNonKeyIndex() { return nonKeyIdx; }
public void setNonKeyIndex(int i) { nonKeyIdx = i; }
}

Google Collections Suppliers and Find

I'm looking for a Google Collections method that returns the first result of a sequence of Suppliers that doesn't return null.
I was looking at using Iterables.find() but in my Predicate I would have to call my supplier to compare the result against null, and then have to call it again once the find method returned the supplier.
Given your comment to Calm Storm's answer (the desire not to call Supplier.get() twice), then what about:
private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() {
public X apply(Supplier<X> in) {
// If you will never have a null Supplier, you can skip the test;
// otherwise, null Supplier will be treated same as one that returns null
// from get(), i.e. skipped
return (in == null) ? null : in.get();
}
}
then
Iterable<Supplier<X>> suppliers = ... wherever this comes from ...
Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY);
X first = Iterables.find(supplied, Predicates.notNull());
note that the Iterable that comes out of Iterables.transform() is lazily-evaluated, therefore as Iterables.find() loops over it, you only evaluate as far as the first non-null-returning one, and that only once.
You asked for how to do this using Google Collections, but here's how you would do it without using Google Collections. Compare it to Cowan's answer (which is a good answer) -- which is easier to understand?
private static Thing findThing(List<Supplier<Thing>> thingSuppliers) {
for (Supplier<Thing> supplier : thingSuppliers) {
Thing thing = supplier.get();
if (thing != null) {
return thing;
}
}
// throw exception or return null
}
In place of the comment -- if this was the fault of the caller of your class, throw IllegalArgumentException or IllegalStateException as appropriate; if this shouldn't have ever happened, use AssertionError; if it's a normal occurrence your code that invokes this expects to have to check for, you might return null.
What is wrong with this?
List<Supplier> supplierList = //somehow get the list
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){
boolean apply(Supplier supplier) {
return supplier.isSomeMethodCall() == null;
}
boolean equals(Object o) {
return false;
}
});
Are you trying to save some lines? The only optimisation I can think is to static import the find so you can get rid of "Iterables". Also the predicate is an anonymous inner class, if you need it in more than one place you can create a class and it would look as,
List<Supplier> supplierList = //somehow get the list
Supplier s = find(supplierList, new SupplierPredicateFinder());
Where SupplierPredicateFinder is another class.
UPDATE : In that case find is the wrong method. You actually need a custom function like this which can return two values. If you are using commons-collections then you can use a DefaultMapEntry or you can simply return an Object[2] or a Map.Entry.
public static DefaultMapEntry getSupplier(List<Supplier> list) {
for(Supplier s : list) {
Object heavyObject = s.invokeCostlyMethod();
if(heavyObject != null) {
return new DefaultMapEntry(s, heavyObject);
}
}
}
Replace the DefaultMapEntry with a List of size 2 or a hashmap of size 1 or an array of length 2 :)

Categories

Resources