The view/save lifecycle describes the process behind the scenes when an administrator applies a rule to a user segment using the User Segment Editor. You’ll implement that now.
When the user opens the User Segment Editor, the render phase begins for the
rule creation. During the render phase, the HTML for the form is generated
and, if necessary, the context
map is generated with any parameters that you
need to create the form. Once the HTML is successfully retrieved and the user
has set the values and clicked Save, the action phase begins.
When the action phase begins, the processRule(...)
method takes the values
provided by the form and persists them. Once the rule processing ends, the form
is reloaded and the lifecycle restarts again. The value(s) selected in the rule
are stored and are ready to be accessed once user segment evaluation begins.
In this section, you’ll begin defining the weather rule’s Java class. This
assumes that you followed the instructions in the previous
tutorial,
creating the WeatherRule
class and extending
com.liferay.content.targeting.api.model.BaseJSPRule
.
If you used the content-targeting-rule
Blade CLI template, your project
already extends BaseJSPRule
and has a default view.jsp
file already
created.
-
If you didn’t use the template, add the activation and deactivation methods to your class.
@Activate @Override public void activate() { super.activate(); } @Deactivate @Override public void deActivate() { super.deActivate(); }
These methods call the super class
com.liferay.content.targeting.api.model.BaseRule
to implement necessary logging and processing for when your rule starts and stops. Make sure to include the @Activate and @Deactivate annotations, which are required. -
Define the category for the Rule when displayed in the User Segment Editor. Find the
getRuleCategoryKey()
method and replace it with the code below:@Override public String getRuleCategoryKey() { return SessionAttributesRuleCategory.KEY; }
This code puts the weather rule in the Session Attributes category. To put your rule into the appropriate category, use the
getRuleCategoryKey
method to return the category class’s key. Available category classes includecom.liferay.content.targeting.rule.categories.BehaviourRuleCategory
,com.liferay.content.targeting.rule.categories.SessionAttributesRuleCategory
,com.liferay.content.targeting.rule.categories.SocialRuleCategory
, andcom.liferay.content.targeting.rule.categories.UserAttributesRoleCategory
.Figure 1: This example Weather rule was modified to reside in the Session Attributes category.
-
Find the
populateContext()
method and replace it with the code below:@Override protected void populateContext( RuleInstance ruleInstance, Map<String, Object> context, Map<String, String> values) { String weather = ""; if (!values.isEmpty()) { weather = GetterUtil.getString(values.get("weather")); } else if (ruleInstance != null) { weather = ruleInstance.getTypeSettings(); } context.put("weather", weather); }
To understand what this method accomplishes, you must examine the rule’s configuration lifecycle.
Figure 2: An Audience Targeting rule must be configured by the user and processed before it can become part of a User Segment.
When the user opens the User Segment Editor, the render phase begins for the rule. The
getFormHTML(...)
method retrieves the HTML to display. You don’t have to worry about implementing this method because it’s already implemented in theBaseJSPRule
class you’re extending. ThegetFormHTML
method calls thepopulateContext(...)
method.You’ll notice the
populateContext
method is not available in thecom.liferay.content.targeting.api.model.Rule
interface. This is because it’s not needed in all cases. It’s available by extending theBaseJSPRule
class, and it needs more logic for the weather rule.The
populateContext
method generates a map with all the parameters your JSP view needs to render the rule’s HTML. This map is stored in thecontext
variable. This variable is a map defining the form evaluation context for Audience Targeting rules. Each rule contributes its specific parameters to it. ThepopulateContext
method above populates aweather
context variable with theweather
values from thevalues
map parameter, which is then passed to the JSP.For the weather rule, the
populateContext
method accounts for three use cases:a. The rule was added but has no set values yet. In this case, the default values defined by the developer are injected (e.g.,
weather=""
).b. The rule was added and a value is set, but the request failed to complete (e.g., due to an error). In this case, the
values
parameter of thepopulateContext
method contains the values that were intended to be saved, and they are injected so that they are displayed in the rule’s view together with the error message.c. The rule was added and a value was successfully set. In this case, the
values
parameter is empty, and you must obtain the values that the form should display from storage and inject them in the context so they appear in the rule’s HTML. The weather rule uses thetypeSettings
field of the rule instance, but complex rules could use services to store values.You can think of the
populateContext
method as the intermediary between your JSP and your back-end code. Creating the weather rule’s UI using a JSP is covered in Defining the Rule’s UI. Once the HTML is successfully retrieved and the user has set the weather value and clicked Save, the action phase begins. -
Replace the
processRule()
method with this code:@Override public String processRule( PortletRequest portletRequest, PortletResponse portletResponse, String id, Map<String, String> values) { return values.get("weather"); }
The
processRule(...)
method is invoked when the action phase is initiated. Thevalues
parameter only contains the value(s) the user added in the form. The logic you could add to aprocessRule
method is outlined below.a. Obtain the value(s) from the
values
parameter.b. (Optional) Validate the data consistency and possible errors. If anything is wrong, throw an
com.liferay.content.targeting.exception.InvalidRuleException
and prohibit the values from being stored. In the weather rule scenario, when the rule is reloaded after an exception is thrown in the form, case 3b from the previous step occurs.c. Return the value to be stored in the rule instance’s
typeSettings
field. ThetypeSettings
field is managed by the framework in the Rule Instance table. If your rule has its own storage mechanism, then you should call your services in theprocessRule
method.Once the rule processing ends, the form is reloaded and the lifecycle restarts again. The value(s) selected in the rule are stored and are ready to be accessed once user segment evaluation begins. You must add two more methods to the
WeatherRule
class before defining the rule’s evaluation. -
Define a way to retrieve the rule’s localized summary. In many instances, you can do this by combining keys in the rule’s resource bundle with the information stored for the rule. For the weather rule, you can return the rule’s type settings, which contains the selected weather condition. Replace the generated
getSummary()
method with this one:@Override public String getSummary(RuleInstance ruleInstance, Locale locale) { return ruleInstance.getTypeSettings(); }
-
Set the servlet context for your rule. This method was generated and can be left alone:
@Override @Reference( target = "(osgi.web.symbolicname=weather)", unbind = "-" ) public void setServletContext(ServletContext servletContext) { super.setServletContext(servletContext); }
Setting the servlet context is only required for rules extending the
BaseJSPRule
class. The servlet context must be set for the rule to render its own JSP files. ThesetServletContext
method is invoked automatically when the rule module is installed and resolved in Liferay. Make sure theosgi.web.symbolicname
in thetarget
property of the@Reference
annotation is set to the same value as theBundle-SymbolicName
defined in thebnd.bnd
file of the module.
Next, you’ll learn how to evaluate a rule that is configured and saved to a user segment.