I am developing a custom portlet (EDIT:I'm extending MVCPortlet), and looking at several examples and tutorials, I find that when the doView(RenderRequest, RenderResponse) method is overridden, at the end of it there is always at least this line:
super.doView(renderRequest, renderResponse);
or this:
include(viewJSP, renderRequest, renderResponse);
If I don't put either of these my portlet doesn't render anything, but any of them does the trick.
I would like to know which one I should be using, and why do I need to add them to get my portlet to work.
Thanks!
So you must be extending MVCPortlet class. Both the calls are used to include the JSP after the doView processing is completed. If you look at the source code of this class then you would understand what the flow is, below is my explanation:
super.doView(renderRequest, renderResponse);
This includes the default JSP i.e. view.jsp, that you might (or not) have configured in portlet.xml something like this:
<init-param>
<name>view-template</name>
<value>/html/view.jsp</value>
</init-param>
This super class method does nothing but calls the include(viewJSP, renderRequest, renderResponse); method at the end.
include(viewJSP, renderRequest, renderResponse);
This method includes whatever JSP path you have specified for the parameter viewJSP. So with this call you can specify including different JSP for different condition something like the following:
if (isThisTrue) {
include("/html/myCustomPortlet/view.jsp", renderRequest, renderResponse);
} else if (isThisTrueThen) {
include("/html/myCustomPortlet/first/another_view.jsp", renderRequest, renderResponse);
} else {
super.doView(renderRequest, renderResponse);
}
So depending on your requirement you can use any to the two or the mix of the two as shown above. Hope this helps.
The include lets you specify a different JSP to use instead of the default view. So if you are not using a custom view page either will work.
Related
I want to add an other item in the admin menu in a portlet.
For example, add an item "Organization" between Apparence and Configuration.
Is it possible ??
However, i tested a new configuration page in the Configuration menu.
So i add in portlet.xml :
<init-param>
<name>config-jsp</name>
<value>/html/foo/configuration.jsp</value>
</init-param>
in liferay-portlet.xml :
<configuration-action-class>com.projecto.ec.config.ConfigurationActionFooImpl</configuration-action-class>
and my ConfigurationActionPrenalyticImpl looks like this :
public class ConfigurationActionPrenalyticImpl implements ConfigurationAction {
#Override
public void processAction(PortletConfig portletConfig, ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {
// TODO Auto-generated method stub
}
#Override
public String render(PortletConfig portletConfig, RenderRequest renderRequest, RenderResponse renderResponse) throws Exception {
return "/html/preanalytic/configuration.jsp";
}
}
But i don't know how to init correctly this page with some content like in a doView or doEdit.
I'd say it is possible, but is none of the standard extension paths that you typically would go within Liferay. A standard way would be to either implement the JSR-286 "edit" mode or contribute another configuration page to the Liferay-specific configuration.
I've never seen the extension you're intending to do in the wild, and I'm assuming that it would require some poking in the internals. It's most likely not well documented. Given that 6.x is the last release that does not use OSGi (and everything will change with Liferay 7 / DXP), I'm not sure if I should recommend going this way.
A certain managed bean has an action method that returns "/private/myview.jsf". However, without changing this code, I want to perform some checks and eventually render the view "/private/other/myview.jsf".
So, in summary, I want to translate "/private/myview.jsf" to "/private/other/myview.jsf" somewhere after the method return and before the actual view rendering.
How to achieve that?
Environment:
Eclipse Luna
Java 1.7
JSF 2
Current condition
Web application fully operational but not developed to support accessibility features.
Requirement for the next version
To be an application good enough to be used by blind people who uses screen readers.
Details
After some study, we reached the conclusion that we will have to have an accessible version of each page we have nowadays.
We will design such accessible version of each page, the matter is when to show the not accessible version and when to show the accessible version.
We decided that the application will turn to accessible mode (that will not be the default state) when the user clicks a certain link in the top of the page. In accessible mode, only accessible versions of pages are rendered.
We don't want to review all the application, what we want is to intercept some phase of JSF and replace the outcome that should be rendered. For instance, consider the follow:
A certain page has a link or a button to another one, let's say "mysettings.xhtml";
When in accessible mode, we would like to tell to JSF to not render "mysettings.xhtml", instead "mysettings_ac.xhtml" or "accessible/mysettings.xhtml" should be rendered;
Both pages will interact with the very same managed beans and will provide the very same features, but one will be good to the ones who can see and the other will be designed to be comfortable to screen reader users.
Thanks in advance!
So, in summary, I want to translate "/private/myview.jsf" to "/private/other/myview.jsf" somewhere after the method return and before the actual view rendering.
If you're already on JSF 2.2, you can do this by providing a custom ResourceHandeler wherein you return the desired view resource in createViewResource() based on some condition.
public class YourResourceHandler extends ResourceHandlerWrapper {
private ResourceHandler wrapped;
public YourResourceHandler(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewResource createViewResource(FacesContext context, final String name) {
if (someCondition) {
name = name.replace("/private/", "/private/other/");
}
return super.createViewResource(context, name);
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
}
Which is registered in faces-config.xml as below:
<application>
<resource-handler>com.example.YourResourceHandler</resource-handler>
</application>
Or if you're not on JSF 2.2 yet, then use ResourceResolver instead.
public class YourResourceResolver extends ResourceResolver {
private ResourceResolver parent;
public YourResourceResolver(ResourceResolver parent) {
this.parent = parent;
}
#Override
public URL resolveUrl(String path) {
if (someCondition) {
path = path.replace("/private/", "/private/other/");
}
return parent.resolveUrl(path);
}
}
Which is registered in web.xml as below:
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.example.YourResourceResolver</param-value>
</context-param>
As I can see, there can be two probable solutions to it.
using redirect() method
returnAction(){
ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
context.redirect("/private/other/myview.jsf"); //Relative path might vary based upon your business logic
}
conditional redirect after action return; we can maintain a navigation rule in faces-config.xml something like below:
<navigation-rule>
<navigation-case>
<from-action>#{yourManagedBean.actionMethod}</from-action>
<if>#{yourManagedBean.redirectAccessibleFlag}</if> <!-- We maintain a boolean variable redirectAccessibleFlag in the managed Bean and set its value to true or false conditionally-->
<to-view-id>/private/other/myview.jsf</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
In the second alternative, you can put up the managed bean at ApplicationScope in order to be utilized across multiple JSF pages.
Although these solutions are from the general concepts, they might not necessarily fall in the "somewhere after the method return and before the actual view rendering." But you can check if it solves the purpose.
The JSF component SelectOneRadio layout is very limited so I wrote a custom Renderer for it, and it works great. However, there are times when I want to use the standard SelectOneRadio layout as well. So I decide to make my new component that utilize the custom Renderer I create, but I want this new component to mirror the functionality of SelectOneRadio, and the only different is that it will use my Renderer. Do I need to create both custom tag and custom component to go with my custom renderer in this case? What class should I extends to obtain all functionalities from SelectOneRadio? I would greatly appreciated if you can provided some codes.
EDIT
#BalusC: I like your idea about detecting the value of layout to delegate the correct renderer. So if I have layout="div_layout", then it works great, but if it is pageDirection or lineDirection and nothing show up. What I did is: I create a class that extends MenuRenderer and I override encodeEnd method, so in there I did this
String layout = (String) component.getAttributes().get("layout");
if(layout != null){
if(layout.equals(PAGE_DIRECTION) || layout.equals(LINE_DIRECTION)){
super.encodeEnd(context, component);
return;
} else if (!layout.equals(DIV_LAYOUT)){
//Throw error message
}
}
//Continue with my own renderer code
EDIT2
Above when I said nothing show up, I was wrong. super.encodeEnd(context, component); did render, but instead of render the radio, it render select option tag. So it seems that I delegate to the wrong renderer. I need to use RadioRenderer instead of MenuRenderer.
If it's specific to your own web application, then you could replace just alone the renderer. Easiest is to extend the implementation specific renderer and then depending on the value of one of the standard attributes (layout is the best choice) either delegate to the implementation specific renderer, or do your own custom rendering job.
I case of Mojarra, you'd like to extend com.sun.faces.renderkit.html_basic.RadioRenderer and then register it as follows
<renderkit>
<renderer>
<component-family>javax.faces.SelectOne</component-family>
<renderer-type>javax.faces.Radio</renderer-type>
<renderer-class>com.example.ExtendedRadioRenderer</renderer-class>
</renderer>
</renderkit>
If you wish to be implementation independent, then you'd need to write the entire renderer implementation yourself.
If you wish to have a custom component for it, then you'd need to write it yourself as well.
I'm trying to add a tab in the conf of my custom portlet, beside the natives import/export and permissions.
Like in this image : http://imageshack.us/photo/my-images/716/sampledn.png/
This tab had to allow, to change the value of a parameter in a conf.properties which define some variable.
How can I do that?
Regards.
Yup you can do it by first of all adding this to your portlet.xml as a child of the "portlet" node:
<init-param>
<name>config-jsp</name>
<value>/html/config.jsp</value>
</init-param>
The in your liferay-portlet.xml you need to add this as a child of the "portlet" node:
<configuration-action-class>com.yourportlet.action.ConfigurationActionImpl</configuration-action-class>
Then you need to create this files in the directories you've specified in your XML, and your ConfigurationActionImpl should implement the ConfigurationAction interface so the skeleton would look like this:
public class ConfigurationActionImpl implements ConfigurationAction {
#Override
public String render(PortletConfig config, RenderRequest renderRequest, RenderResponse renderResponse) throws Exception {
return "/html/config.jsp";
}
Let me know if this helps or you have any other questions! :)
Add edit mode to your portlet.xml:
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode> <!-- add this line -->
</supports>
Then you will see preferences option in the menu. Override doEdit method in your portlet class to render content of the edit mode.
EDIT:
More advanced solution:
You can add another tab by changing portal jsp via hook. The jsp you need to change is:
/html/portlet/portlet_configuration/tabs1.jsp
Note that this will change configuration window for ALL portlets.
I use JSF 2.0 and facelets. I want to login check at each page and redirect to loginpage if it fails...
<%
HttpSession sess = request.getSession(true);
if (sess.getAttribute("userName") == null ) {
%>
<jsp:forward page="/login.xhtml"/>
<%
return;
} else {
// some code
%>
<%-- some other code --%>
<%
}
%>
When I write this code, Netbeans IDE won't let me.
How can I use this.
Thanks.
I would suggest using a filter instead of jsp. Then, define it as one of the first filters in web.xml.
public class DirectAccessBlockFilter implements Filter {
private String loginPage = "login.xhtml";
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpSession session = httpRequest.getSession(false);
if(session.getAttribute("userName") == null && !httpRequest.getServletPath().contains(loginPage)) {
RequestDispatcher dispatcher = request.getRequestDispatcher(loginPage);
dispatcher.forward(request, response);
return;
}
chain.doFilter(request, response);
}
}
You cannot do that. It's completely impossible, because facelets are not JSPs. Scriptlets don't exists.
Besides, this kind of thing should be implemented in a servlet filter, not on individual pages. Furthermore, you should not do it yourself but use one of the freely available mature implementations:
Apache Shiro
Spring Security
Don't do it. Facelets is the default view for a reason.
The login check should instead be done in either of the following:
javax.servlet.Filter
javax.faces.event.PhaseListener
Like the others mentioned, you should absolutely not do it this way, even if it was possible.
Facelets is a pure XML document that's parsed by an XML parser for the sole reason of creating the component tree. As such it's only used for component layouting. There is no facility whatsoever to include any kind of scriptlet.
Technically there are a few tricks which more or less would give you the (wrong) idiom you're after. E.g. you could put that code fragment in a backing bean and call it via an EL expression at the start of each page. You could also create a Java based custom component and place that at the start of each page. Finally you could define your own custom EL function containing that code and call that.
But I can't stress enough however that such an approach is plain wrong. Use the filter or phaselistener suggested by mmanco and Bozho. If you can't live with this, then maybe JSF and Facelets is just not the best technology for you and you'll be better off programming in JSP or PHP.