I have defined a configuration-action-class for loading the configuration of an existing portlet based on drools (liferay-portlet.xml):
<configuration-action-class>com.liferay.drools.action.ConfigurationActionImpl</configuration-action-class>
This class is processAction class:
public class ConfigurationActionImpl extends DefaultConfigurationAction {
#Override
public void processAction(
Now, I want to add another form with rows (inside the same config.jsp page). Exactly I want to call a different class from all of this rows (A call to SelectRules.java class):
<%
ResultRow row = (ResultRow)request.getAttribute(WebKeys.SEARCH_CONTAINER_RESULT_ROW);
IRRule myRule = (IRRule)row.getObject();
String name = IRRule.class.getName();
String primKey = String.valueOf(myRule.getPrimaryKey());
%>
<liferay-ui:icon-menu>
<portlet:actionURL name="selectRule" var="selectURL">
<portlet:param name="resourcePrimKey" value="<%=primKey %>" />
</portlet:actionURL>
<liferay-ui:icon image="checked" message="SelectRule" url="<%=selectURL.toString() %>" />
</liferay-ui:icon-menu>
In my portlet.xml I defined the following portlet-class:
<portlet-class>com.myown.oriol.selectrules.portlet.SelectRules</portlet-class>
As you see, the main problem is that actionURL is looking to the configuration-action-class but what I exactly want is to call to the portlet-class(SelectRules.java) function called selectRules.
And the defined class selectRules that I want to call starts this way:
public class SelectRuleClass extends MVCPortlet {
public void selectRule(
PortletConfig portletConfig, ActionRequest actionRequest,
ActionResponse actionResponse)
Do you know what I need to solve this?? I don't know how I can merge this two classes with two different extensions considering that configurationActionImpl.java is already defined by another person.
In resume.. I need to call the function selectRule from configuration.jsp while selecting a Rule to be used. But the configuration-action-class is another one required for loading this existing portlet. And while selecting a rule I get this error...
86 does not have any paths specified
Thank you so much,
Oriol
Since the configuration.jsp is rendered by a liferay portlet with name 86 you would need to use <liferay-portlet:actionURL> instead of the simple <portlet:actionURL> since you would need to specify the portlet-name whose action method you need to call from configuration.jsp, something like this:
<liferay-ui:icon-menu>
<liferay-portlet:actionURL name="selectRule" var="selectURL" portletName="SelectRules_WAR_SelectRulesportlet">
<liferay-portlet:param name="resourcePrimKey" value="<%=primKey %>" />
</liferay-portlet:actionURL>
</liferay-ui:icon-menu>
If you have defined <portlet-name>SelectRules</portlet-name> than the attribute portletName of the tag would have value portletName="SelectRules_WAR_SelectRulesportlet", this is the portlet-id which is generated by liferay once you deploy the portlet.
This is liferay's convenient way to call one portlet (SelectRules) from another (86).
Related
I develop a web application in Java EE, in this one there is an inputText allowing to search for a student according to his name.
However, I am faced with a problem that I cannot find the solution to.
I use an inputText with a typeahead (Bootsfaces), if I send it a List Etudiant (My List Object) it works however when I send it a List String no suggestion appears:/
In my controller (Java), I return a List containing the name and surname of each student and I would like to be able to make appear the suggestion of this list.
There is my xHtml code :
<b:inputText style="width:200px" value="" placeholder="Rechercher étudiant" typeahead="true" typeahead-values="#{etudiantController.getEtudiants()}"/>
There is my Controller (etudiantController) code :
public List<String> getEtudiants() {
etudiants = gestionEtudiant.selectAll();
List<String> listeNomPrenom = new ArrayList<String>();
for(Etudiant e : etudiants) {
listeNomPrenom.add(e.getNom() + " " + e.getPrenom());
}
return listeNomPrenom;
}
I hope not to disturb with my post, thanks in advance ;)
So there are several things to address here...
First of all, you need a backing bean value in order for the component to have a proper reference value. Not setting value might work for the auto completion depending on how the component is implemented, but you won't have access to what the user actually entered later in your controller. With some components it might make the component function in an undesirable way. So you need to connect it to a bean property.
Secondly, typeahead-values is expecting either a straight up string, or a bean property. Only in very special circumstances will you ever need to call the getter of a bean property - so you should reference the property.
Thirdly, instead of returning a new list of students, try to take advantage of Java's built in toString() functionality in your typeahead-values. Then you don't have to create a completely new list, but instead can rely on Java doing the conversion for you.
So a complete solution mimicing what you are trying to do and translated to English would look like this;
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:b="http://bootsfaces.net/ui">
<h:head>
<title>Autocomplete test</title>
</h:head>
<h:body>
<h:form>
<b:inputText value="#{studentBean.studentEntry}" placeholder="Search student"
typeahead="true" typeahead-values="#{studentBean.students}"/>
</h:form>
</h:body>
</html>
#Data
#Named
#ViewScoped
public class StudentBean implements Serializable {
private List<Student> students;
private String studentEntry;
#PostConstruct
public void init() {
students = new ArrayList<>();
students.add(new Student("Carl", "Sagan"));
students.add(new Student("Enrico", "Fermi"));
students.add(new Student("Jay", "Miner"));
}
#Data
#AllArgsConstructor
public class Student {
private String firstName;
private String lastName;
#Override
public String toString() {
return String.format("%s %s", lastName, firstName);
}
}
}
Note that this example uses Lombok - so the #Data annotation creates the needed setters and getters for the properties.
Also notice how toString() actually flips the name and puts the surname first
just like you do in your code.
Here it is mentioned that
Though only a single ELResolver is associated with an ELContext, there
are usually multiple resolvers considered for any given variable or
property resolution.
For the sake of making it understandable to the one going to answer, I am demonstrating it taking into consideration a custom ELResolver. This is only for illustration purposes. I haven't felt the need for a home-brewed custom ELResolver ever in the projects in which I have worked so far.
Inside the CustomELResolver, getValue() method looks like,
#Override
public Object getValue(ELContext ctx, Object base, Object property)
throws NullPointerException, PropertyNotFoundException, ELException {
logger.log(Level.INFO, "Get Value property : {0}", property);
if ((base == null) && property.equals(SOME_PROPERTY)) {
logger.log(Level.INFO, "Found request {0}", base);
ctx.setPropertyResolved(true);
return SOME_OBJECT;
}
return null;
}
Each value expression is evaluated behind the scenes by the getValue
method. Adding this in faces-config.xml, the custom
resolver is added in the chain of responsibility.
a simple facelet page:
<h:outputText value="#{bean.name}" />
<br />
<br />
<b>Ordered:</b>
<br />
<h:dataTable id="tableId1"
value="#{PROPERTY DECLARED IN CUSTOM RESOLVER CLASS}" var="t">
<h:column>#{t}</h:column>
</h:dataTable>
with
#ManagedBean(name = "bean")
#RequestScoped
public class Bean {
private String name = "Rafael";
// getters & setters
}
When I debug, for this expression value="#{PROPERTY DECLARED IN CUSTOM RESOLVER CLASS}" from the above page, the call delegated to the getValue() in CompositeELResolver, where the CustomELResolver highlighted in red is considered.
Whereas, for this expression
value="#{bean.name}"
a normal ManagedBeanELResolver is considered. Absolutely, no issues with that.
But for the same request, the ELContext was clearly associated with 2 ELResolvers.
Please elucidate as to what the documentation meant in the first paragraph as mentioned above
...a single ELResolver is associated with an ELContext...
You forgot to read the next sentence in the link you refer to.
ELResolvers are combined together using CompositeELResolvers, to
define rich semantics for evaluating an expression.
If you look in the call hierarchy, you'll see 1 (one, a single) FacesCompositeELResolver... So there is one CompositeResolver directly associated with the ELContext.
But you could also read it that effectively only one EL resolver is actually doing the work each time, the one in the 'chain' that says "I've resolved it, here is the result"
I am trying to add a multiple file upload using h:inputFile. I had a quick look through the source code and it appears that it does not have the option to render multiple="multiple". Is there a way around this without writing a custom component?
If not, is there a suggested custom JSF2.2 component available that can handle multiple Ajax file uploads?
Update:
I have passed the multiple="multiple" using passthrough tag, but when I debugged the FileRenderer the relevant piece of code overwrites the first file with the second:
for (Part cur : parts) {
if (clientId.equals(cur.getName())) {
component.setTransient(true);
setSubmittedValue(component, cur);
}
}
As you can see, since there are two Parts with the same clientId, it always use the last instead of passing a list.
Please recommend an alternative if there is one.
This is not natively supported by <h:inputFile> until Faces version 4.0. It's introduced in Faces 4.0 as per spec issue 1555 (by yours truly):
<html ... xmlns:h="jakarta.faces.html">
...
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.files}" multiple="true" />
<h:commandButton value="submit" action="#{bean.submit}" />
</h:form>
private List<Part> files;
public void submit() {
for (Part file : files) {
String name = Paths.get(part.getSubmittedFileName()).getFileName().toString();
long size = part.getSize();
// ...
}
}
In case you're not on Faces 4.0 yet, then there are 2 alternative options:
Set the multiple attribute as a passthrough attributes (browser support is currently quite broad).
<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:inputFile ... a:multiple="true" />
However, the <h:inputFile> component itself doesn't support grabbing multiple Parts from the request and setting it as an array or Collection bean property. It would only set the last part matching the input field name. Basically, to support multiple parts, a custom renderer needs to be created (and you should immediately take the opportunity to just support multiple attribute right away without resorting to passthrough attributes).
For the sake of having a "workaround" without creating a whole renderer, you could however manually grab all the parts via HttpServletRequest with help of below little utility method:
public static Collection<Part> getAllParts(Part part) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
return request.getParts().stream().filter(p -> part.getName().equals(p.getName())).collect(Collectors.toList());
}
So, the below construct should work with above utility method:
<h:inputFile value="#{bean.part}" a:multiple="true" />
<h:commandButton ... action="#{bean.submit}" />
private Part file;
public void submit() throws ServletException, IOException {
for (Part part : getAllParts(file)) {
String fileName = part.getSubmittedFileName();
InputStream fileContent = part.getInputStream();
// ...
// Do your thing with it.
// E.g. https://stackoverflow.com/q/14211843/157882
}
}
public Part getFile() {
return null; // Important!
}
public void setFile(Part file) {
this.file = file;
}
Do note that the getter can for safety and clarity better always return null. Actually, the entire getter method should have been unnecessary, but it is what it is.
Or, use the JSF utility library OmniFaces. Since OmniFaces version 2.5 the <o:inputFile> is offered which should make multiple and directory selection less tedious.
<o:inputFile value="#{bean.files}" multiple="true" />
<o:inputFile value="#{bean.files}" directory="true" />
The value can be bound to a List<Part>.
private List<Part> files; // +getter+setter
This component was the base for the new Faces 4.0 feature.
See also:
What's new in Faces 4.0?
Since the question was asked a very long time ago, I would like to give an update here. If you are working with the new Jakarta EE Faces 4.0 specification it becomes quite simple to support multiple file upload:
As already mentioned the h:from has to be extended with the enctype "multipart/form-data". And the h:inputFile needs the passthrough attribute multiple=true:
<ui:composition template="/WEB-INF/templates/layout.xhtml"
xmlns:faces="jakarta.faces" xmlns:f="jakarta.faces.core"
xmlns:h="jakarta.faces.html" xmlns:ui="jakarta.faces.facelets"
xmlns:pt="jakarta.faces.passthrough">
<f:view>
<h:form id="models_form_id" enctype="multipart/form-data">
.....
<h:inputFile id="file" value="#{myBean.files}" pt:multiple="true"/>
....
<h:commandButton id="submit" value="Submit" action="#{myBean.submit}" />
</h:form>
</f:view>
</ui:composition>
Your bean code just need to support the 'files' property as a List of jakarta.servlet.http.Part elements:
#Named
#RequestScoped
public class MyBean implements Serializable {
private List<Part> files;
public List<Part> getFiles() {
return files;
}
public void setFiles(List<Part> files) {
this.files = files;
}
public void submit() throws IOException {
if (files != null) {
System.out.println(" uploading " + files.size() + " files");
for (Part file : files) {
System.out.println("name: " + file.getSubmittedFileName());
System.out.println("type: " + file.getContentType());
System.out.println("size: " + file.getSize());
InputStream content = file.getInputStream();
// Write content to disk or DB.
}
}
}
}
....
That's it. Now you can process uploaded files as any other data in your form.
I think it is possible to use multiple file upload using the standard JSF 2.2 using the passthrough tag.
Step 1:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough">
...
<h:form id="form" enctype="multipart/form-data">
<h:inputFile id="file" value="#{fileUploadBean.uploadedFile}" pt:multiple="multiple" />
...
Step 2:
The JSF renderer class FileRenderer for the javax.faces.File type of the javax.faces.Input family of components doesn't handle this case correctly.
Instead, as it iterates through the parts of the form, it just overwrites the preceding part with each file in the uploaded collection.
I think a better strategy is to always have the value of the component be a List<Part> instead of just Part as suggested here and implemented here.
Step 3:
The last thing to make it work is to configure such modified multiple file renderer class in faces-config.xml adding the following to the <faces-config> root element:
<render-kit>
<renderer>
<description>Multiple File Renderer</description>
<component-family>javax.faces.Input</component-family>
<renderer-type>javax.faces.File</renderer-type>
<renderer-class>com.example.MultipleFileRenderer</renderer-class>
</renderer>
</render-kit>
Even it's quite some time ago: Considering your own comment I would recommend a component like PrimeFaces fileUploadMultiple, mentioning not to forget the needed changes in web.xml and all needed libs for uploading. See it as a workaround or complete solution, based on your needs. PrimeFaces is a quite nice component-lib
I have this very strange error with h:graphicImage
This code works fine :-
<h:graphicImage value="/Common/Images/#{item.templatePicName}"/>
And this one doesn't :-
<h:graphicImage alt="${app:getCommonImagePath(item.templatePicName)}" value="${app:getCommonImagePath(item.templatePicName)}" />
It only shows alt value /Common/Images/Sunset.jpg which is perfectly fine and works in 1st case. Then why doesn't it work in 2nd case? There are no problems with my images. They are present in right directory.
here getCommonImagePath is my custom EL function, whose definition is :
package Common;
public final class AppDeployment {
private AppDeployment(){ //hide constructor
}
private static String commonImageFolderPath = "/Common/Images/";
public static String getCommonImagePath(String picName){
return commonImageFolderPath + picName;
}
}
With JSF you should use #{..} rather than ${..}.
Then check the HTML that is generated to see what the src of the generated image is pointing to.
Then check whether your custom tag is mapped properly.
Its easier to solve if you have a property in your app class that concatenates what you want.
ie:
class App {
private String commonImagePath="/Common/Images/";
//getters and setters
}
Then you would write:
<h:graphicImage alt="#{app.commonImagePath}#{item.templatePicName}" value="#{app.commonImagePath}#{item.templatePicName}" />
From the jsf 1.2 revB mrel2 spec: bottom of page 65
■ It must be possible for the application to programmatically modify the component tree at any time during the request processing lifecycle (except during the rendering of the view) and have the system behave as expected. For example, the following must be permitted. Modification of the view during rendering may lead to undefined results. It must be possible to allow components added by the templating system (such as JSP) to be removed from the tree before rendering. It must be possible to programmatically add components to the tree and have them render in the proper place in the hierarchy. It must be possible to re-order components in the tree before rendering. These manipulations do require that any components added to the tree have ids that are unique within the scope of the closest parent NamingContainer component. The value of the rendersChildren property is handled as expected, and may be either true or false.
So how does one do this in adf 11g? I'm trying to implement an application wide authorization system where components are visible/editable based on a user's roles. However, I cannot find a way to hook into adf to modify components (eg RichInputText.setDisabled(true)) before the response is written out. I've tried with both PhaseListeners and ViewHandlers. Neither of these seem to allow me to perform the above mentioned functionality. So what gives? Am I out of luck? Am I missing something?
Thanks,
Ben
public class AuthorizationPhaseListener implements PhaseListener {
...
public PhaseId getPhaseId() {
return PhaseId.RENDER_RESPONSE; // I've also tried in the other phases including ALL_PHASES
}
public void beforePhase(PhaseEvent p1) {
// relevant ui components don't yet exist
...
}
public void afterPhase(PhaseEvent p1) {
// relevant ui components exist, but have already been written to the stream, thus it's too late to modify them
...
}
...
}
public class MyCustomViewHandler extends ViewHandlerWrapper {
...
#Override
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException {
AuthorizationService as = (AuthorizationService)RiscsContext.getCurrentInstance().getBean("AuthorizationService");
// relevant ui components don't yet exist
as.applyAuthorization();
super.renderView(context, viewToRender);
// relevant ui components exist, but have already been written to the stream, thus it's too late to modify them
as.applyAuthorization();
}
...
}
You really need to do this at the presentation side. Do not do it using a phaselistener, there it is not for. Make use of the rendered attribute wisely. Here are some basic examples how you can make use of it:
<h:someComponent rendered="#{bean.booleanValue}" />
<h:someComponent rendered="#{bean.intValue > 10}" />
<h:someComponent rendered="#{bean.objectValue == null}" />
<h:someComponent rendered="#{bean.stringValue != 'someValue'}" />
<h:someComponent rendered="#{!empty bean.collectionValue}" />
<h:someComponent rendered="#{!bean.booleanValue && bean.intValue != 0}" />
<h:someComponent rendered="#{bean.stringValue == 'oneValue' || bean.stringValue == 'anotherValue'}" />
According to my (limited) searching through the docs, the UIViewRoot object is the root node of the view tree. You can use it's getChildren methods to find the appropriate UIComponents and make your modifications. However, I would suggest a different way.
If you expose your Authorization service as a bean, you can directly add the methods to the markup. For example...
public class User {
...
Map<String, Boolean> allowedRoles;
...
public Map<String, Boolean> getAllowedRoles { return allowedRoles; }
}
<h:inputText value="#{SomethingImportant}" disabled="!#{User.allowedRoles['importantRole']}/>
Even better would be using a security framework which would simplify this even more.
It does allow to access/modify the UI Components in tree if it is locatable. You need to provide Client Component Id while using findComponent(). The only problem remains that it does not give you access/constrol for Initial Page load( restore_view ). :-(
For that as of now only 1 way i could find that is specifying EL in jspx/jsp/jsff.