Combining DLM audience conditions for Mobile customizations

Combining DLM audience conditions for Mobile customizations

I found a couple of entries on the uPortal Mailing list that suggested to me that several people have similar requirements to myself so this is why I am making this available here.

I am using the list based mobile view and would like to have different list folders on the mobile view than I have tabs on the desktop view.  Therefore I think I need to be able to combine DLM Evaluators.

For example I want my desktop guest users to see something different to my mobile guest users.  So my mobile guest DLM fragment might look something like this:

<?xml version="1.0" encoding="UTF-8"?> <fragment-definition xmlns:dlm="http://org.jasig.portal.layout.dlm.config" script="classpath://org/jasig/portal/io/import-fragment-definition_v3-1.crn"> <dlm:fragment name="Mobile Guests" ownerID="mobile-guest-lo" precedence="80"> <dlm:audience evaluatorFactory="edu.bristol.MustMatchAllAudiencesEvaluatorFactory"> <audience evaluatorFactory="org.jasig.portal.layout.dlm.providers.GuestUserEvaluatorFactory"/> <audience evaluatorFactory="org.jasig.portal.layout.dlm.providers.ProfileEvaluatorFactory"> <paren mode="AND"> <profile value="mobileDefault"/> </paren> </audience> </dlm:audience> </dlm:fragment> </fragment-definition>

 

A non-mobile guest user fragment would look almost identical to the above XML except that the mode would be "NOT" rather than "AND" for the profile value.

I have therefore created a DLM Evaluator that can combine DLM audience conditions (See attached classes - apologies for the clumsy name).  This code works by re-using the FragmentDefinition methods but defines a user as belonging to an audience only if all of the nested audience evaluations are met.

I had to tweak FragmentDefinition.java to make constructor and loadAudienceEvaluators() method protected rather than private.  So that my EvaluatorFactory would simply consist of:

public class MustMatchAllAudiencesEvaluatorFactory extends FragmentDefinition implements EvaluatorFactory { public Evaluator getEvaluator(Node node) { Element e = (Element) node; loadAudienceEvaluators(e.getElementsByTagName("audience")); return new MustMatchAllAudiencesEvaluator(evaluators); } }


after which point the Evaluator's core method just needs to conduct the evaluations in order:

public MustMatchAllAudiencesEvaluator(List<Evaluator> evaluators) { this.evaluators = evaluators; } @Override public boolean isApplicable(IPerson ip) { int matches = 0; for (Evaluator e : evaluators) { if (e.isApplicable(ip)) { matches++; } else { break; } } return matches == evaluators.size(); }



I then added my Evaluator into ehcache.xml and hibernate.cfg.xml in order to make the new Evaluator cacheable and persistent.  Seems to work.