I'm facing a serious problem with ice:inputFile component.
When an error occurred while uploading process (like : invalid file name error, empty file name error, exceeding max size error), i use ice:message tag to show these error messages.
I use ice:panelPopup and display the ice:inputFile component inside it.
The problem is : when i toggle the uploading popup the error message still appears, i need any way to clear these messagses.
Please help me, any help is appreciated......................... :)
I'm not 100% sure, if I understood your question correctly, however I guess that the immediate keyword, applied on the action, which triggers the popup, will help you.
<ice:commandLink
action="#{this.popup}"
immediate="true">
<h:outputText value="foo" />
</ice:commandLink>
In regular JSF Life Cycle, action events are normally fired after the Process Validations phase. Additionally, values will be updated from the UI to the model.
The immediate property, which is available to basically every JSF component which can cause any kind of event, bypasses validation and, depending on the event type, also the Model Update phase.
alt text http://img43.imageshack.us/img43/3900/jsfimmediatecomponents.png
(Geary, Horstmann, 2008. Core JavaServer Faces - Second Edition. Prentice Hall)
You'll find more information on this topic in Suns JSF Tutorial: The immediate Attribute
Here are two things that have worked for me.
Bind your ice:inputFile component to a property on your backing bean and manually call the reset method on the property when you close the popup pane.
<ice:inputFile binding="#{Bean.uploadedFile}"/>
class BackingBean {
private UICommand uploadedFile;
public UICommand getUploadedFile() { return uploadedFile; }
public void setUploadedFile(UICommand uploadedFile) { this.uploadedFile = uploadedFile; }
public void onClose(ActionEvent event) {
((InputFile) uploadedFile).reset();
}
}
-OR-
Add an actionListener to your ice:inputFile component. This will stop the inputFile component from adding its own validation errors to the context. You can implement whatever validation you need in the actionListener method and display the validation errors using an ice:messages tag. I've found that this works better than relying on inputFile's validation because it gives you complete control over the error message text/style and because the error messages clear automatically when the popup pane goes away.
<ice:inputFile actionListener="#{Bean.onFileUpload}"/>
public class BackingBean {
public void onFileUpload(ActionEvent event) {
FileInfo info = ((InputFile) event.getSource()).getFileInfo();
switch (info.getStatus()) {
case FileInfo.SAVED :
// handle uploaded file
case FileInfo.SIZE_LIMIT_EXCEEDED :
// file too big error
...
}
}
}
Related
I have a backend restservice call, returning a value, with which I have to execute a JS function (for simplicity, I took "alert" here, in the frontend. This has to be implemented in JSF, and I'm having a hard time.
And, this is the catch, for performance reasons, I want the backend rest-callto be executed on click.
Here is (amongst many other things), what I have tried:
<p:commandLink action="#{viewingSessionBean.prepareViewingSession(document)}" oncomplete="alert('#{viewingSessionBean.name(document)}')">
<p:graphicImage value="documentViewerPopup.png"/>
</p:commandLink>
Here the bean (shortended to make the point clearer):
#ManagedBean
#ViewScoped
public class ViewingSessionBean implements Serializable {
private String name;
public String prepareViewingSession(Document document) {
name = restClient.call()
hashMap.put(document.getBlobId(), name);
return null; // don't navigate away...
}
public String name(Document document) {
return hashMap.get(document.getBlobId()); // return null if nothing is cached for the document yet there
}
}
I'd like to do something like this (pseudo code... don't have h:commandScript..., too old JSF, no way to upgrade)
<h:commandScript action="alert('#{viewingSessionBean.prepareViewingSession(document)}') />
That's something a bit tricky to accomplish, but stil doable.
One thing you must have in mind first: The JavaScript code you write in a .xhtml is rendered in a 'static' way. But what means 'static'? It means that if you reference a bean variable inside of your JavaScript code, and then update this variable value inside your bean, your printed JavaScript code will not be able to see these changes you just made. In this case you must first update your JavaScript code (using ajax) to get the changes in your variable and only then execute it.
Let's start with your bean:
#ManagedBean
#ViewScoped
public class ViewingSessionBean implements Serializable {
private String variable;
public String getVariable() {
return this.variable;
}
public void updateVariableValue(Document document) {
variable = restClient.call();
}
}
Now, the .xhtml code:
<h:form id="form">
<p:commandLink id="firstLink"
actionListener="#{viewSessionBean.updateVariableValue(document)}"
update=":form:secondLink"
oncomplete="$('#form\\:secondLink').click()"/>
<p:commandLink id="secondLink" onclick="alert('#{viewSessionBean.variable}')" style="display: none;"/>
</h:form>
Note a few things:
First: It was used two commandLinks, and not only one, why? Because at the time of the oncomplete call of the first Link the bean variable is already up-to-date, but your html code is not. So in order to have the updated value of the bean variable we do the following things:
Call the actionListener to update the variable value on the bean;
Make an ajax update on the second Link to get the updated value from the bean;
Call the oncomplete method and call a click to the second Link (now updated with the correct values);
Second: To call the click on the second Link we must escape the two dots on the jQuery call.
Third: The second Link is set with the display: none style to make it invisible in the screen.
Now just some thoughts about it: JSF works pretty well alongside JavaScript, but sometimes we have to make some clumsy tricks like this one to accomplish an "easy" task. I'm not saying that JSF is bad, but I think we could have a more 'out-of-box' approach to these kind of things. Just my opinion though.
i want to update the text field value when i was changed.for this i use action listener because every updation time one trigger was fired in my code so,that's the reason i used action listener instead of data changed listener.for data changed listener on key pressed the listener is called updation done but my requirement is after completion of entering the data on text field only the listener is called.but it is not calling properly.
please find the below code,
agencyWorker.addActionListener(createAgencyActionListener(agencyWorker,eventPostchedules.getSerialId()));
private ActionListener createAgencyActionListener(final TextField searchField, String serialId){
return new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
String agencyText = searchField.getText();
searchField.setPreferredW(110);
roasterDao = RoasterDao.getInstance();
roasterDao.updateEventPostScheduleAgency(agencyText, serialId, "supervisor");
}
};
}
thanks in advance.
I just tested this on my iPad and action listener was invoked as expected. Check that you don't have a different error that is causing this e.g. networking error related to https change in iOS.
FYI on a side note, it's really bad to write this:
searchField.setPreferredW(110);
You are limiting the size of the field based in pixels which is rarely the right thing to do. The method is deprecated for a reason...
How do I handle the exception and access the stack trace when an exception is thrown while processing a JSF ajax request? Right now, I only get the exception class name and message in a JavaScript alert when JSF project stage is set to Development. Even worse, there's no visual feedback whatsoever when JSF project stage is set to Production, and the server log doesn't show any information about the exception.
If that's relevant, I'm using GlassFish in Netbeans.
This problem is known and fleshed out in among others the OmniFaces FullAjaxExceptionHandler showcase.
By default, when an exception occurs during a JSF ajax request, the enduser would not get any form of feedback if the action was successfully performed or not. In Mojarra, only when the project stage is set to Development, the enduser would see a bare JavaScript alert with only the exception type and message.
The technical reason is that asynchronous requests (read: Ajax requests) by default don't return a synchronous response (read: a full page). Instead, they return small instructions and parts how to update the HTML DOM tree of the already-opened page. When an exception occurs, then these instructions are basically fully absent. Instead, some error information is sent back. You can usually handle them in the onerror attribute of the Ajax component and e.g. display an alert or perhaps perform a window.location change. At least, this is what JSF expected from you.
In order to catch and log the exception and optionally change the whole response, you basically need to create a custom ExceptionHandler. Standard JSF unfortunately doesn't provide a default one out the box (at least, not a sensible one). In your custom exception handler you will be able to get hands on the Exception instance causing all the trouble.
Here's a kickoff example:
public class YourExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public YourExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public void handle() throws FacesException {
FacesContext facesContext = FacesContext.getCurrentInstance();
for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents().iterator(); iter.hasNext();) {
Throwable exception = iter.next().getContext().getException(); // There it is!
// Now do your thing with it. This example implementation merely prints the stack trace.
exception.printStackTrace();
// You could redirect to an error page (bad practice).
// Or you could render a full error page (as OmniFaces does).
// Or you could show a FATAL faces message.
// Or you could trigger an oncomplete script.
// etc..
}
getWrapped().handle();
}
#Override
public ExceptionHandler getWrapped() {
return wrapped;
}
}
In order to get it to run, create a custom ExceptionHandlerFactory as follows:
public class YourExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
public YourExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
#Override
public ExceptionHandler getExceptionHandler() {
return new YourExceptionHandler(parent.getExceptionHandler());
}
}
Which needs to be registered in faces-config.xml as follows:
<factory>
<exception-handler-factory>com.example.YourExceptionHandlerFactory</exception-handler-factory>
</factory>
Alternatively, you can go ahead using the OmniFaces one. It will fully transparently make sure that exceptions during asynchronous requests behave the same as exceptions during synchronous requests, using <error-page> configuration in web.xml.
See also:
Why FullAjaxExceptionHandler does not simply perform an ExternalContext#redirect()?
Authorization redirect on session expiration does not work on submitting a JSF form, page stays the same
I have one application running in the following environment.
GlassFish Server 4.0
JSF 2.2.8-02
PrimeFaces 5.1 final
PrimeFaces Extension 2.1.0
OmniFaces 1.8.1
EclipseLink 2.5.2 having JPA 2.1
MySQL 5.6.11
JDK-7u11
There are several public pages which are lazily loaded from the database. A few CSS menus are displayed on the header of the template page like displaying category/subcategory-wise featured, top seller, new arrival etc products.
The CSS menus are populated dynamically from the database based on various categories of products in the database.
These menus are populated on every page load which is completely unnecessary. Some of these menus require complex/expensive JPA criteria queries.
Currently the JSF managed beans that populate these menus are view scoped. They all should be application scoped, be loaded only once on application start up and be updated only when something in the corresponding database tables (category/subcategory/product etc) is updated/changed.
I made some attempts to understand WebSokets (never tried before, completely new to WebSokets) like this and this. They worked fine on GlassFish 4.0 but they don't involve databases. I'm still not able to understand properly how WebSokets work. Especially when database is involved.
In this scenario, how to notify the associated clients and update the above-mentioned CSS menus with the latest values from the database, when something is updated/deleted/added to the corresponding database tables?
A simple example/s would be great.
Preface
In this answer, I'll assume the following:
You're not interested in using <p:push> (I'll leave the exact reason in the middle, you're at least interested in using the new Java EE 7 / JSR356 WebSocket API).
You want an application scoped push (i.e. all users gets the same push message at once; thus you're not interested in a session nor view scoped push).
You want to invoke push directly from (MySQL) DB side (thus you're not interested in invoking push from JPA side using an entity listener). Edit: I'll cover both steps anyway. Step 3a describes DB trigger and step 3b describes JPA trigger. Use them either-or, not both!
1. Create a WebSocket endpoint
First create a #ServerEndpoint class which basically collects all websocket sessions into an application wide set. Note that this can in this particular example only be static as every websocket session basically gets its own #ServerEndpoint instance (they are unlike servlets thus stateless).
#ServerEndpoint("/push")
public class Push {
private static final Set<Session> SESSIONS = ConcurrentHashMap.newKeySet();
#OnOpen
public void onOpen(Session session) {
SESSIONS.add(session);
}
#OnClose
public void onClose(Session session) {
SESSIONS.remove(session);
}
public static void sendAll(String text) {
synchronized (SESSIONS) {
for (Session session : SESSIONS) {
if (session.isOpen()) {
session.getAsyncRemote().sendText(text);
}
}
}
}
}
The example above has an additional method sendAll() which sends the given message to all open websocket sessions (i.e. application scoped push). Note that this message can also quite good be a JSON string.
If you intend to explicitly store them in application scope (or (HTTP) session scope), then you can use the ServletAwareConfig example in this answer for that. You know, ServletContext attributes map to ExternalContext#getApplicationMap() in JSF (and HttpSession attributes map to ExternalContext#getSessionMap()).
2. Open the WebSocket in client side and listen on it
Use this piece of JavaScript to open a websocket and listen on it:
if (window.WebSocket) {
var ws = new WebSocket("ws://example.com/contextname/push");
ws.onmessage = function(event) {
var text = event.data;
console.log(text);
};
}
else {
// Bad luck. Browser doesn't support it. Consider falling back to long polling.
// See http://caniuse.com/websockets for an overview of supported browsers.
// There exist jQuery WebSocket plugins with transparent fallback.
}
As of now it merely logs the pushed text. We'd like to use this text as an instruction to update the menu component. For that, we'd need an additional <p:remoteCommand>.
<h:form>
<p:remoteCommand name="updateMenu" update=":menu" />
</h:form>
Imagine that you're sending a JS function name as text by Push.sendAll("updateMenu"), then you could interpret and trigger it as follows:
ws.onmessage = function(event) {
var functionName = event.data;
if (window[functionName]) {
window[functionName]();
}
};
Again, when using a JSON string as message (which you could parse by $.parseJSON(event.data)), more dynamics is possible.
3a. Either trigger WebSocket push from DB side
Now we need to trigger the command Push.sendAll("updateMenu") from the DB side. One of simplest ways it letting the DB to fire a HTTP request on a web service. A plain vanilla servlet is more than sufficient to act like a web service:
#WebServlet("/push-update-menu")
public class PushUpdateMenu extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Push.sendAll("updateMenu");
}
}
You've of course the opportunity to parameterize the push message based on request parameters or path info, if necessary. Don't forget to perform security checks if the caller is allowed to invoke this servlet, otherwise anyone else in the world other then the DB itself would be able to invoke it. You could check the caller's IP address, for example, which is handy if both DB server and web server run at the same machine.
In order to let the DB fire a HTTP request on that servlet, you need to create a reusable stored procedure which basically invokes the operating system specific command to execute a HTTP GET request, e.g. curl. MySQL doesn't natively support executing an OS specific command, so you'd need to install a user defined function (UDF) for that first. At mysqludf.org you can find a bunch of which SYS is of our interest. It contains the sys_exec() function which we need. Once installed it, create the following stored procedure in MySQL:
DELIMITER //
CREATE PROCEDURE menu_push()
BEGIN
SET #result = sys_exec('curl http://example.com/contextname/push-update-menu');
END //
DELIMITER ;
Now you can create insert/update/delete triggers which will invoke it (assuming table name is named menu):
CREATE TRIGGER after_menu_insert
AFTER INSERT ON menu
FOR EACH ROW CALL menu_push();
CREATE TRIGGER after_menu_update
AFTER UPDATE ON menu
FOR EACH ROW CALL menu_push();
CREATE TRIGGER after_menu_delete
AFTER DELETE ON menu
FOR EACH ROW CALL menu_push();
3b. Or trigger WebSocket push from JPA side
If your requirement/situation allows to listen on JPA entity change events only, and thus external changes to the DB does not need to be covered, then you can instead of DB triggers as described in step 3a also just use a JPA entity change listener. You can register it via #EntityListeners annotation on the #Entity class:
#Entity
#EntityListeners(MenuChangeListener.class)
public class Menu {
// ...
}
If you happen to use a single web profile project wherein everything (EJB/JPA/JSF) is thrown together in the same project, then you can just directly invoke Push.sendAll("updateMenu") in there.
public class MenuChangeListener {
#PostPersist
#PostUpdate
#PostRemove
public void onChange(Menu menu) {
Push.sendAll("updateMenu");
}
}
However, in "enterprise" projects, service layer code (EJB/JPA/etc) is usually separated in EJB project while web layer code (JSF/Servlets/WebSocket/etc) is kept in Web project. The EJB project should have no single dependency on web project. In that case, you'd better fire a CDI Event instead which the Web project could #Observes.
public class MenuChangeListener {
// Outcommented because it's broken in current GF/WF versions.
// #Inject
// private Event<MenuChangeEvent> event;
#Inject
private BeanManager beanManager;
#PostPersist
#PostUpdate
#PostRemove
public void onChange(Menu menu) {
// Outcommented because it's broken in current GF/WF versions.
// event.fire(new MenuChangeEvent(menu));
beanManager.fireEvent(new MenuChangeEvent(menu));
}
}
(note the outcomments; injecting a CDI Event is broken in both GlassFish and WildFly in current versions (4.1 / 8.2); the workaround fires the event via BeanManager instead; if this still doesn't work, the CDI 1.1 alternative is CDI.current().getBeanManager().fireEvent(new MenuChangeEvent(menu)))
public class MenuChangeEvent {
private Menu menu;
public MenuChangeEvent(Menu menu) {
this.menu = menu;
}
public Menu getMenu() {
return menu;
}
}
And then in the web project:
#ApplicationScoped
public class Application {
public void onMenuChange(#Observes MenuChangeEvent event) {
Push.sendAll("updateMenu");
}
}
Update: at 1 april 2016 (half a year after above answer), OmniFaces introduced with version 2.3 the <o:socket> which should make this all less circuitous. The upcoming JSF 2.3 <f:websocket> is largely based on <o:socket>. See also How can server push asynchronous changes to a HTML page created by JSF?
Since you are using Primefaces and Java EE 7 it should be easy to implement:
use Primefaces Push ( example here http://www.primefaces.org/showcase/push/notify.xhtml )
Create a view which listen to a Websocket endpoint
Create a database listener which produces a CDI event on database change
The payload of the event could either be the delta of the latest data or just and update information
Propagate the CDI event via Websocket to all clients
Clients updating the data
Hope this helps
If you need some more details just ask
Regards
PrimeFaces has poll features to update the component automatically. In the following example, <h:outputText> will be auto updated every 3 seconds by <p:poll>.
How to notify the associated clients and update the above-mentioned CSS menus with the latest values from the database?
Create a listener method like process() to select your menu data. <p:poll> will be auto-update your menu component.
<h:form>
<h:outputText id="count"
value="#{AutoCountBean.count}"/> <!-- Replace your menu component-->
<p:poll interval="3" listener="#{AutoCountBean.process}" update="count" />
</h:form>
#ManagedBean
#ViewScoped
public class AutoCountBean implements Serializable {
private int count;
public int getCount() {
return count;
}
public void process() {
number++; //Replace your select data from db.
}
}
I'm using Icefaces 1.8.2 and an ice:inputTextarea control, and I can't figure why the value is not getting set here:
.jsp
<ice:inputTextarea binding="#{easp$RecordSearch.repairRemark}" id="repairRemark"
partialSubmit="true" style="height:40px; width:100%;" />
.java
//bean
private HtmlInputTextarea repairRemark = new HtmlInputTextarea();
public HtmlInputTextarea getRepairRemark() {
return repairRemark;
}
public void setRepairRemark(HtmlInputTextarea hit) {
this.repairRemark = hit;
}
....
public String button3_action() {
...
//code that sets value
String myVal = "new value";
this.repairRemark.setValue(myVal);
...
return null;
}
The code that sets the value is part of a button click event that I know is getting fired because I'm setting several other Icefaces controls, and all the other setters are working except this one. I just noticed that it actually appears to set the text very briefly, but disappears instantly. I checked all the code on that page, and I'm almost certain there is no other setter overwriting it. Does anyone know what is going here?
Update:
It does not seem to be a "phase" related issue, as this event is being processed in the INVOKE_APPLICATION phase. Also to note, I'm experiencing the same issue with the jsf h:inputTextarea
I found the cause and solution. The cause was the ice:commandButtons that were triggering this click event were in a column in a ice:dataTable. The ice:dataTable had an ice:rowSelector that seemed like it was causing an additional server request when a button was clicked. When I removed the ice:rowSelector, the problem went away.
The solution was to add either toggleOnClick="false" or toggleOnInput="false" to the ice:rowSelector. I added both, just in case.
http://res.icesoft.org/docs/v1_8_2/tld/ice/rowSelector.html
Hope this helps anyone else that runs into this issue.