Liferay overriding JSONAction using hook - liferay

Liferay has feature to modify Struts Action using hook which is straight-forward. However I am trying to override getJSON method of RateEntryAction.
The use case is I need total positive score and total negative score instead of average score that Liferay's OOTB rating component provides.
I already have necessary methods readily available in Liferay API to get the total positive and negative scores. I created a custom type just like "stars" and "votes" to write my necessary logic in hook. I was then planning to override struts action represented by /portal/rate_enty to override the method and add negative and positive votes in the json that is already being returned.
But RateEntryAction (which is the original class) is extending JSONAction and overriding getJSON method. Is it possible to override just getJSON method using struts action hook?

I can see this action class in struts-config.xml, so it's a Struts Action.
This is the path you could try to override.
<action path="/portal/rate_entry" type="com.liferay.portal.action.RateEntryAction" />
I would try to override this path, and see if can put your logic there.
RateEntryAction extends from JSONAction , and this one from org.apache.struts.action.Action , which is the same class that PortletAction extends.
Hope this help

As per my research we can only hook com.liferay.portal.struts.PortletAction sub classes, Yeah JSONAction also extend org.apache.struts.action.Action class same as PortletAction, but liferay allow only those classes hookable which comes under PortletAction class not except that.

As RateEntryAction is not a Struts Action, you can't overload it with a Struts Action Hook. I'm not aware of any hookable way to override it, thus my best guess is that you'll have to either go for ext or introduce a whole new JSON API function and hook all places in Liferay that refer to the original implementation to now go to your implementation.
I suspect that in this case an ext plugin will be easier to maintain. Someone correct me if I'm wrong.

Related

How to modify Hybris Backoffice refocus functionality

I'm trying to modify the backoffice refocusing functionality. Not sure exactly where the behavior is taking place but I believe the class is the FocusUtils.java (com.hybris.cockpitng.editor.util) This util class is used in the DefaultEditorAreaValidationHandler.onEvent().
The action takes place in the summary-view of a product in the "Data Quality" section. Here the user can see what fields are missing or are needing to be filled. They can click on the attribute listed and the editor will refocus on the selected field. Currently the refocusing is working with the OOTB implementation BUT it cuts off the label to the fields at times. I would like to slightly modify this util class (override) and use the custom implementation instead.
Field label is cut off
What should be dispalyed instead:
Field label is displayed correctly
The only way to do this from what I can see is by modifying/replacing the widget implementation that is using this logic. Basededitorarea widget (com\hybris\cockpitng\widgets\baseeditorarea) and specifically having to override bean definition of the below bean and additional classes as well.
<alias name="defaultEditorAreaValidationPopupDelegate" alias="editorAreaValidationPopupDelegate" />
This is the only bean I see that is defined in the backoffice-widgets-spring.xml that eventually touches this focus logic. This is like the starting point. Ideally, it would be nice to just make changes to the actual util class or replace it with a custom one rather than having to duplicate many other classes.
Does anyone know if this is the correct approach to doing this? or if anyone has any alternative suggestions that would be great.

When does mojarra adds a naming container to the list of optional parameters?

In the source of the class AjaxBehaviorRenderer (line 260) there is a line that apparently appends the NamingContainer Id to the list of optional parameters of mojarra.ab(...). I've never come across it so I'm curious as to when it is used:
RenderKitUtils.appendProperty(ajaxCommand, "com.sun.faces.namingContainerId", namingContainerId, true);
line 260
While working on spec issue 790 last week, which should solve a.o. Rendering other form by ajax causes its view state to be lost, how do I add this back?, this was explained to me by Neil Griffin, a portlet guy.
It appears that portlets can have multiple JSF views rendering to the same HTML document, each with its own view state. In portlets, there's a special UIViewRoot instance which implements NamingContainer. During regular rendering, all forms, inputs and commands will have IDs and names prefixed with the view's own client ID. This will work fine during synchronous postbacks. The portlet can this way identify the exact view to restore.
However, during asynchronous postbacks, the jsf.js will create a bunch of additional ajax-specific request parameters such as javax.faces.source, javax.faces.partial.event, etc. Those request parameter names are not prefixed with the view's own client ID. Therefore the portlet cannot associate them with a specific view. Hence the impl issue 3031.
There was another problem of view state identifiers in ajax responses not being properly namespaced this way. Therefore the portlet implementation had to customize the partial response writer in the so-called "JSF bridge". This will be taken into account during implementing spec issue 790. Instead of sniffing a "portlet environment" as in current implementation, there will be checks on UIViewRoot instanceof NamingContainer which is more flexible and portlet-independent. The Mojarra-specific com.sun.faces.namingContainerId will also be removed. Instead, this value will be rendered to <partial-response id="..."> so that the jsf.js can just extract from there.
All in all, not really important if you're only targeting servlet based environments.
As per balusC comment :
It's only interesting for portlet based apps (not servlet based apps).
I can't exactly explain why and what it is used for (a portlet/liferay
guy might), but the portlet specific feature is called "namespaced
parameters". See https://web.liferay.com/web/meera.success/blog/-/blogs/liferay-requires-name-spaced-parameters

How to add new ViewState programatically?

I am trying to find out a way to add new ViewState while performing some action in application.
Use case :
I have a spring webflow with 2 static ViewState defined in the flow file. In the the first view there is a UI action that will add one new ViewState. I know, I can add the said ViewState in the flow but this is just a example. I have too many such cases. It was possible in earlier version of Spring webflow. But now ViewState object needs a ViewFactory instance.
How can I add new ViewState in a Flow programatically?
If the dynamic SPEL doesn't suffice then you'll have to resort to framework hacks.
The FlowModelFlowBuilder.class controls how flows are built/initialized. Extend the FlowModelFlowBuilder.class and override/add to existing methods.
http://docs.spring.io/spring-webflow/docs/current-SNAPSHOT/api/org/springframework/webflow/engine/builder/model/FlowModelFlowBuilder.html
You'll probably be interested in the createFlow() method. By either overriding, adding to, or studying its functionality to inject your own "dynamic view-states" for predefined flows.
createFlow()
Factory method that initially creates the flow implementation during flow builder initialization.
Once you've implemented your own FlowBuilder you inject it in your webflow-registery config like this:
<webflow:flow-registery id="flowRegistry" flow-builder-services="someFlowBuilderService">
<webflow:flow-location-pattern value="/**/*-flow.xml"/>
<webflow:flow-builder class="com.my.package.MyCustomFlowModelFlowBuilder"/>
</webflow:flow-registery>
Disclaimer: I have personally never done this but the framework does allow you to inject your own custom FlowBuilder impl.
I think you're thinking about this problem incorrectly. You can pass variables into the 'view' attribute of a view-state tag using Spring Expression Language (SPEL) like so
<action-state id="determineWhichViewStateToRender">
<set name="flowScope.dynamicViewState" value="myService.determineWhichViewState()"/>
<set name="flowScope.modelObj" value="myService.getModelTypeForThisViewState(flowScope.dynamicViewState)"/>
<transition to="myDynamicViewState"/>
</action-state>
<view-state id="myDynamicViewState" view="#{flowScope.dynamicViewState}/edit" model="modelObj">
.....
</view-state>
and that would achieve a similar effect to "dynamic view-state" that you desire without resorting to frame work hacks.
Also, in the example modelObj can be set to initialized to any object type prior to entering the view-state.

When to use parameterized method invocations introduced with EL 2.2 (especially in JSF 2.x )?

In the past I used a lot of getter and setter methods to move as much boolean logic as possible from facelet files to JSF backing beans.
This way, the interface of a view was given by the getter and setter methods of its backing bean as well as by the action methods of the backing bean.
An advantage of this approach is that the facelet files are rather logic-free and ,therefore, all logic is within the backing beans and can be unit tested.
But with EL 2.2 another programming style became possible. In EL 2.2 you can invoke methods with expressions like
#{bean.collection.size()},
#{bean.collection.add(elem)},
#{bean.property.substring(0, bean.property.indexOf(something))}.
Is the usage of rather complex expressions like parameterized method invocations good style now or do you rather advise against using such expressions?
Is there a rule of thumb when to use the new method invocation expressions and when not?
The major guideline is the following: reduce as much 'model' logic from the view as possible and leave only the 'view' logic. EL 2.2 made possible some model simplification and reduced the need for creation of artificial properies of JSF beans. Invocation of methods with parameters also enables to pass the necessary information from the view to the controller which would be tedious without that opportunity.
You can call arbitrary methods to access the model from the view that the view part relies on, but you should never call methods that modifies the model from the view.
Let me elaborate on that.
Some legal examples:
evaluate non-accessor methods when building view:
render UI components based on some conditions like rendered="#{request.isUserInRole('administrator')}";
make collection modifications where necessary like <ui:repeat value="#{bean.set.toArray()}" ... >
conditionally evaluate UI component / HTML element attributes like class="#{bean.name.contains('special') ? 'special' : ''}";
output non-accessor data like there are #{bean.list.size()} elements.
pass information to the controller in action methods or listeners:
execute action methods with currently iterated variables like var="data" and action="#{bean.action(data)}" with public String action(Data data);
pass additional data, like current iteration index, in listeners like varStatus="status" and actionListener="#{bean.action(status.index)}" with public String action(int index).
Some to-be-avoided examples:
use EL operators when possible:
use #{not empty bean.list} instead of #{bean.list.size() gt 0}.
use method call with parameters instead of extending the model:
use #{bean.name.contains('special')} instead of #{bean.special} with public boolean isSpecial() {return name.contains("special");}.
prefer leaving view logic in view for plain rendering of the right things and create model logic in case it applies purely to the model:
in case you need to perform some calculations to change the appearance of an object, do that in view directly without changing the model, in case some property is inherent to the model itself, introduce it directly in the model and refer to it from the view.
Some illegal examples:
modify the model from the view:
do not use EL 2.2 possibility of calling methods with parameters to break the MVC paradigm, i.e. do not call #{bean.list.add(element)} from the view side.
Of course, all things said apply to the cases that your goals don't contain targeting at the older servers without EL 2.2 support.
As a bigger picture, I'd recommend to also see BalusC's explanation of what MVC architecture represents within the context of JSF.
Personally, i prefer using "complex" EL expressions when really needed, and take any bit logic/traitement to the correspondant managed-beans.
For example: the first example you put is the only one that i may sometimes use directly, the two others however should be for me put in action methods with void/String returning type according to the need.
Use El 2.2 to reduce our JSF code, e.g. setPropertyActionListener is made redundant, see
JSF Core Tag :setPropertyActionListener vs attribute vs param

Purpose and use of properties 'action', 'actionListener', 'actionListeners'

In a button I can see three properties action, actionListener & actionListeners. I tried to use the actionListener property by creating a class implementing java.awt.event.ActionListener and implementing actionPerformed method and then calling the class using expression language. But nothing happened.
Even the documentation on these properties is cryptic. Can anyone explain how these properties are used and their purpose?
I think you need to use "javax.faces.event.actionlistener" and it uses processAction method. I assume you know though that xpages uses xp:eventHandler's instead of the vanilla JSF 1.1 attributes you mentioned.

Resources